服务挂了没人重启?systemd 开机自启 + 失败自动拉起
服务器重启后网站没起来,或者程序半夜自己挂了、早上才发现,这两种事都有一个共同原因:那个服务没有交给系统管。手动在终端里跑起来的进程,终端一关、机器一重启就没了;想要它一直活着,就得把它写成一个服务,让 systemd 负责启动、看护和重启。
第一步:先看清,服务现在是谁在管
先确认两件事:服务有没有开机自启,当前是不是活着。
systemctl is-enabled myapp
systemctl is-active myapp
systemctl status myapp --no-pager
is-enabled 回答的是“下次开机还会不会起来”,is-active 回答的是“现在活没活着”,这两个问题不一样。一个服务可以现在活着但没开自启,重启就丢;也可以开了自启但现在挂了,等下次重启才回来。排障时先分清是哪一种,再动手。
第二步:写一个最小可用的 service 文件
假设程序在 /opt/myapp/app,启动命令就是直接运行它,写一个单元文件 /etc/systemd/system/myapp.service:
[Unit]
Description=My App Service
After=network.target
[Service]
ExecStart=/opt/myapp/app
WorkingDirectory=/opt/myapp
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
几个字段各管一件事:After 保证网络就绪后再启动,避免程序起来时网络还没好;WorkingDirectory 决定程序的相对路径和默认工作目录,写错了程序可能找不到配置文件;Restart=always 是本篇的核心,进程退出就自动拉起来;RestartSec=5 是两次重启之间等 5 秒,别让一个起不来的程序在 1 秒内反复崩、把日志刷爆。
写完之后不是直接能用,要先让 systemd 重新读配置,再开自启、再启动:
systemctl daemon-reload
systemctl enable myapp
systemctl start myapp
顺序不能乱:daemon-reload 在前,否则 systemd 读到的还是旧文件;enable 只管开机自启,不管现在活不活;start 只管现在,enable 和 start 要分开做。
第三步:验证自愈真的生效,而不只是“看起来生效”
写完就信了,是最常见的坑。验证要做两步,缺一不可。
第一步,杀掉进程,看它是不是自己回来:
systemctl status myapp --no-pager
# 记下主进程 PID,kill 掉它,再看 status
kill <主进程 PID>
systemctl status myapp --no-pager
如果 Restart=always 生效,几秒后会看到一个新的 PID,服务状态回到 active。第二步,重启机器,看开机后是不是自己起来——只在能接受短暂停机的机器上做,生产服务先在测试机上验证。两步都过了,这个服务才算真正交给了系统。
第四步:挂了之后,先看日志再改配置
服务反复重启,先别急着改 Restart 参数,先看它为什么死。systemd 的日志用 journalctl 查:
journalctl -u myapp --since "1 hour ago" --no-pager
看最近一小时的报错:是配置文件路径错、端口被占、还是依赖的数据库没起来。端口被占时,先看是谁占了端口,再决定是改程序端口还是停掉冲突的服务;依赖没起来时,After 里要补上对应的目标,而不是把 RestartSec 调大去“等运气”。日志里没有报错、进程却反复退出时,再去看程序自己的日志文件,systemd 只管拉起进程,不管程序内部为什么退出。
一个容易踩的边界
Restart=always 不是万能药。程序本身有 bug、启动就崩、依赖的数据一直缺失时,自动重启只会让它无限崩下去,日志越刷越多。这时正确的做法是先停掉服务(systemctl stop myapp),修好根本原因,再重新启动验证,而不是把重启策略调得更激进。自愈管的是“偶发挂掉”,不是“一直起不来”。
一句话收尾
把服务交给 systemd,就三件事:写好 service 文件、enable 加 start 分开做、杀进程和重启机器各验证一次。做到这三条,半夜挂掉的服务不用等你早上手动拉,重启后的机器也不用你一个个去起服务。
- 点赞
- 收藏
- 关注作者
评论(0)