systemd 服务起不来:Unit 找不到、依赖顺序和 Type 选错的三类坑

举报
yd_291384559 发表于 2026/11/06 06:18:32 2026/11/06
【摘要】 systemctl start 成功不等于服务真的起来了。本文按 Unit 路径与 daemon-reload、After 不等于拉起依赖、Type 选错导致进程退出仍显示 active 三类坑,给出 systemctl cat、systemd-analyze verify、journalctl 与 systemd-run 的排查顺序。

systemctl start 返回成功,服务却没在跑;或者刚启动就退出,systemctl status 里只剩一行 failed。这类问题八成不在应用代码,而在 unit 文件本身。下面按排查顺序讲三类最常见的坑,每类都给可直接执行的命令。

一、Unit 找不到:先确认 systemd 看见的是哪个文件

自己写的 unit 放在 /etc/systemd/system/ 下,改完必须执行 systemctl daemon-reload,否则 systemd 仍在用内存里的旧版本。若报 Unit xxx.service not found,先用 systemctl cat 和 systemctl show -p FragmentPath 确认它实际解析到的路径:

systemctl cat myapp.service
systemctl show -p FragmentPath myapp.service

FragmentPath 为空,说明这个 unit 根本没被加载。常见原因是文件名后缀漏了 .service、放错目录,或者 unit 名里的 @ 被当成模板实例。模板 unit(myapp@.service)只有在 systemctl start myapp@foo 时才会实例化,直接 start myapp@.service 是找不到的。写完先跑一遍静态检查,比启动后再猜快得多:

systemd-analyze verify /etc/systemd/system/myapp.service

二、依赖顺序:After 只排序,不会把依赖拉起来

After= 和 Before= 只决定谁先谁后,不会让 systemd 去启动对方。真正拉起依赖的是 Wants=、Requires= 和 BindsTo=。只写 After=network.target 却漏了 Wants=network-online.target,开机时服务可能比网络先起,表现为手动 start 正常、开机必失败。反过来,Wants 写太多也会拖慢启动。用 critical-chain 看真正的启动链:

systemd-analyze critical-chain myapp.service
systemctl list-dependencies myapp.service

还要区分 network.target 和 network-online.target:前者只表示网络栈初始化完成,不保证拿到地址;需要联网的服务应依赖后者,并确认 NetworkManager-wait-online 已启用。

三、Type 选错:进程退出了,systemd 还以为活着

Type=simple 下,systemd 执行 ExecStart 后立刻认为服务已启动,之后进程退出就进入 failed,并触发 Restart 策略,日志里表现为反复重启。前台常驻程序用 simple 没问题;会自己 daemonize 的老程序必须用 Type=forking 并给出 PIDFile=,否则 systemd 跟踪的是那个已经退出的父进程。使用 sd_notify 的程序要写 Type=notify,一次性任务用 Type=oneshot,需要保持 active 状态则再加 RemainAfterExit=yes。

判断服务到底怎么退的,看这三条:

systemctl status myapp.service --no-pager
journalctl -u myapp.service -b --no-pager -n 100
systemctl show -p ExecMainStatus -p Result myapp.service

ExecMainStatus 是应用自己返回的退出码,Result 是 systemd 的判定结果,两者分开看能快速区分程序自己崩了和 systemd 认为启动超时或失败。

四、别忘了环境:EnvironmentFile、WorkingDirectory 与权限

手动能跑、systemd 跑不了,多数是环境差异。EnvironmentFile 指向的文件不存在会让 unit 直接失败,可以在前面加一个减号忽略;WorkingDirectory 不存在的报错很隐晦;User= 切换后,家目录和相对路径都变了。先用 systemd-run 在同样的 unit 环境下跑一条命令验证:

systemd-run --unit=probe --property=User=app --property=WorkingDirectory=/opt/app /bin/sh -c 'env; pwd; id'

排查顺序小结

systemctl cat 确认 unit 内容,systemd-analyze verify 做静态检查,systemctl status 看 Result 和退出码,journalctl -u 看应用日志,systemd-analyze critical-chain 看依赖链,最后用 systemd-run 复现环境。按这个顺序走,绝大多数起不来的问题都能在十分钟内定位到具体是哪一行配置。

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

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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