一文读懂systemd

在这里插入图片描述

背景知识

systemd 的产生源于对传统 Unix 系统初始化进程(如 System V init,简称 SysV init)的一系列局限性的认识。systemd 由 Lennart Poettering 和 Kay Sievers 等 Red Hat 开发人员创建,首次发布于 2010 年。

systemd 是专为 Linux 内核设计的,目前大多数现代的 Linux 发行版都使用 systemd 作为其默认的初始化系统和服务管理器。以下是一些使用 systemd 的 Linux 发行版的例子:

  1. Fedora - Fedora 是最早采用 systemd 的发行版之一。
  2. Red Hat Enterprise Linux (RHEL) - 自 7.x 版本起,RHEL 使用了 systemd。
  3. CentOS - CentOS 是 RHEL 的免费克隆版,因此同样也采用了 systemd。
  4. Debian - 从 Debian 8 “Jessie” 开始,默认使用 systemd。
  5. Ubuntu - 从 Ubuntu 15.04 “Vivid Vervet” 开始,默认使用 systemd。
  6. openSUSE - openSUSE 也使用 systemd。
  7. Arch Linux - Arch Linux 是一个滚动更新的发行版,很早就采用了 systemd。
  8. Mageia - 从 Mageia 2 开始,默认使用 systemd。
  9. CoreOS - CoreOS 是一个为大规模服务器部署设计的轻量级操作系统,使用 systemd 管理服务。
  10. 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 旨在提供一种更有效、更强大的方法来初始化系统和管理服务,具体解决以下几个问题:

  1. 并发启动: SysV init 启动服务时通常是串行的,或者至少对并发能力有限制,这导致系统启动速度慢。systemd 引入了依赖关系解析和并行启动服务的能力,显著提高了启动速度。

  2. 复杂的依赖管理: 传统的启动脚本不易于管理复杂的依赖关系。systemd 使用 unit 文件定义服务及其之间的依赖,使得管理更为清晰和易于维护。

  3. 一致的服务控制: systemd 提供了统一的接口来管理所有类型的服务,使得系统管理变得更加一致。

  4. 日志管理: 传统的日志系统(如 Syslog)与服务管理是分开的。systemd 通过 journald 提供集成的日志管理功能。

  5. 资源控制: systemd 利用 Linux 的 cgroups 功能允许管理员控制服务使用的资源量。

替代了什么

systemd 主要替代了以下系统组件:

  1. System V init: 这是一个传统的 Unix 初始化系统,负责启动和停止系统服务。systemd 提供了更快速、更灵活的替代方案。

  2. inetd/xinetd: 这些是网络服务守护程序,负责监听网络端口并按需启动服务。systemd 通过 socket 激活功能实现了类似的功能。

  3. Upstart: 由 Canonical 开发,也是一个现代的初始化系统,用于 Ubuntu 和一些其他 Linux 发行版。systemd 通过提供更广泛的功能和更大的采用率,逐渐取代了 Upstart。

  4. Syslog: 传统的日志系统被 systemd 的 journald 部分所取代,它提供了更强大的日志收集和查询功能。

systemd 的引入在 Linux 社区中引发了广泛的讨论和争议,一些用户和开发者赞赏它带来的改进和现代化,而另一些则批评它过于复杂,或者违背了 Unix 哲学中的 “做好一件事” 原则。尽管有争议,systemd 仍然成为了大多数现代 Linux 发行版的标准组成部分。

init的缺点

init 进程是传统的 Unix 和类 Unix 系统中的第一个进程(PID 1),它负责系统启动后的进程启动和管理。最常见的 init 实现是 System V Init(SysVinit),它在许多较早的 Linux 发行版中使用。尽管 SysVinit 在历史上非常成功,但它确实存在一些缺点,这些缺点随着现代计算环境的发展而日益突出。以下是 SysVinit 的一些主要缺点:

  1. 串行化处理
    SysVinit 通常以串行方式启动服务,这意味着在一个服务启动完成之前,下一个服务不能启动。这会导致系统启动过程慢,特别是在依赖较多的服务上。

  2. 复杂的依赖管理
    在 SysVinit 中,服务依赖关系通过启动脚本中的注释和命名约定来处理,这不一定能可靠地管理复杂的依赖关系。这可能导致服务启动顺序问题,因为服务可能在其依赖项准备好之前就尝试启动。

  3. 缺乏动态控制
    SysVinit 没有原生支持自动重启失败的服务,或根据系统负载动态启动和停止服务。服务管理通常比较静态。

  4. 缺乏集中化管理
    SysVinit 使用一组分散的脚本来管理服务,没有提供一个集中的工具或配置方式来控制不同的系统资源和服务。

  5. 不足的并行处理
    虽然有些实现提供了一定程度的并行启动服务,但 SysVinit 的设计并没有很好地支持并行操作。这限制了现代多核处理器上的利用率。

  6. 日志处理
    SysVinit 没有集成的日志管理系统,因此管理员必须依赖于额外的工具(如 Syslog)来收集和查看系统日志。

  7. 非原生支持现代功能
    例如,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 的服务。

  1. 创建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 下被启用时应该启动。
  1. 重新加载 systemd 配置
    创建或修改服务文件后,需要让 systemd 重新加载配置,以便识别新的或变更的 unit 文件。
systemctl daemon-reload
  1. 启动服务
    通过 systemctl 启动新创建的服务。
systemctl start example.service
  1. 设置服务开机自启动

如果你想让这个服务在系统启动时自动运行,使用 enable 命令。

systemctl enable example.service
  1. 检查服务状态
    检查服务是否正常运行。
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 服务器的配置选项,如端口号、允许的认证方法等。

请根据您的需要和发行版的具体情况调整上述路径和命令。

进一步阅读和参考资料

  • 11
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

namedlock

您的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值