systemd 服务单元配置的六个常见坑与排查方法
【摘要】 为什么写这篇
把一个二进制程序做成 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 但开机仍不启动,往下看。
- 缺 [Install] 段或者 WantedBy 写错。没有这一段,enable 只是打了个空链接。
- 被其他单元挡住。
After=只排序不拉依赖,要确保前置服务真的启动,得配Wants=或Requires=。只写After=network.target而目标服务没起来,你的服务一样会失败。 - 依赖网络但要的是可用网络。
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为 enabledsystemctl is-active为 activesystemctl cat输出内容与自己预期一致,来源路径正确journalctl -u近 50 行无 panic、无权限拒绝- 重启一次机器,服务仍为 active
小结
systemd 的坑集中在四点:文件放的位置、工作目录、daemon-reload、enable 的生效条件。把这四件事当成固定动作,配置类故障基本就能一次排清。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)