Linux Systemd Service 設定與 Journalctl
在上一篇 systemctl 中,我們學會了如何管理現有的服務。
這篇我們將深入探討:如何撰寫自己的 Service 設定檔,讓你的程式 (Python, Go, Node.js 等) 也能像 Nginx 一樣開機自動啟動、掛掉自動重啟。
以及如何使用 journalctl 查看服務的 Log。
撰寫 Systemd Service 設定檔
Systemd 的設定檔通常放在 /etc/systemd/system/ 目錄下,副檔名為 .service。
1. 設定檔結構範例
假設我們有一個 Python 程式 /opt/my-app/main.py。
我們建立一個設定檔:sudo nano /etc/systemd/system/my-app.service
[Unit]
Description=My Custom Python App
After=network.target
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/opt/my-app
ExecStart=/usr/bin/python3 /opt/my-app/main.py
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
2. 欄位詳解
[Unit]區塊:基本資訊
Description: 服務的描述(顯示在status裡)。After: 定義啟動順序。例如network.target代表「等網路功能啟動後,才啟動我」。(注意:這不是依賴關係,只是順序)。
[Service]區塊:執行細節 (最重要)
Type: 通常設為simple(預設值)。如果你的程式會 fork 子行程 (如 nginx),則可能要設為forking。User/Group: 指定以哪個使用者身份執行。強烈建議不要用 root,除非必要。WorkingDirectory: 程式的工作目錄 (也就是程式裡.代表的地方)。ExecStart: 最重要的欄位。啟動指令。- 注意: 必須使用 絕對路徑!例如
/usr/bin/python3而不是python3。
Restart: 定義什麼時候要自動重啟。no(預設): 永不重啟。on-failure: 只有在程式「非正常退出」 (Exit code != 0) 時才重啟。always: 無論如何都重啟 (包含你手動 kill 它)。適合長期運行的 Daemon。
RestartSec: 重啟前要等幾秒。
[Install]區塊:安裝設定
WantedBy: 指定這個服務掛載在哪個 Target 下。multi-user.target: 最常用,代表「多使用者文字模式」 (類似傳統 Runlevel 3)。- 如果沒寫這行,
systemctl enable會無法運作。
3. 套用新設定
寫好設定檔後,必須通知 Systemd 重新讀取設定:
# 1. 重載 Systemd 設定 (只要修改了 .service 檔都要跑這行)
sudo systemctl daemon-reload
# 2. 啟動服務
sudo systemctl start my-app
sudo systemctl enable my-app
User Service (使用者層級服務)
這是一個非常實用但常被忽略的功能。
上述的服務都是 System Service (放在 /etc/systemd/system/),由 root 管理,開機時啟動。
Systemd 也支援 User Service:
- 位置:放在
~/.config/systemd/user/目錄下 (目錄不存在請自己 mkdir)。 - 權限:不需要 sudo,以該使用者身份執行。
- 時機:當使用者「登入」時啟動,使用者「完全登出」時停止 (除非啟用 lingering)。
1. 建立 User Service
假設我想跑一個自己的 Python 腳本,不想麻煩管理員。
建立檔案:mkdir -p ~/.config/systemd/user/
編輯:nano ~/.config/systemd/user/my-bot.service
注意:不需要 User= 和 Group= 欄位(因為就是你本人)。
[Unit]
Description=My Telegram Bot
[Service]
ExecStart=/usr/bin/python3 /home/miko/bot.py
Restart=always
[Install]
WantedBy=default.target
(注意:這裡用 default.target 而不是 multi-user.target)
2. 管理 User Service
指令跟平常一樣,但在 systemctl 後面加上 --user。
# 重載設定
systemctl --user daemon-reload
# 啟動服務
systemctl --user start my-bot
# 查看狀態
systemctl --user status my-bot
# 設定登入自啟
systemctl --user enable my-bot
3. 如何讓 User Service 在登出後繼續跑? (Lingering)
預設情況下,當你登出 Server,你的 User Service 就會被殺掉。 如果你希望它像 System Service 一樣一直在背景跑(即使你沒登入),你需要啟用 Lingering:
# 請用 sudo 幫該使用者開啟 lingering
sudo loginctl enable-linger <username>
更多 Unit 設定技巧
設定檔還有很多好用的參數:
- EnvironmentFile: 從檔案讀取環境變數 (例如
.env檔)。[Service] EnvironmentFile=/opt/my-app/.env - Before / After: 控制啟動順序。
[Unit] # 在 nginx 啟動之前,先啟動我 Before=nginx.service # 在 mysql 啟動之後,才啟動我 After=mysql.service - Requires / Wants: 定義依賴關係。
Requires=mysql.service: 如果 MySQL 掛了或沒開,我也不能開 (強依賴)。Wants=mysql.service: 我希望 MySQL 開,但他沒開我也無所謂 (弱依賴)。
進階 Log 管理 (journalctl)
Systemd 統一管理了所有服務的 Log,我們不需要去 /var/log 翻檔案,直接用 journalctl 指令即可。
對於 User Service,記得加上 --user。
常用過濾方式
# 查看特定服務的 Log
journalctl -u nginx
# 持續追蹤 Log (Follow mode)
journalctl -u nginx -f
# 查看某個時間點之後的 Log
journalctl -u nginx --since "2023-12-01 12:00:00"
journalctl -u nginx --since "1 hour ago"
# 只顯示錯誤 (Error) 等級
journalctl -p err
# 以 JSON 格式輸出 (方便程式解析)
journalctl -u nginx -o json-pretty
清理 Log (Vacuum)
Systemd 的 Log 預設會一直存,可能會吃光硬碟。
# 檢查 Log 佔用了多少空間
journalctl --disk-usage
# 清理 Log,只保留最近 1GB
sudo journalctl --vacuum-size=1G
# 清理 Log,只保留最近 1 週
sudo journalctl --vacuum-time=1weeks