systemd 服务单元配置的六个常见坑与排查方法

举报
云上小栈 发表于 2026/10/31 00:57:54 2026/10/31
【摘要】 为什么写这篇 把一个二进制程序做成 systemd 服务,看起来只是写十几行 ini 配置。但实际上手就会发现,服务起不来、开机不自启、日志看不到、重启后工作目录不对,这几个问题反复出现。本文按排查顺序梳理一遍,每个坑都给出可复现的判断方法。 一、单元文件放哪里,先搞清优先级 systemd 会从多个目录加载同名单元,后者覆盖前者: /usr/lib/systemd/system/ ...

为什么写这篇

把一个二进制程序做成 systemd 服务,看起来只是写十几行 ini 配置。但实际上手就会发现,服务起不来、开机不自启、日志看不到、重启后工作目录不对,这几个问题反复出现。本文按排查顺序梳理一遍,每个坑都给出可复现的判断方法。

一、单元文件放哪里,先搞清优先级

systemd 会从多个目录加载同名单元,后者覆盖前者:

/usr/lib/systemd/system/      发行版包管理器安装的
/etc/systemd/system/          管理员自定义,优先级更高
/run/systemd/system/          运行时生成

自己写的服务一律放 /etc/systemd/system/。如果两个目录下有同名文件,/etc 下的优先。排查时可以先用这条命令确认实际生效的是哪一份:

systemctl cat your-service.service

它会把合并后的完整配置连同每段的来源文件路径一起打出来。如果看到的内容和你改的文件对不上,说明你改的不是生效的那份。

二、最小可用单元长什么样

[Unit]
Description=My App
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/server --config /opt/myapp/config.yaml
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

几个容易写错的地方:

  • ExecStart 必须写绝对路径,不能写 ./server,也不能依赖 PATH。
  • WorkingDirectory 不写的话默认是 /。很多程序用相对路径读配置,工作目录一错就读不到,报错还是一句含糊的“配置文件不存在”。
  • Type=simple 适用于前台常驻进程。forking 是给会自己 daemon 化的老程序用的,用错会导致 systemd 立刻判定服务退出。
  • WantedBy=multi-user.target 缺了这一行,systemctl enable 会“执行成功”但开机根本不启动。

三、起不来的固定排查顺序

不要一上来就改配置,按下面顺序看:

systemctl daemon-reload
systemctl start your-service.service
systemctl status your-service.service -l --no-pager
journalctl -u your-service.service -n 50 --no-pager

判读要点:

  • status 里的 exit code:203/EXEC 表示找不到可执行文件或没有执行权限,多半是路径错或 SELinux 拦截;1/FAILURE 才是程序自己退出的。
  • 改了单元文件必须先 daemon-reload。不执行这一步,改什么都不生效,而且 systemd 不报错,非常容易误判。
  • 日志里如果一行都没有,说明进程可能根本没起来,看 status 的 Main PID 是否为 0。

四、开机不自启的三种成因

先确认状态:

systemctl is-enabled your-service.service

返回 disabled,就是没 enable;返回 enabled 但开机仍不启动,往下看。

  1. 缺 [Install] 段或者 WantedBy 写错。没有这一段,enable 只是打了个空链接。
  2. 被其他单元挡住。After= 只排序不拉依赖,要确保前置服务真的启动,得配 Wants= 或 Requires=。只写 After=network.target 而目标服务没起来,你的服务一样会失败。
  3. 依赖网络但要的是可用网络。network.target 只表示网络管理服务已启动,不代表拿到 IP。network-online.target 才是网络可用,配合 Wants=network-online.target 使用。

五、Restart 策略别乱开

Restart=always 看着省事,但它会把配置错误这类永久性故障变成无限重启。默认的启动限制是 10 秒内最多 5 次,超了就进入 failed 状态,日志里会出现 start request repeated too quickly。

实践建议:

  • 常驻服务用 on-failure,配合 RestartSec=5。
  • 确需 always 时,把 StartLimitIntervalSec 和 StartLimitBurst 调宽,避免一次抖动就被锁死。
  • 改完限制要 systemctl reset-failed your-service.service 才能重新计数。

六、验证清单

部署完按这五项过一遍,能挡掉绝大多数线上事故:

  • systemctl is-enabled 为 enabled
  • systemctl is-active 为 active
  • systemctl cat 输出内容与自己预期一致,来源路径正确
  • journalctl -u 近 50 行无 panic、无权限拒绝
  • 重启一次机器,服务仍为 active

小结

systemd 的坑集中在四点:文件放的位置、工作目录、daemon-reload、enable 的生效条件。把这四件事当成固定动作,配置类故障基本就能一次排清。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。