如何用 systemd 管理自訂服務
在現代 Linux 發行版中,systemd 已經取代了傳統的 SysVinit,成為系統初始化和服務管理的標準。對於開發者和系統管理員來說,能夠自訂並管理自己的服務(Service)是日常工作的核心技能。無論是你寫的 Python 腳本、Node.js 應用,還是其他後台程序,透過 systemd 管理都能讓它們在開機時自動啟動、崩潰時自動重啟,並方便地查看日誌。
這篇文章將引導你從零開始,建立一個簡單的自訂服務,涵蓋檔案建立、權限設定、啟用服務以及除錯技巧。
步驟一:準備測試腳本
首先,我們需要一個簡單的腳本作為示範。為了方便理解,我們建立一個會持續輸出時間的 Python 腳本。請在 /opt 目錄下建立一個資料夾並撰寫腳本:
sudo mkdir -p /opt/myapp
sudo nano /opt/myapp/app.py
在檔案中輸入以下內容:
#!/usr/bin/env python3
import time
import datetime
while True:
print(f"Current time: {datetime.datetime.now()}")
time.sleep(5)
儲存並離開後,務必賦予該腳本執行權限:
sudo chmod +x /opt/myapp/app.py
步驟二:建立 systemd 服務單元檔案
systemd 的服務配置檔通常存放在 /etc/systemd/system/ 目錄下,副檔名為 .service。我們要建立一個名為 myapp.service 的檔案。
sudo nano /etc/systemd/system/myapp.service
請填入以下內容。這裡我們使用 User 和 Group 來確保服務以非 root 身份運行,這是安全最佳實踐:
[Unit]
Description=My Custom Application Service
After=network.target
[Service]
Type=simple
User=ubuntu
Group=ubuntu
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/app.py
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
關鍵參數說明:
ExecStart:指定啟動服務時執行的完整路徑指令。Restart=on-failure:當程式異常退出時,系統會自動重啟服務。WantedBy=multi-user.target:確保服務在系統進入多使用者模式(一般開機狀態)時被啟用。
步驟三:啟用並啟動服務
修改完配置後,必須重新載入 systemd 的 daemon 配置,讓系統識別新的服務檔案。
sudo systemctl daemon-reload
接著,我們啟用並啟動服務:
sudo systemctl enable --now myapp.service
enable 會建立符號連結,確保開機時自動啟動;--now 參數則會立即啟動該服務。你可以透過以下指令檢查服務狀態:
sudo systemctl status myapp.service
如果看到綠色的 active (running) 狀態,且下方有輸出時間訊息,代表服務已成功運行。
常見問題與除錯技巧
1. 服務無法啟動,狀態顯示為 failed
當服務啟動失敗時,systemctl status 通常只會顯示最後幾行錯誤。更詳細的資訊可以透過 journalctl 查詢。由於我們配置了將標準輸出和錯誤導向 journal,你可以使用以下指令查看最近的日誌:
sudo journalctl -u myapp.service -e
-e 參數會直接跳到日誌末尾,-f 則可以即時追蹤日誌(類似 tail -f)。如果發現路徑錯誤或權限問題,請檢查 ExecStart 中的路徑是否正確,以及 User 是否有權限讀取腳本和相關檔案。
2. 修改配置後服務沒有生效
許多使用者在修改 .service 檔案後,直接執行 sudo systemctl restart myapp.service,但發現更改無效。這是因為 systemd 在啟動時會讀取配置,若配置結構有變(例如新增了環境變數或修改了 Restart 策略),有時需要重新載入 daemon 才能完全生效。
標準的更新流程應為:
- 編輯服務檔案。
- 執行
sudo systemctl daemon-reload。 - 執行
sudo systemctl restart myapp.service。
若仍無法解決,可嘗試 sudo systemctl reload myapp.service,但這僅適用於支援熱重載的服務。對於大多數簡單服務,重啟是必要的。
小結
透過這篇文章,我們學會了如何建立自訂的 systemd 服務單元檔案。這不僅適用於 Python 腳本,同樣也適用於 Go、Node.js、Java 等任何可執行程式。掌握 systemctl 和 journalctl 的組合使用,能讓你在管理後台服務時更加得心應手。記住,良好的服務配置(如正確的權限和重啟策略)是維持系統穩定性的關鍵。