寫 systemd unit 檔踩過的坑,比想像中多。這篇整理平常排查問題最常用到的指令組合。

先看服務目前狀態

systemctl status my-service.service

重點看三個地方:Active 狀態(running / failed / activating)、Main PID,以及底下附帶的最後幾行 log。

查完整 log

# 只看這個服務的 log
journalctl -u my-service.service

# 從這次開機以來的 log
journalctl -u my-service.service -b

# 即時追蹤
journalctl -u my-service.service -f

# 只看最近 100 行
journalctl -u my-service.service -n 100

-b 很重要:預設 journalctl 可能會混雜前幾次開機的 log,除錯這次的問題卻看到上次的錯誤訊息,容易誤判。

服務一直重啟(restart loop)

先確認重啟策略:

systemctl show my-service.service -p Restart -p RestartUSec -p StartLimitBurst -p StartLimitIntervalSec

如果 Restart=always 又沒設好 StartLimitBurst,服務崩潰時會不斷瘋狂重啟、灌爆 log。建議至少設:

[Service]
Restart=on-failure
RestartSec=2
StartLimitIntervalSec=60
StartLimitBurst=5

超過次數限制後 systemd 會直接把服務標記為 failed,不再自動重啟,這時要 systemctl reset-failed 才能重新啟動。

環境變數沒吃到

systemd service 不會繼承你 shell 裡的環境變數,.bashrc.profile 裡設的東西一律無效。要嘛寫在 unit 檔的 Environment=,要嘛用 EnvironmentFile= 指向一個 .env 檔案:

[Service]
EnvironmentFile=/etc/my-service/env

權限問題

service 預設常常是用 root 或某個 system user 執行,跟你手動在終端機用自己帳號跑起來的行為可能不一樣(檔案權限、家目錄路徑都不同)。用 User=Group= 明確指定執行身份,比讓它用預設值更容易除錯。

小結

九成的 systemd 除錯問題,答案都藏在 journalctl -u <service> -b 裡;只是很多人忘記加 -b,結果被上一次開機的 log 誤導方向。