systemd 操作手册

11 分钟
本页目录

先分清正在运行、允许被启动、是否随目标启动这三件事。本文以系统服务 example.service 为例;用户服务在命令中加 --user,不要把两套管理器的状态混在一起。

当前任务入口
服务起不来状态与证据
开机启动或禁止启动运行与启用
改配置、改启动命令配置的生效边界
计划任务与日志定时与验证

先读状态,再找退出原因

检查一个服务

# 读取 unit 来源、运行状态及最近日志
systemctl status example.service --no-pager

--no-pager 直接输出。先看 Loaded 的路径与错误,再看 Active 和主进程;status 在非 active 时可能返回非零,不能直接当成查询失败。

# 提取运行、退出结果与启用状态供对照
systemctl show example.service -p ActiveState -p SubState -p Result -p ExecMainStatus -p UnitFileState

ActiveState=failed 与 Result=exit-code 指向进程退出失败;ExecMainStatus 是主进程状态码。Type 与启动阶段不同可能需要检查 ExecStartPre 等,不能只盯主进程。

# 读取本次启动中该服务最近的日志
journalctl -u example.service -b -n 80 --no-pager

-u 选 unit,-b 限本次系统启动,-n 限行数。问题发生在上次启动则选择 -b -1;持续观察用 -f,不是必须再执行的步骤。

查单个服务与列全机清单分开

# 列出管理器记录为失败的 unit
systemctl --failed

修复原因后才按需 sudo systemctl reset-failed example.service 清除失败状态与启动限速计数;它不会修配置或启动应用。

# 查看已加载的服务,包括非活动项
systemctl list-units --all --type=service

要查安装在磁盘上的 unit 文件及 enable 状态,改查 systemctl list-unit-files --type=service。一个是管理器加载集合,一个是文件清单,范围不同。

看到什么能说明什么下一步
active (running)管理器认为进程正在运行,不证明业务正常检查服务端口和实际请求
active (exited)常见于带 RemainAfterExit 的一次性任务看 Type、ExecStart、退出结果
failed / exit-code有失败结果,不能仅靠 reset-failed 修复看 journal 与 Result,不只看最后一行
not-found此管理器没找到该 unit查名称、安装位置、是否应加 --user

运行状态与启用状态是两个维度

正在呈现知识画面
正在运行与开机启用:两条独立轴

start/stop 改变当前运行状态,enable/disable 改变启动依赖;mask 阻止后续启动但不会自动停止已有进程。

意图systemctl作用
现在启动/停止start / stop改变当前运行状态
随目标启动/取消enable / disable按 [Install] 管理符号链接,不自动 start/stop
同时执行enable --now / disable --now同时改变安装与运行状态
禁止任何正常启动请求mask / unmaskmask 指向 /dev/null;已运行服务仍需 stop 或 --now

只改变当前运行状态

# 请求立即启动这个服务
sudo systemctl start example.service

成功后用 systemctl is-active example.service 确认管理器状态,再做业务请求。需要停止时另用 sudo systemctl stop example.service;stop 不会取消开机启动。

设置随目标启动

# 按 Install 配置建立启动链接,不立即启动
sudo systemctl enable example.service

随后 systemctl is-enabled example.service 应反映 enabled;要同时启动,以 enable --now 代替。取消只用 disable;需同时停止则选 disable --now。这些是不同意图的选项。

阻止启动前先检查谁会拉起它

# 查看已加载依赖关系中的反向引用
systemctl list-dependencies example.service --reverse

去掉 --reverse 看该服务依赖谁;同时查关联 socket / timer。该清单不是所有未加载 unit 的完整静态分析。确需屏蔽时用 sudo systemctl mask example.service,解除用 unmask,然后核对 is-enabled。

disabled 的服务仍可手动或经依赖、socket、timer 启动;static 通常没有可供 enable 的 [Install] 信息。mask 对已有本地 unit 文件可能报冲突,先检查 systemctl cat,不要覆盖文件。

修改的是 unit 文件,还是应用配置?

改动执行验证
手工修改 unit / drop-indaemon-reloadshow 查看解析值;必要时 restart 才使用新进程配置
应用自己的配置reload仅在该服务支持 reload 时可用;连接影响由应用决定
需要重新创建进程restart会停止再启动,安排业务中断窗口

读完整配置再添加覆盖

# 显示原始 unit 与各个 drop-in 的来源
systemctl cat example.service

记录要修改的原值及文件位置,避免直接编辑发行版管理的文件。输出是磁盘文件;是否已加载还要看 show。

