文章目录
- 背景知识
- 为何而来
- 替代了什么
- init的缺点
- systemd的系统架构图
- systemd (PID 1):
- systemd-journald:
- systemd-logind:
- systemd-udevd:
- systemd-networkd:
- systemd-resolved:
- systemd-timedated:
- systemd包括了哪些
- systemctl
- journalctl
- loginctl
- hostnamectl
- timedatectl
- localectl
- machinectl
- unit service
- 查看现成的 unit 服务
- 创建一个unit service
- ssh的例子
- 配置文件的路径
- 配置文件的内容
- 在 Unit 部分:
- 在 Service 部分:
- 在 Install 部分:
- 启动服务
- 开机自启动
- 进一步阅读和参考资料
背景知识
systemd 的产生源于对传统 Unix 系统初始化进程(如 System V init,简称 SysV init)的一系列局限性的认识。systemd 由 Lennart Poettering 和 Kay Sievers 等 Red Hat 开发人员创建,首次发布于 2010 年。
systemd 是专为 Linux 内核设计的,目前大多数现代的 Linux 发行版都使用 systemd 作为其默认的初始化系统和服务管理器。以下是一些使用 systemd 的 Linux 发行版的例子:
- Fedora - Fedora 是最早采用 systemd 的发行版之一。
- Red Hat Enterprise Linux (RHEL) - 自 7.x 版本起,RHEL 使用了 systemd。
- CentOS - CentOS 是 RHEL 的免费克隆版,因此同样也采用了 systemd。
- Debian - 从 Debian 8 “Jessie” 开始,默认使用 systemd。
- Ubuntu - 从 Ubuntu 15.04 “Vivid Vervet” 开始,默认使用 systemd。
- openSUSE - openSUSE 也使用 systemd。
- Arch Linux - Arch Linux 是一个滚动更新的发行版,很早就采用了 systemd。
- Mageia - 从 Mageia 2 开始,默认使用 systemd。
- CoreOS - CoreOS 是一个为大规模服务器部署设计的轻量级操作系统,使用 systemd 管理服务。
- Manjaro - 基于 Arch Linux,但更加用户友好,也使用 systemd。
不过,也有一些 Linux 发行版选择不使用 systemd,或者提供了替代的初始化系统,例如:
- Devuan - Debian 的一个分支,它是为了反对 Debian 转向 systemd 而创建的,提供了不使用 systemd 的系统。
- Slackware - 一个古老的发行版,继续使用传统的 SysV init 系统。
- Gentoo - 提供了多种初始化系统的选择,包括传统的 OpenRC 和 systemd。
- Void Linux - 使用 runit 作为其初始化系统。
注意,systemd 只能在 Linux 系统上工作,其他类 Unix 系统,如 FreeBSD、OpenBSD 或 macOS 不支持 systemd。
为何而来
systemd 旨在提供一种更有效、更强大的方法来初始化系统和管理服务,具体解决以下几个问题:
-
并发启动: SysV init 启动服务时通常是串行的,或者至少对并发能力有限制,这导致系统启动速度慢。systemd 引入了依赖关系解析和并行启动服务的能力,显著提高了启动速度。
-
复杂的依赖管理: 传统的启动脚本不易于管理复杂的依赖关系。systemd 使用 unit 文件定义服务及其之间的依赖,使得管理更为清晰和易于维护。
-
一致的服务控制: systemd 提供了统一的接口来管理所有类型的服务,使得系统管理变得更加一致。
-
日志管理: 传统的日志系统(如 Syslog)与服务管理是分开的。systemd 通过 journald 提供集成的日志管理功能。
-
资源控制: systemd 利用 Linux 的 cgroups 功能允许管理员控制服务使用的资源量。
替代了什么
systemd 主要替代了以下系统组件:
-
System V init: 这是一个传统的 Unix 初始化系统,负责启动和停止系统服务。systemd 提供了更快速、更灵活的替代方案。
-
inetd/xinetd: 这些是网络服务守护程序,负责监听网络端口并按需启动服务。systemd 通过 socket 激活功能实现了类似的功能。
-
Upstart: 由 Canonical 开发,也是一个现代的初始化系统,用于 Ubuntu 和一些其他 Linux 发行版。systemd 通过提供更广泛的功能和更大的采用率,逐渐取代了 Upstart。
-
Syslog: 传统的日志系统被 systemd 的 journald 部分所取代,它提供了更强大的日志收集和查询功能。
systemd 的引入在 Linux 社区中引发了广泛的讨论和争议,一些用户和开发者赞赏它带来的改进和现代化,而另一些则批评它过于复杂,或者违背了 Unix 哲学中的 “做好一件事” 原则。尽管有争议,systemd 仍然成为了大多数现代 Linux 发行版的标准组成部分。
init的缺点
init 进程是传统的 Unix 和类 Unix 系统中的第一个进程(PID 1),它负责系统启动后的进程启动和管理。最常见的 init 实现是 System V Init(SysVinit),它在许多较早的 Linux 发行版中使用。尽管 SysVinit 在历史上非常成功,但它确实存在一些缺点,这些缺点随着现代计算环境的发展而日益突出。以下是 SysVinit 的一些主要缺点:
-
串行化处理
SysVinit 通常以串行方式启动服务,这意味着在一个服务启动完成之前,下一个服务不能启动。这会导致系统启动过程慢,特别是在依赖较多的服务上。 -
复杂的依赖管理
在 SysVinit 中,服务依赖关系通过启动脚本中的注释和命名约定来处理,这不一定能可靠地管理复杂的依赖关系。这可能导致服务启动顺序问题,因为服务可能在其依赖项准备好之前就尝试启动。 -
缺乏动态控制
SysVinit 没有原生支持自动重启失败的服务,或根据系统负载动态启动和停止服务。服务管理通常比较静态。 -
缺乏集中化管理
SysVinit 使用一组分散的脚本来管理服务,没有提供一个集中的工具或配置方式来控制不同的系统资源和服务。 -
不足的并行处理
虽然有些实现提供了一定程度的并行启动服务,但 SysVinit 的设计并没有很好地支持并行操作。这限制了现代多核处理器上的利用率。 -
日志处理
SysVinit 没有集成的日志管理系统,因此管理员必须依赖于额外的工具(如 Syslog)来收集和查看系统日志。 -
非原生支持现代功能
例如,cgroups 控制组、容器管理、socket 激活等是 SysVinit 原生不支持的功能。
因为这些缺点,许多 Linux 发行版转向了其他初始化系统,如 systemd 和 Upstart,它们提供了更快的启动时间、更好的服务依赖管理、更强大的并行处理能力和更现代的系统管理功能。systemd 特别受到关注,因为它提供了一个一致的接口来管理所有系统服务,并集成了许多额外的功能,它已成为许多主流 Linux 发行版的默认初始化系统。
systemd的系统架构图
(引用自Learning to love systemd)
以 systemd PID 1 进程位于中心,周围是下述组件,显示它们如何协同工作来初始化和管理系统。
systemd (PID 1):
作为系统的第一个用户空间进程启动,是所有其他 systemd 单元的父进程。
负责初始化系统,启动所有其他 systemd 单元(包括服务、定时器、设备等)。
systemd-journald:
负责日志收集和管理。
与 systemd 紧密集成,收集系统和服务的日志消息。
systemd-logind:
负责用户登录会话管理。
管理用户登录、注销、多用户会话等。
systemd-udevd:
负责设备事件的处理。
监听内核发送的设备事件,并处理 udev 规则。
systemd-networkd:
管理网络配置。
用于设置和管理网络接口。
systemd-resolved:
名称解析服务。
提供网络名称解析到应用程序。
systemd-timedated:
时间和日期设置服务。
用于管理系统时钟和同步。
这些核心组件在 systemd 的体系结构中占据中心位置,并通过总线(D-Bus)与其他组件交互,以便提供一个统一的系统管理和服务管理解决方案。除了核心组件,systemd 还管理各种类型的单元,如 service、socket、device、mount、timer、swap、path、target 等。
systemd包括了哪些
systemd 提供了一套命令行工具来控制和管理系统和服务。以下是一些核心的 systemd 命令,以及它们的作用、运行命令和选项:
systemctl
作用:systemctl 是控制 systemd 系统和服务管理器的主要工具。
运行命令和选项:
systemctl start [unit]:启动一个服务。
systemctl stop [unit]:停止一个服务。
systemctl restart [unit]:重启一个服务。
systemctl status [unit]:显示一个服务的状态。
systemctl enable [unit]:使服务在启动时自动运行。
systemctl disable [unit]:禁止服务在启动时自动运行。
systemctl list-units:列出当前启动的单位。
systemctl list-unit-files:列出可用的单位文件。
journalctl
作用:journalctl 用于查询和显示从 systemd 日志开始收集的消息。
运行命令和选项:
journalctl:显示全部日志消息。
journalctl -u [unit]:显示指定服务的日志消息。
journalctl --since “2021-02-01” --until “2021-03-01”:显示指定时间范围的日志。
journalctl -f:实时跟踪新日志消息(类似于 tail -f)。
journalctl --disk-usage:显示当前占用的日志空间。
systemd-analyze
作用:systemd-analyze 用于分析系统引导时间和单元启动时间,并诊断系统性能问题。
运行命令和选项:
systemd-analyze:显示启动耗时总览。
systemd-analyze blame:按时间排序显示各服务的启动耗时。
systemd-analyze critical-chain [unit]:显示启动关键链,即启动过程中每个单元的耗时及其依赖关系。
loginctl
作用:loginctl 用于检查和管理系统上的登录会议。
运行命令和选项:
loginctl list-sessions:列出活动的会话。
loginctl show-session [id]:显示指定会话的属性。
loginctl terminate-session [id]:终止指定的会话。
hostnamectl
作用:hostnamectl 用于查看和更改系统的主机名和相关的设置。
运行命令和选项:
hostnamectl:显示当前的主机名和相关信息。
hostnamectl set-hostname [name]:设置系统的主机名。
timedatectl
作用:timedatectl 用于查看和更改系统的时间和日期设置。
运行命令和选项:
timedatectl:显示当前的时间、日期和时区。
timedatectl set-timezone [timezone]:设置系统的时区。
localectl
作用:localectl 用于查看和设置系统的本地化和字符编码设置。
运行命令和选项:
localectl:显示当前的语言和本地化设置。
localectl set-locale LANG=[locale]:设置系统的语言环境。
machinectl
作用:machinectl 用于管理本地和远程的 Linux 容器和虚拟机。
运行命令和选项:
machinectl list:列出本地运行的容器和虚拟机。
machinectl start [name]:启动一个容器或虚拟机。
machinectl enable [name]:配置容器或虚拟机开机自启。
这些命令构成了 systemd 系统管理的基础,通过它们可以控制几乎系统的所有方面。每个命令都有各自详细的手册页(可以通过 man [command] 来查看),提供了完整的命令选项和使用说明。
unit service
systemd 提供了各种类型的 unit 文件来管理系统资源。这些 unit 不仅包括服务 (service units),还包括挂载点 (mount units),设备 (device units),定时器 (timer units),socket (socket units) 等等。以下是一些常见的 systemd unit 类型以及它们各自提供的服务:
-
.service units - 管理服务或应用程序。例如,sshd.service 管理 SSH 守护进程,httpd.service (或 apache2.service) 管理 Apache HTTP 服务器。
-
.socket units - 管理网络或 IPC socket,当有数据发送到 socket 时,可以用于触发相应的服务启动。例如,dbus.socket 管理 D-Bus 系统消息总线的 socket。
-
.device units - 表示系统中的物理或虚拟设备。每个由 udev 管理的设备都会有相应的 unit 文件。
-
.mount units - 管理文件系统的挂载点。例如,home.mount 可能用于挂载 /home 目录。
-
.automount units - 管理自动挂载点,这是一个特别的挂载点,只有在访问时才会自动挂载。
-
.swap units - 管理交换空间。
-
.target units - 用于逻辑分组其他 units,类似于 SysV init 的运行级别。例如,multi-user.target 为多用户文本模式,而 graphical.target 为图形界面模式。
-
.timer units - 管理定时任务,类似于 cron 作业。例如,fstrim.timer 用于定期执行 fstrim.service,以释放未使用的文件系统空间。
-
.path units - 监听文件系统路径的变化,当指定路径的文件被创建或修改时,可以触发相应的服务或者其他 unit 开始工作。
查看现成的 unit 服务
要查看系统上所有已加载 unit 的列表,可以使用以下命令:
systemctl list-units --type=service
要查看所有已安装的 unit 文件(包括未激活的),可以使用:
systemctl list-unit-files --type=service
查看 unit 服务的依赖树
你可以使用 systemctl 来查看特定服务的依赖关系。例如,查看 sshd.service 依赖的 unit:
systemctl list-dependencies sshd.service
此命令会显示一个树形结构,列出 sshd.service 的所有依赖项。
如果你想看的更详细,包括反向依赖(哪些 unit 依赖于指定的 unit),可以使用 --reverse 标志:
systemctl list-dependencies --reverse sshd.service
要查看整个系统的依赖关系树,可以省略服务名称。请注意,这可能会输出非常长的列表,因为它会显示所有活跃 unit 的依赖关系:
systemctl list-dependencies
以上命令将帮助你理解 systemd 如何组织和启动系统上的不同服务和资源。
创建一个unit service
下面是一个简单的示例服务文件,我们将创建一个名为 example.service 的服务。
- 创建unit文件
首先,创建一个服务文件。这通常位于 /etc/systemd/system/ 目录下,因为这个目录用于存放系统管理员创建的 unit 文件。
/etc/systemd/system/example.service:
[Unit]
Description=Example Service
After=network.target
[Service]
Type=simple
User=nobody
ExecStart=/usr/bin/example-program
Restart=on-failure
[Install]
WantedBy=multi-user.target
解释:
- [Unit] 部分定义了服务的元数据和依赖关系。
Description 提供了服务的描述。
After 指定了服务需要在 network.target 启动之后再启动,即服务依赖于网络。 - [Service] 部分定义了服务如何运行。
Type=simple 指定了服务类型。simple 是最常见的启动类型,表示 ExecStart 指定的程序为主服务进程。
User 指定了服务运行时的用户。
ExecStart 指定了启动服务时执行的命令。
Restart 指定了服务失败时的重启策略。 - [Install] 部分定义了如何安装这个服务(即如何使服务随系统启动而启动)。
WantedBy 指定了服务在哪个 target 下被启用时应该启动。
- 重新加载 systemd 配置
创建或修改服务文件后,需要让 systemd 重新加载配置,以便识别新的或变更的 unit 文件。
systemctl daemon-reload
- 启动服务
通过 systemctl 启动新创建的服务。
systemctl start example.service
- 设置服务开机自启动
如果你想让这个服务在系统启动时自动运行,使用 enable 命令。
systemctl enable example.service
- 检查服务状态
检查服务是否正常运行。
systemctl status example.service
以上是一个简单的 systemd 服务配置示例。实际情况中,服务的 ExecStart 可能会包含具体的程序路径和参数,服务文件可能还会包含更多的指令和配置选项,根据服务的实际需求而定。在创建自己的服务文件之前,最好查看一下 systemd 的官方文档,以了解所有可用的配置选项。
ssh的例子
以 OpenSSH 服务器(通常称为 sshd)为例,以下是在使用 systemd 的 Linux 系统上 sshd 服务的配置文件路径、内容以及启动后的依赖进程等信息。
配置文件的路径
sshd 的 systemd unit 文件通常位于以下位置之一:
/lib/systemd/system/sshd.service
/usr/lib/systemd/system/sshd.service
/etc/systemd/system/sshd.service (通常用于自定义或覆盖默认服务文件)
配置文件的内容
一个示例 sshd 的 systemd 配置文件内容可能如下:
[Unit]
Description=OpenSSH server daemon
After=network.target auditd.service
Requires=sshd-keygen.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Service]
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s
[Install]
WantedBy=multi-user.target
Alias=sshd.service
这个文件定义了以下内容:
在 Unit 部分:
- Description 是该服务的简单描述。
- After 指定了 sshd 服务应该在 network.target 和 auditd.service 启动后启动,这意味着 sshd 依赖于网络和审计守护进程。
- Requires 表示 sshd 服务需要 sshd-keygen.service 完成密钥生成后才能启动。
- ConditionPathExists 确保在指定路径不存在文件时服务不会运行,这可以用来禁用 sshd。
在 Service 部分:
- ExecStart 用于定义启动服务时运行的命令(-D 选项告诉 sshd 在前台运行)。
- ExecReload 指定了重新加载配置文件时执行的命令。
- KillMode 定义了停止服务时如何处理服务的进程。
- Restart 指定了服务失败时的重启策略。
- RestartSec 定义了失败后重启之前等待的秒数。
在 Install 部分:
- WantedBy 指定了在哪个目标下启用服务时它应该被自动启动。
- Alias 提供了服务的别名,以便可以使用不同的名字来引用同一个服务。
启动服务
启动 sshd 服务的命令为:
systemctl start sshd.service
或者,如果文件名是 ssh.service:
systemctl start ssh.service
启动后的依赖进程
sshd 作为守护进程启动后,通常不依赖于其他进程。但是,它可能会依赖于如下几个组件:
- 网络: sshd 需要网络服务正常启动和运行。
- 系统日志: 根据配置,sshd 可能会与系统日志守护进程(如 syslog 或 journald)交互,用于记录登录尝试和系统事件。
- 密钥生成: 如上面的 systemd 配置文件所示,sshd 可能依赖 sshd-keygen.service 来生成主机密钥,如果还没有的话。
一旦 sshd 启动,每个 SSH 连接都将创建一个新的子进程来处理该连接。连接结束时,这些子进程会被终止。
开机自启动
要设置 sshd 服务在系统启动时自动启动,可以使用以下命令:
systemctl enable sshd.service
检查服务状态
检查 sshd 服务是否正在运行:
systemctl status sshd.service
配置文件
请注意,上面介绍的是 systemd 的服务 unit 文件,而不是 sshd 本身的配置文件。sshd 的主配置文件通常位于 /etc/ssh/sshd_config,它包含了 SSH 服务器的配置选项,如端口号、允许的认证方法等。
请根据您的需要和发行版的具体情况调整上述路径和命令。
进一步阅读和参考资料
- Learning to love systemd