Linux 服务启动失败:用 systemd 和 journalctl 定位原因
业务发布后服务起不来,值班常会反复 systemctl restart。重启几次仍失败时,应先固定证据:看单元状态和本轮启动日志,再对照常见原因排除。下面以自建单元 app.service 为例。
先看状态和定义
systemctl status app
systemctl cat app
status 给出 Active、主进程 PID、最近日志,以及是否出现 start-limit-hit。cat 打印实际生效的单元文件(含 drop-in),用来核对 ExecStart、User、Environment 和 Restart。避免只盯日志却改错文件。若已是 failed 或正在自动重启,先不要再盲目重启。
用 journalctl 拉全日志
status 只截了尾巴,完整记录在 journal 里:
journalctl -u app -b
journalctl -u app --since "10 min ago"
journalctl -u app -p err
journalctl -u app -f
-u 限定该服务;-b 只看本次开机;--since 缩到刚才发布或重启的时段;-p err 先滤错误级,避免海量信息淹没关键行;-f 用于再执行 start 时盯新日志。必要时去掉级别过滤,回看前后文,原因常写在警告或应用输出里。
常见原因对照
ExecStart 路径写错最常见:二进制不在指定路径、发布后目录变了,或相对路径依赖了错误的工作目录。状态里会出现 status=203/EXEC 或找不到文件。用 ls 核对绝对路径,改完必须 systemctl daemon-reload 再启动,否则仍用旧定义。
权限和 User 不匹配:单元指定了 User=app,但可执行文件、配置或日志目录属于 root,进程一启动就没有访问权限。对照属主和权限,把工作目录和数据目录预先 chown 给该用户。
端口被占用:监听端口已被旧进程或其他实例占用,日志会提示地址已被使用。用 ss -lptn 查出占用进程,确认是不是上次没退出的进程,再决定停谁。
环境变量缺失:交互终端能启动,交给 systemd 就失败,多半是 PATH 或配置路径只写在用户 shell 里。把必要变量放到 Environment= 或 EnvironmentFile=,不要假设会读 .bashrc。
Restart 限速触发 start-limit-hit:Restart=always 且启动瞬间失败时,短时间重启次数打满,单元进入失败,再启动也会被拒。先修好根因,再执行 systemctl reset-failed app,若改过单元还要 daemon-reload,然后启动。只复位计数不修根因,很快会再次触顶。
改完记得 daemon-reload
凡是改了系统目录下的单元或附加配置,都必须先 systemctl daemon-reload,再启动或重启。漏掉会误以为修改没生效。改完再用 cat 确认,用 journalctl -u app -f 观察一次干净启动。
小结
服务启动失败,先用状态和单元定义固定现场,再用 journalctl -u -b --since -p err -f 看全量或实时日志。对照 ExecStart 路径、User 权限、端口占用、环境变量和 start-limit-hit 逐项排除,改单元后执行 daemon-reload。写进发布检查单,比反复重启更能一次定位。
- 点赞
- 收藏
- 关注作者
评论(0)