systemd 服务起不来?五步排查法

交付给一线运维:一条服务重启了十几次、systemctl start 只回一句 Job for app.service failed, journalctl 里翻半天只有一行 exited。其实 systemd 的失败信息非常规范,按五步走, 从"现象分类"到"读到根因",五分钟内能定位到具体那一行配置。

一、先分清三种"起不来"

不同失败形态,排查入口完全不同,先归类再动手:

  1. 根本起不来 :systemctl start 立刻返回失败,进程连创建都没成功。多为 ExecStart 路径、权限、解释器问题,退出码常见 203/EXEC。
  2. 起来又马上退出 :能启动一秒,然后进程自己崩。表现为 Restart=always 不断重启,状态里是 activating (auto-restart),多半是应用自身配置或依赖问题。
  3. 起来了但状态不对 :Active: active (running),可端口不通、健康检查失败。这是 Type= 与就绪判定不匹配,或进程 daemon 化后 systemd 跟丢了。

二、第 1 步:systemctl status 一眼读四行

bash 复制代码
systemctl status app.service --no-pager

重点看四行:

  • Loaded: ------ unit 文件路径是否正确,是否被 masked、disabled。
  • Active: ------ 失败会直接标注 (Result: exit-code) 或 (Result: timeout)。
  • Process: ------ 实际执行的命令行,以及 status=203/EXEC 这类关键退出码。
  • 末尾日志 ------ 只有最近 10 行,够用来判断方向,但不足以定根因。

203/EXEC 基本等于"这个命令 systemd 跑不起来":路径写错、没有执行权限、shelbang 坏了、脚本是 CRLF 换行。

三、第 2 步:journalctl -u 拿全量日志

bash 复制代码
# 看这个服务最近 100 行
journalctl -u app.service -n 100 --no-pager

# 只看本次开机、只看错误级别
journalctl -u app.service -b -p err --no-pager

# 缩小到出问题的时间窗
journalctl -u app.service --since "10 min ago" --no-pager

三句高频报错的含义:

  • Unit app.service not found. ------ 文件没放在 /etc/systemd/system/,或放完没执行 systemctl daemon-reload。
  • Start request repeated too quickly. ------ 重启太密被 systemd 熔断,需要 systemctl reset-failed app.service 再试。
  • Address already in use ------ 端口被别的进程占了,用 ss -lntp 找占用者。

四、第 3 步:核对 unit 文件本身

bash 复制代码
systemctl cat app.service                  # 看最终生效内容(含 drop-in 覆盖)
systemd-analyze verify /etc/systemd/system/app.service   # 语法与依赖检查
systemctl show app.service -p ExecStart -p Environment   # 看 systemd 眼中的真实值

unit 文件里最容易写错的五处:

  1. ExecStart 必须写绝对路径 ,且不能带 shell 语法(管道、&&、重定向都要包一层 bash -c)。
  2. Type= 选错 。前台常驻用 simple(默认),会 fork 后退出的老程序要 forking + PIDFile,oneshot 只跑一次不能常驻。
  3. EnvironmentFile= 路径写错会让变量全空;写成 EnvironmentFile=-/etc/app/env(前面加 -)则文件缺失不报错。
  4. User= / Group= 指定的账号对 WorkingDirectory 和日志目录没有写权限,进程会直接退出。
  5. 依赖写反 :需要网络的要 After=network-online.target 且 Wants=network-online.target,只写 After=network.target 常常起太早。

改完 unit 文件必须:

bash 复制代码
systemctl daemon-reload
systemctl restart app.service

五、第 4 步:查环境差异与资源限制

最常见的"我手工跑明明可以"------因为交互 shell 和 systemd 的环境完全不同:

  • 不加载 /etc/profile :PATH 只有极简几条,java、node 找不到。解决:ExecStart 写全路径,或在 unit 里显式 Environment=PATH=/usr/local/bin:/usr/bin。
  • WorkingDirectory 默认是 /:相对路径配置一律找不到,必须显式指定。
  • 资源上限 :LimitNOFILE、MemoryMax、TasksMax 触顶会直接把进程打掉,journalctl 里能看到 oom 或 Failed to fork。
  • 沙箱与 SELinux :ProtectSystem=strict、PrivateTmp=true 会让服务看不到宿主机路径,表现为"文件明明存在却报 no such file"。
  • 看真实上限 :systemctl show app.service -p LimitNOFILE -p MemoryMax。

六、第 5 步:排除端口与依赖冲突

bash 复制代码
ss -lntp | grep -E ':8080|:3306'      # 端口是否被占
systemctl list-dependencies app.service --reverse | head

如果服务启动后秒退,且日志停在"connecting to db...",那就是依赖的下游没起来。此时不要给应用加 Restart=always 硬扛------重启掩盖的是依赖顺序问题 ,应该在 unit 里用 After= / Requires= 声明清楚,或在应用层加重试与退避。

七、避坑清单

  1. 改完 unit 不 daemon-reload:改动完全不生效,白排查半天。
  2. 用 Restart=always 掩盖根因 :日志被反复重启刷满,真正那一行错误被冲掉。先 systemctl stop 手动跑一次。
  3. ExecStart 里用 shell 语法 :管道、&&、$VAR 都不被解析,必须 bash -lc '...'。
  4. Type=forking 却没配 PIDFile :systemd 不知道主进程是谁,状态一直 activating 直到超时。
  5. TimeoutStartSec 太短:大应用初始化要 2 分钟,默认 90 秒直接判失败,应显式放宽。
  6. 脚本 CRLF 换行 :从 Windows 传上来的启动脚本会报 203/EXEC,dos2unix 一下。
  7. 别在 /usr/lib/systemd/system/ 里直接改 :升级会被覆盖,自定义放 /etc/systemd/system/,覆盖用 drop-in(/etc/systemd/system/app.service.d/override.conf)。

小结

口诀:看状态分类型 → 翻日志找报错 → 核 unit 查语法 → 比环境与限额 → 排端口与依赖。

systemd 的报错信息其实很诚实,它只是被"重启刷屏"和"环境不一致"藏起来了。 把服务先停掉手动跑一次、把 unit 文件当成代码来 review,绝大多数"起不来"都能一眼看破。

相关推荐
vibecode18 小时前
网站服务器失去响应怎么解决?我把连接超时和读超时这两段计时拆开跑了一遍
运维·服务器
工业一体机老司机19 小时前
Docker部署工控机采集服务 Compose编排与开机自启
运维·docker·容器
迪康Defender20 小时前
终端供应链安全:应用白名单与软件正版化检测落地|终端安全治理实践
运维·服务器·网络·安全·web安全·自动化·运维开发
万联WANFLOW1 天前
异地厂区视频监控远程运维:从组网到安全的实施要点
运维·网络·安全·企业组网·sdwan
十碗饭吃不饱1 天前
SSH 密钥认证详解:原理、实操、参数、排错与加固
运维·ssh
echoarts1 天前
服务器连不上?FileZilla 改被动模式就好了
运维·服务器·其他
无言听风雨丶1 天前
Redis 运维实战与排错
运维·数据库·redis
QXWZ_IA1 天前
变电站数字孪生巡检的能力分层、数据接入与空间计算边界
运维·服务器·空间计算
miaobinfei1 天前
docker拉取dify镜像,执行docker compose up -d 报错
运维·docker·容器
女神下凡1 天前
芯参谋(85):Linux_PPI_NAND_驱动开发指南
linux·运维·arm开发·驱动开发·单片机·嵌入式硬件·设计规范