如何實現 Linux 服務 Crash 後自動重啓?

概述

近期碰到了一個 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 個可選參數:

alwayson-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 有多種有效值: nonerebootreboot-forcereboot-immediatepoweroffpoweroff-forcepoweroff-immediateexitexit-forcesoft-rebootsoft-reboot-forcekexeckexec-forcehalthalt-force 和 halt-immediate.

總結

本文介紹了服務異常時, 自動處理故障的一些方式。Systemd 包含強大的功能,可自動響應以保持服務運行。

References

[1] Auto-restart a crashed service in systemd (ttias.be): https://ma.ttias.be/auto-restart-crashed-service-systemd/
[2] Set up self-healing services with systemd | Enable Sysadmin (redhat.com): https://www.redhat.com/sysadmin/systemd-automate-recovery

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/5foPUpX26ddWnS3-Fpg-tA