# 为该服务创建或编辑本地 drop-in
sudo systemctl edit example.service

在编辑器提示的有效区域写入下面的 [Service] 片段,保存退出。取消时退出而不保存;回退时只移除或恢复本次改动的 drop-in,再 reload / restart 验证,不清空其他人的覆盖配置。

[Service]
Environment=LOG_LEVEL=debug
Restart=on-failure
RestartSec=5s

systemctl edit 成功保存后通常会自动执行等效的 daemon-reload;手工写文件时需自行执行。替换单条 ExecStart 要先用空的 ExecStart= 清除旧值,再写新命令;不要照抄别的服务启动参数。

手工写文件后的校验与加载

# 校验这份本地 unit 的语法和可解析依赖
systemd-analyze verify /etc/systemd/system/example.service

路径替换为实际主 unit 路径;若只通过 edit 修改发行版服务,按 cat 的来源定位,不能假设 /etc 下已有完整主文件。校验失败先修复;通过不代表应用自身配置有效。

# 让管理器重新读取手工修改的 unit 文件
sudo systemctl daemon-reload

它不重新创建服务进程。systemctl edit 正常保存通常已经完成这一步,手工写文件才需要补做。

# 核对管理器解析后的关键配置
systemctl show example.service -p ExecStart -p Environment -p Restart

确认正确后,确需新进程才执行 sudo systemctl restart example.service,再检查 status / journal 和业务请求。仅改应用配置且支持 reload 时,选择 sudo systemctl reload example.service;两条不应机械连续执行。

用户管理器有独立的状态

# 在目标用户的登录会话查询用户服务
systemctl --user status example.service --no-pager

对应文件一般在 ~/.config/systemd/user/。同一用户运行 edit / daemon-reload / enable --now,并用 journalctl --user -u example.service 读日志;不要加 sudo 后误操作 root 的用户管理器。

用户服务用 systemctl --user,日志用 journalctl --user -u example.service。需要未登录时也启动用户管理器,再考虑 loginctl enable-linger USER;这与 enable 某个用户服务是两件事。

定时任务:看触发条件与执行结果

# /etc/systemd/system/example.timer
[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=30s

[Install]
WantedBy=timers.target
# /etc/systemd/system/example.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/example-task

先提供可执行的任务程序,再启用 timer。Persistent=true 对 OnCalendar 生效:timer 停用期间错过了日历触发,可在重新激活时补一次,不逐条重放所有遗漏。OnBootSec、OnUnitActiveSec 属于单调时间计时,不靠 Persistent 补跑。

先校验定时表达式与配套 unit

# 查看 daily 的解释和下一次触发时刻
systemd-analyze calendar daily

核对时区和时间是否符合预期;可换成实际 OnCalendar 表达式。再用 systemd-analyze verify /etc/systemd/system/example.timer /etc/systemd/system/example.service 校验两个文件,确认任务程序存在且可执行。

# 加载刚写入的 timer 与 service
sudo systemctl daemon-reload
# 启用并激活计时器,不手动触发 service
sudo systemctl enable --now example.timer

Persistent 补跑可能在激活后发生,提前确认任务重复执行的行为。

# 核对 timer 的 NEXT、LAST 与触发服务
systemctl list-timers --all

NEXT 是计划,LAST 是触发,不是成功记录。用 journalctl -u example.service --since today --no-pager 和 systemctl show example.service -p Result -p ExecMainStatus 核对任务结果。停用调度选择 sudo systemctl disable --now example.timer,已经运行的任务需另外处理。

启动耗时与日志空间是独立任务

# 查看该服务的时间关键依赖链
systemd-analyze critical-chain example.service

结合 journal 的时间戳判断等待发生在哪里;并行启动和服务类型会影响这些统计。

# 先测量 journal 占用,再决定保留策略
journalctl --disk-usage

确需删除旧日志时,sudo journalctl --rotate 归档当前文件,再单独 sudo journalctl --vacuum-time=7d 清理过期归档;删除前保存排障所需时间段。持久大小策略应配置 journald 的 SystemMaxUse 等,而不是反复手工 vacuum。

timer active 只表示计时器在等候,不表示上次任务成功;看对应 service 的 Result 与日志。journalctl --vacuum-time=7d 只清理归档日志;必要时先 rotate,不能把它当成总目录大小的硬上限。blame 也不能单独证明谁阻塞了启动关键路径。

systemctl · systemd.timer · journalctl