近期碰到了一个 Linux Systemd 服务 Crash, Crash 后需要人工介入重启. 那么, 有没有办法如何实现 Linux 服务 Crash 后自动重启?
Systemd
Systemd Restart
Systemd 允许你对服务进行配置,以便在服务崩溃时自动重启。
一个典型的单元文件是这样的:
[Unit]
Description=Tailscale node agent
After=network-online.target
Wants=tailscale-weekly-update.timer
[Service]
Type=oneshot
ExecStart=/usr/bin/tailscale update -yes
[Install]
WantedBy=multi-user.target
在上面的例子中,如果守护进程崩溃或被杀死,systemd 不会去管它。
不过,你可以让 systemd 自动重启守护进程,以防它崩溃或意外被杀掉。为此,你可以在 [Service]
中添加 Restart
选项。典型的示例如下:
[Unit]
Description=Lightweight Kubernetes
Documentation=https://k3s.io
Wants=network-online.target
After=network-online.target
StartLimitIntervalSec=600
StartLimitBurst=5
[Install]
WantedBy=multi-user.target
[Service]
Type=notify
EnvironmentFile=-/etc/systemd/system/k3s.service.env
KillMode=process
Delegate=yes
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
TimeoutStartSec=0
Restart=always
RestartSec=5s
ExecStartPre=/bin/sh -xc '! /usr/bin/systemctl is-enabled --quiet nm-cloud-setup.service'
ExecStartPre=-/sbin/modprobe br_netfilter
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/k3s \
server \
上述操作会对任何导致守护进程停止的情况做出反应...只要守护进程停止,systemd 就会在 5 秒内重启它。
Restart
有 2 个可选参数:
•always
•on-failure
: 即故障时重启. 涵盖了最广泛的故障情形,如信号不清和退出代码不清:
在本例中,[Unit]
部分还有 StartLimitIntervalSec
和 StartLimitBurst
指令。这可以防止故障服务每 5 秒钟重启一次。如果仍然失败,systemd 将停止尝试启动服务。
如果服务在 600 秒内 5 次尝试重启均未成功,则应进入失败状态,不再尝试重启。这样就能确保如果服务真的坏了,systemd 不会继续尝试重启它。应该人工上去处理了。
如果在守护进程被杀死后询问其状态,systemd 会显示正在activating (auto-restart)
。
Systemd OnFailure
重启一项服务固然很好,但在某个单元出现故障时采取特定行动就更好了。也许你使用的软件有一个已知的错误,要求在崩溃时删除缓存文件,也许你想启动一个脚本来收集日志和系统信息,以便诊断问题。Systemd 允许你指定在服务失败时运行的单元。
[Unit]
Description=Lightweight Kubernetes
Documentation=https://k3s.io
Wants=network-online.target
After=network-online.target
StartLimitIntervalSec=600
StartLimitBurst=5
OnFailure=k3s-recovery.service
[Install]
WantedBy=multi-user.target
[Service]
Type=notify
EnvironmentFile=-/etc/systemd/system/k3s.service.env
KillMode=process
Delegate=yes
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
TimeoutStartSec=0
Restart=on-failure
RestartSec=5s
ExecStartPre=/bin/sh -xc '! /usr/bin/systemctl is-enabled --quiet nm-cloud-setup.service'
ExecStartPre=-/sbin/modprobe br_netfilter
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/k3s \
server \
此示例指定 OnFailure=k3s-recovery.service
来告诉 systemd,如果我的服务失败,它就应该启动 k3s-recovery
单元.
k3s-recovery
单元只是一个运行此脚本的一次性服务单元:
[Unit]
Description=K3s recovery
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/k3s-recovery.sh
这个脚本可以做任何事情:执行一些手动变通方法让服务重新运行,向监控系统发出警报,或者压缩一些临时日志和应用程序状态以排除故障。示例如下:
#!/bin/bash
echo 'Attempting to recover!' > /tmp/recovery_info
systemctl stop k3s.service
/usr/local/sbin/k3s-killall.sh
systemctl start k3s.service
Systemd FailureAction reboot
还有一种可能, 重启治百病! 所以 systemd 内置了在单元故障时触发系统重启的功能。在本例中,当单元发生故障时,系统将优雅地重新启动:
[Unit]
Description=Lightweight Kubernetes
Documentation=https://k3s.io
Wants=network-online.target
After=network-online.target
StartLimitIntervalSec=600
StartLimitBurst=5
FailureAction=reboot
[Install]
WantedBy=multi-user.target
[Service]
Type=notify
EnvironmentFile=-/etc/systemd/system/k3s.service.env
KillMode=process
Delegate=yes
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
TimeoutStartSec=0
Restart=on-failure
RestartSec=5s
ExecStartPre=/bin/sh -xc '! /usr/bin/systemctl is-enabled --quiet nm-cloud-setup.service'
ExecStartPre=-/sbin/modprobe br_netfilter
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/k3s \
server \
FailureAction
有多种有效值: none
, reboot
, reboot-force
, reboot-immediate
, poweroff
, poweroff-force
, poweroff-immediate
, exit
, exit-force
, soft-reboot
, soft-reboot-force
, kexec
, kexec-force
, halt
, halt-force
和 halt-immediate
.
总结
本文介绍了服务异常时, 自动处理故障的一些方式。Systemd 包含强大的功能,可自动响应以保持服务运行。