寫 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 誤導方向。