systemd 系统和服务管理器
systemd是现代Linux发行版中最主流的初始化系统(init system)和服务管理器,它现在已经取代了传统的SysV init系统,负责在系统启动时初始化用户空间的各个组件,并在系统运行过程中管理服务和进程。systemd主要由两位德国程序员Lennart Poettering和Kay Sievers开发,首次发布于2010年,如今已被Fedora、Ubuntu、Debian、CentOS等主流发行版采用。
核心概念
单元(Unit)
systemd管理的基本对象是"单元"(Unit),每种单元由一类配置文件描述,配置文件以单元的类型作为后缀名,部分常见的单元类型如下表。
| 单元类型 | 文件后缀 | 说明 |
|---|---|---|
| Service | .service |
服务单元,用于管理守护进程 |
| Target | .target |
目标单元,用于组织和同步多个单元 |
| Socket | .socket |
套接字单元,用于实现基于套接字的激活 |
| Mount | .mount |
挂载单元,用于管理文件系统挂载点 |
| Timer | .timer |
定时器单元,用于实现定时任务,可作为Crontab的替代方案 |
| Device | .device |
设备单元,用于管理内核识别的设备,底层大量使用,但普通用户很少直接编写这类Unit |
我们日常使用中,接触最多的是Service和Target,不过其它类型的Unit其实在系统中也是广泛存在的,我们可以使用以下命令列出指定类型的Unit。
systemctl list-units --type=<Unit类型>
单元文件位置
systemd的单元文件可能存放在多个目录中,按优先级从高到低排列如下。
/etc/systemd/system/ # 系统管理员配置的单元文件,手动创建的单元文件也一般放在这里
/run/systemd/system/ # 运行时生成的单元文件
/usr/lib/systemd/system/ # 软件包安装的单元文件
systemd常用命令
systemd通过systemctl命令进行管理,它是我们日常操作中使用最频繁的命令行工具。
管理服务
service服务单元是最常用的单元类型,下面是一些服务管理的常用命令。
# 启动服务
systemctl start nginx.service
# 停止服务
systemctl stop nginx.service
# 重启服务
systemctl restart nginx.service
# 重新加载服务配置(不中断服务)
systemctl reload nginx.service
# 查看服务状态
systemctl status nginx.service
# 设置服务开机自启
systemctl enable nginx.service
# 取消服务开机自启
systemctl disable nginx.service
命令中.service后缀可以省略,例如systemctl start nginx与systemctl start nginx.service是等价的。
查看系统状态与日志
# 查看所有已加载的单元
systemctl list-units
# 查看所有已加载的服务单元
systemctl list-units --type=service
# 查看所有单元文件(包括未加载的)
systemctl list-unit-files
# 查看当前处于失败状态的单元
systemctl --failed
# 查看单元的依赖关系
systemctl list-dependencies nginx.service
# 查看单元文件内容
systemctl cat nginx.service
# 查看单元的详细属性
systemctl show nginx.service
systemd通过journalctl命令管理日志,它整合了系统中所有服务的日志输出。
# 查看所有日志
journalctl
# 查看指定服务的日志
journalctl -u nginx.service
# 实时追踪日志输出
journalctl -f
# 实时追踪指定服务的日志
journalctl -u nginx.service -f
# 查看本次启动以来的日志
journalctl -b
# 查看指定时间范围的日志
journalctl --since "2024-01-01 00:00:00" --until "2024-01-02 00:00:00"
# 查看最近N行日志
journalctl -n 100
# 查看内核日志
journalctl -k
系统关机与重启
systemd可以管理系统电源状态,传统命令(例如reboot、shutdown等)在大多数现代Linux发行版中其实就是systemd对应命令的别名。
# 重启系统
systemctl reboot
# 关闭系统
systemctl poweroff
# 挂起系统
systemctl suspend
# 休眠系统
systemctl hibernate
Target(目标)简介
Target是systemd中用于组织和同步多个单元的机制,类似于传统SysVinit中的运行级别(runlevel)概念。一个Target可以依赖多个其他单元,当系统切换到某个Target时,systemd会确保该Target所依赖的所有单元都已启动,常见的Target如下表。
| Target | 说明 |
|---|---|
poweroff.target |
关机 |
rescue.target |
救援模式(单用户模式) |
multi-user.target |
多用户命令行模式 |
graphical.target |
图形界面模式 |
reboot.target |
重启 |
下面是一些Target相关的常用命令。
# 查看当前默认Target
systemctl get-default
# 设置默认Target
systemctl set-default multi-user.target
# 切换到指定Target
systemctl isolate graphical.target
创建一个简单的自定义服务
下面我们创建一个简单的自定义服务来演示服务单元文件的编写方法。假设我们有一个需要后台运行的应用程序/opt/myapp/myapp,我们希望将其配置为系统服务。首先,创建服务单元文件/etc/systemd/system/myapp.service。
[Unit]
Description=My Custom Application
After=network.target
[Service]
Type=simple
ExecStart=/opt/myapp/myapp
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -TERM $MAINPID
Restart=on-failure
RestartSec=5
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
[Install]
WantedBy=multi-user.target
服务单元文件主要由三个部分组成:
[Unit]部分:描述单元的元数据和依赖关系
Description:服务描述信息After:指定服务启动顺序,表示在指定单元启动之后再启动本服务,After可以有多个(单行空格分隔或多行写多个After),表示有多个依赖项
[Service]部分:定义服务的具体行为
Type:服务类型,simple表示主进程由ExecStart启动且保持在前台运行ExecStart:启动服务时执行的命令ExecReload:重新加载配置(不中断)时执行的命令,常见做法是写作/bin/kill -HUP $MAINPID,但这需要程序支持SIGHUP信号重载配置,如果程序完全不支持重载配置可以留空(systemctl reload会失败)ExecStop:停止服务时执行的命令Restart:定义服务重启策略,on-failure表示非正常退出时重启RestartSec:重启前等待的秒数User/Group:指定运行服务的用户和组WorkingDirectory:指定工作目录
[Install]部分:定义服务的安装信息
WantedBy:指定服务被哪个Target依赖,设置开机自启时会在对应Target目录下创建符号链接
创建完服务单元文件后,执行以下命令使配置生效并启动服务。
# 重新加载systemd配置
systemctl daemon-reload
# 启动服务
systemctl start myapp.service
# 查看服务状态
systemctl status myapp.service
# 设置开机自启
systemctl enable myapp.service
如果再次修改了服务单元文件,我们需要重新执行systemctl daemon-reload使配置生效。