在 Linux 系统中,系统初始化和服务管理是确保系统正常运行的核心组件。传统上,Linux 使用 sysvinit 或 Upstart 作为初始化系统,但随着系统复杂性的增加,这些系统逐渐显得力不从心。systemd 作为一种全新的系统和服务管理器,凭借其高效、灵活的特点,已成为现代 Linux 发行版(如 Red Hat Enterprise Linux、Ubuntu、Arch Linux)的默认选择。

什么是systemd

systemd 是一个由 Lennart Poettering 和 Kay Sievers 开发的系统和服务管理器,运行在 Linux 系统的 PID 1(第一个进程)。它负责启动系统服务、管理挂载点、设备、网络配置等资源,并提供统一的接口以简化系统管理。systemd 的设计目标是提高系统启动速度、优化资源利用率,并提供强大的依赖管理功能。

主要特性

systemd 的核心优势在于其现代化设计,以下是其主要特性:

  • 并行启动:支持同时启动多个服务,显著缩短系统启动时间。

  • 按需启动:通过 socket 或 D-Bus 激活服务,仅在需要时启动,节省资源。

  • 依赖管理:通过依赖关系(如 Requires 和 After)确保服务按正确顺序启动。

  • 进程跟踪:利用 Linux 控制组(cgroups)监控和管理进程,防止资源泄漏。

  • 兼容性:支持传统的 SysV 和 LSB 初始化脚本,作为 sysvinit 的替代品。

  • 附加组件:包括日志管理(journald)、网络配置(networkd)、时间同步(timedated)等。

尽管 systemd 功能强大,但其复杂性和“功能膨胀”也引发争议。部分用户认为其设计违背了 Unix 哲学的“单一职责”原则,且对 Red Hat 的依赖可能影响开源社区的多样性。然而,systemd 的广泛采用表明其在现代 Linux 系统中的重要地位。

单元文件(Unit Files)

systemd 的核心概念是“单位”(unit),即通过配置文件定义的系统资源。单位文件通常存储在以下目录(从最低优先级到最高优先级列出,要查看完整列表,运行 systemctl show --property=UnitPath ):

目录

描述

/usr/lib/systemd/system/

软件包提供的单位文件

/run/systemd/system/

运行时生成的单位文件,优先级较高

/etc/systemd/system/

管理员自定义的单位文件,优先级最高

单元类型

systemd 支持多种单位类型,每种类型对应特定的系统资源:

单位类型

文件扩展名

描述

Service

.service

系统服务,如 Apache 或 SSH

Target

.target

一组单位的集合,表示系统状态

Mount

.mount

文件系统挂载点

Socket

.socket

进程间通信的 socket

Timer

.timer

定时任务,类似 cron

Path

.path

监控文件系统路径

Device

.device

内核识别的设备

Swap

.swap

交换分区或文件

Slice

.slice

资源控制组,管理进程资源

Scope

.scope

外部创建的进程

单元文件结构

单位文件的语法受 XDG Desktop Entry Specification 和 Windows .ini 文件启发,包含以下主要部分:

  • [Unit]:定义单位的元数据,如描述(Description)、依赖关系(Requires、Wants、After)。

  • [Service]:定义服务的具体行为,如启动命令(ExecStart)、重启策略(Restart)。

  • [Install]:定义服务如何安装,例如与某个目标关联(WantedBy)。

以下是一个简单的服务单位文件示例:

[Unit]
Description=My Custom Service
After=network.target

[Service]
ExecStart=/usr/bin/myservice --option
Restart=always
RestartSec=30

[Install]
WantedBy=multi-user.target

编写单位文件的注意事项

  • 命名规范:单位名称只能包含字母、数字、下划线和点,特殊字符需使用 systemd-escape 转义。

  • 注释规则:注释以 # 开头,必须独占一行,行尾注释会导致单位文件失效。

  • 依赖管理:使用 RequiresAfter 定义强制依赖,Wants 定义可选依赖。

  • 服务类型:在 [Service] 部分通过 Type 指定服务类型:

服务类型

描述

simple

默认类型,立即启动,适用于不分叉的进程

forking

进程分叉后父进程退出,需配合 PIDFile

oneshot

一次性任务,执行后退出,适合脚本

notify

进程通过 libsystemd-daemon.so 通知就绪

dbus

当指定的 D-Bus 名称出现在系统总线上时就绪

idle

延迟执行直到所有任务分派完成,类似 simple

  • 验证文件:使用 systemd-analyze verify <file> 检查单位文件语法。

使用 systemd 管理服务

systemd 通过 systemctl 命令管理服务,取代了传统的 service 和 chkconfig 命令。以下是常见的服务管理命令:

传统命令

systemctl 命令

描述

service name start

systemctl start name.service

启动服务

service name stop

systemctl stop name.service

停止服务

service name restart

systemctl restart name.service

重启服务

service name reload

systemctl reload name.service

重新加载配置

service name status

systemctl status name.service

查看服务状态

chkconfig name on

systemctl enable name.service

启用服务(开机自启)

chkconfig name off

chkconfig name off

禁用服务

目标(Targets)

systemd 使用“Target”替代传统的运行级别,表示系统状态。例如:

  • multi-user.target:多用户模式,无图形界面。

  • graphical.target:图形界面模式。

通过 systemctl get-default 查看默认目标,使用 systemctl set-default graphical.target 设置默认目标。

日志管理

systemd 的 journald 组件负责收集和管理系统日志。使用以下命令查看日志:

  • journalctl:查看所有日志。

  • journalctl -u name.service:查看特定服务的日志。

  • journalctl -b:查看当前启动的日志。

最佳实践

为确保 systemd 的高效和稳定使用,以下是一些最佳实践:

  • 重新加载配置:修改单位文件后,运行 systemctl daemon-reload 重新加载配置。

  • 谨慎编辑:使用 systemctl edit 创建 drop-in 文件,或 systemctl edit --full 编辑完整单位文件。

  • 验证依赖:确保依赖关系正确,避免循环依赖。

  • 测试单位文件:在生产环境部署前,使用 systemd-analyze verify <unit file> 测试单位文件。

参考

Arch Wiki:systemd

Red Hat Documentation