云服务器上 systemd 服务起不来?从 systemctl status、journalctl 到 unit 文件的排查顺序

举报
yd_275727902 发表于 2026/11/11 09:19:25 2026/11/11
【摘要】 刚改完配置执行 systemctl restart xxx,结果报 Job for xxx.service failed because the control process exited with error code;或者服务看着启动了,几秒后又变成 failed。这类问题别急着反复重启,按下面顺序把“哪一步失败、退出码是什么、失败原因在哪个日志里”说清楚。命令在 EulerOS、Ce...

刚改完配置执行 systemctl restart xxx,结果报 Job for xxx.service failed because the control process exited with error code;或者服务看着启动了,几秒后又变成 failed。这类问题别急着反复重启,按下面顺序把“哪一步失败、退出码是什么、失败原因在哪个日志里”说清楚。命令在 EulerOS、CentOS 7+/8、Ubuntu 20.04+ 上通用,下文用 myapp.service 作示例,请换成实际服务名。

一、先看状态和退出码

systemctl status myapp.service --no-pager -l

重点看三处:

  • Active: 行:failed (Result: exit-code) 说明主进程非 0 退出;Result: timeout 说明启动超时;Result: start-limit-hit 说明短时间内重启次数太多被 systemd 拦住了。
  • Main PID: ... (code=exited, status=203/EXEC) 这类状态码,含义见第三节。
  • 底部最后几行日志,往往已经直接给出原因。

如果是 start-limit-hit,修完问题后要先清计数再启动:

systemctl reset-failed myapp.service
systemctl start myapp.service

二、用 journalctl 看完整日志

status 只显示最后十行,完整的要看日志:

journalctl -u myapp.service -b --no-pager -n 100      # 本次开机以来最后 100 行
journalctl -u myapp.service --since "10 min ago"       # 最近 10 分钟
journalctl -u myapp.service -f                        # 另开终端实时跟踪,再去 start

注意:有些程序把日志写到自己的文件(比如 /var/log/myapp/、Nginx 的 error.log),journal 里只有一行退出信息,这时要去程序自己的日志里找。

三、常见退出状态码对照

状态 含义 常见原因
status=203/EXEC 启动命令执行不了 ExecStart 路径写错、文件不存在、没有执行权限、脚本缺 shebang、Windows 换行符
status=200/CHDIR 进不了工作目录 WorkingDirectory 不存在或无权限
status=217/USER 找不到运行用户 User= 写的用户不存在
status=226/NAMESPACE 沙箱目录准备失败 ReadWritePaths 等配置的目录不存在
status=1 或其他小数字 程序自己报错退出 配置文件语法错误、端口被占用、依赖连不上
signal=KILL 被强制杀掉 内存不足被 OOM 杀,或停止超时被 systemd 杀

203 最常见,可以这样逐项确认:

systemctl cat myapp.service | grep ExecStart
ls -l /opt/myapp/bin/start.sh          # 路径是否存在、是否有 x 权限
head -1 /opt/myapp/bin/start.sh        # 是否有 #!/bin/bash 这类 shebang
file /opt/myapp/bin/start.sh           # 出现 CRLF 说明是 Windows 换行,用 dos2unix 转换

四、用服务的身份和环境手动跑一遍

很多“手动能跑、systemd 跑不起来”的问题,是因为两者的用户、环境变量和工作目录不同。systemd 不会读取 ~/.bashrc,PATH 也比交互式 shell 短。

systemctl show myapp.service -p User -p WorkingDirectory -p Environment -p ExecStart
sudo -u myappuser env -i PATH=/usr/bin:/bin bash -c 'cd /opt/myapp && ./bin/start.sh'

用这种“干净环境”手动执行一次,常常就能复现报错,比如找不到 java、node,或读不到某个环境变量。解决方法是在 unit 里写绝对路径,或者用 Environment= / EnvironmentFile= 明确提供变量。

五、检查 unit 文件本身

systemctl cat myapp.service                        # 看实际生效的内容,包括 drop-in 覆盖
systemd-analyze verify /etc/systemd/system/myapp.service

几个高频坑:

  1. 改完没 reload:修改 unit 文件后必须执行 systemctl daemon-reload,否则 systemd 还在用旧配置。
  2. Type 和程序行为不匹配:程序会自己转入后台(fork)却写了 Type=simple,或反过来,前台程序写了 Type=forking,就会出现“启动后立刻退出”或“启动超时”。前台运行的程序用 simple(或 exec),自己 daemonize 的用 forking 并配好 PIDFile=。
  3. 启动太慢超时:Java 等启动慢的程序可适当调大 TimeoutStartSec=,但先确认是真的慢,而不是卡在连数据库这类依赖上。
  4. 依赖顺序:要等网络就绪的服务写 After=network-online.target 和 Wants=network-online.target;依赖数据库的写对应的 After=。
  5. drop-in 覆盖:/etc/systemd/system/myapp.service.d/*.conf 里的配置会覆盖主文件,systemctl cat 能看到全部来源。

六、别忘了 SELinux 和端口占用

EulerOS、CentOS 默认开启 SELinux,程序放在非标准目录(比如 /data/app)时可能被拦,但手动以 root 执行却正常:

getenforce
ausearch -m avc -ts recent | tail -20

确认是 SELinux 拦截后,应调整文件上下文(semanage fcontext + restorecon),而不是直接关闭 SELinux。

端口被占用也是 status=1 的高频原因:

ss -lntp | grep ':8080'

七、修好之后

systemctl daemon-reload
systemctl restart myapp.service
systemctl is-active myapp.service && systemctl is-enabled myapp.service

如果希望进程异常退出后自动拉起,可以在 [Service] 里加:

Restart=on-failure
RestartSec=5

不过自动重启只是兜底,根因还是要从上面的日志和退出码里找出来。

小结

排查顺序可以记成:systemctl status 看退出码,journalctl -u 看完整日志,对照状态码判断大类,再用服务身份在干净环境里手动执行一次,最后检查 unit 文件、SELinux 和端口占用。按这个顺序走,大多数“服务起不来”的问题几分钟内就能定位。

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

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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