Systemd 概述
Systemd 是現代 Linux 發行版中最常見的初始化系統(init system),負責管理系統啟動流程、服務管理、日誌記錄等核心功能。在 Ubuntu 22.04 中,systemd 已成為預設的服務管理工具,取代了傳統的 SysVinit。
Systemd 的主要特點包括:
- 平行化啟動:加快系統開機速度
- 按需啟動:服務可在需要時才啟動
- 統一管理介面:透過
systemctl 統一管理所有服務 - 依賴關係追蹤:自動處理服務間的依賴
- 日誌整合:透過 journald 統一管理系統日誌
Unit 檔案結構與類型
Systemd 使用 Unit 檔案來定義各種系統資源。常見的 Unit 類型包括:
| 類型 | 副檔名 | 說明 |
|---|
| Service | .service | 定義系統服務 |
| Timer | .timer | 定時任務(類似 cron) |
| Socket | .socket | Socket 啟動服務 |
| Target | .target | 服務群組 |
| Mount | .mount | 掛載點 |
| Path | .path | 檔案系統路徑監控 |
Unit 檔案的存放位置:
/etc/systemd/system/:系統管理員自訂的 Unit 檔案(優先權最高)/run/systemd/system/:執行時期產生的 Unit 檔案/lib/systemd/system/:套件安裝的 Unit 檔案
建立自訂服務單元
以下是一個完整的自訂服務範例,用於執行一個 Python Web 應用程式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| # /etc/systemd/system/myapp.service
[Unit]
Description=My Python Web Application
Documentation=https://example.com/docs
After=network.target postgresql.service
Wants=postgresql.service
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/opt/myapp
Environment="PATH=/opt/myapp/venv/bin"
Environment="PYTHONUNBUFFERED=1"
ExecStartPre=/opt/myapp/venv/bin/python manage.py migrate
ExecStart=/opt/myapp/venv/bin/gunicorn -w 4 -b 0.0.0.0:8000 myapp.wsgi
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -TERM $MAINPID
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
|
建立服務後,執行以下指令啟用:
1
2
3
4
5
6
7
8
9
10
11
| # 重新載入 systemd 設定
sudo systemctl daemon-reload
# 啟動服務
sudo systemctl start myapp
# 設定開機自動啟動
sudo systemctl enable myapp
# 檢查服務狀態
sudo systemctl status myapp
|
Service 區段詳細設定
Service 區段是服務 Unit 的核心,以下是常用的設定選項:
Type 類型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| [Service]
# simple:預設值,ExecStart 啟動的程序為主程序
Type=simple
# forking:程序會 fork 子程序後退出
Type=forking
PIDFile=/run/myapp.pid
# oneshot:一次性執行,執行完畢後退出
Type=oneshot
RemainAfterExit=yes
# notify:服務準備好後會發送通知
Type=notify
NotifyAccess=main
|
執行身份與權限
1
2
3
4
5
6
7
8
9
10
11
| [Service]
User=appuser
Group=appgroup
# 禁止取得新權限
NoNewPrivileges=true
# 設定私有 /tmp
PrivateTmp=true
# 唯讀檔案系統
ProtectSystem=strict
# 允許寫入的目錄
ReadWritePaths=/var/lib/myapp /var/log/myapp
|
服務依賴關係設定
Systemd 提供多種方式來定義服務間的依賴關係:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| [Unit]
# 在這些服務啟動後才啟動(順序)
After=network.target mysql.service
# 在這些服務啟動前啟動(順序)
Before=nginx.service
# 需要這些服務同時執行(相依)
Requires=mysql.service
# 希望這些服務同時執行(弱相依)
Wants=redis.service
# 與這些服務衝突,無法同時執行
Conflicts=apache2.service
|
依賴關係範例圖:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| ┌─────────────┐
│ network │
└──────┬──────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ mysql │ │ redis │ │ mongodb │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
└────────────┼────────────┘
▼
┌─────────────┐
│ myapp │
└─────────────┘
|
資源限制(CPU、記憶體)
Systemd 整合了 cgroups,可以輕鬆限制服務的資源使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| [Service]
# 記憶體限制
MemoryMax=512M
MemoryHigh=400M
# CPU 限制(百分比,100% = 1 核心)
CPUQuota=50%
# CPU 權重(預設 100)
CPUWeight=50
# I/O 權重(預設 100)
IOWeight=50
# 檔案描述符限制
LimitNOFILE=65535
# 程序數量限制
LimitNPROC=4096
# 核心檔案大小限制
LimitCORE=infinity
|
完整的資源限制範例:
1
2
3
4
5
6
7
| # /etc/systemd/system/myapp.service.d/resources.conf
[Service]
MemoryMax=1G
MemoryHigh=800M
CPUQuota=200%
IOWeight=100
LimitNOFILE=65535
|
自動重啟策略
設定服務在異常退出時自動重啟:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| [Service]
# 重啟條件
# no:不重啟(預設)
# on-success:正常退出時重啟
# on-failure:異常退出時重啟
# on-abnormal:被訊號終止時重啟
# on-abort:被 abort 訊號終止時重啟
# on-watchdog:watchdog 逾時時重啟
# always:總是重啟
Restart=on-failure
# 重啟前等待秒數
RestartSec=5
# 重啟次數限制(在 StartLimitIntervalSec 秒內)
StartLimitBurst=5
StartLimitIntervalSec=60
# 達到重啟次數限制後的動作
StartLimitAction=reboot-force
|
Timer 定時任務
Systemd Timer 可以取代傳統的 cron,提供更靈活的定時任務管理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # /etc/systemd/system/backup.timer
[Unit]
Description=Daily Backup Timer
[Timer]
# 每天凌晨 2 點執行
OnCalendar=*-*-* 02:00:00
# 如果錯過執行時間,開機後立即執行
Persistent=true
# 隨機延遲 0-30 分鐘,避免多服務同時執行
RandomizedDelaySec=30min
[Install]
WantedBy=timers.target
|
對應的服務檔案:
1
2
3
4
5
6
7
8
9
| # /etc/systemd/system/backup.service
[Unit]
Description=Daily Backup Service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
User=backup
Group=backup
|
OnCalendar 語法範例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 每小時
OnCalendar=hourly
# 每天午夜
OnCalendar=daily
# 每週一早上 6 點
OnCalendar=Mon *-*-* 06:00:00
# 每月 1 日和 15 日
OnCalendar=*-*-1,15 00:00:00
# 每 15 分鐘
OnCalendar=*:0/15
|
啟用 Timer:
1
2
| sudo systemctl enable --now backup.timer
sudo systemctl list-timers
|
journalctl 日誌管理
Systemd 的 journald 提供強大的日誌管理功能:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| # 查看特定服務的日誌
sudo journalctl -u myapp.service
# 即時追蹤日誌
sudo journalctl -u myapp.service -f
# 查看最近 100 行
sudo journalctl -u myapp.service -n 100
# 查看特定時間範圍
sudo journalctl -u myapp.service --since "2024-02-01" --until "2024-02-02"
# 查看特定優先級(0=emerg 到 7=debug)
sudo journalctl -u myapp.service -p err
# 輸出為 JSON 格式
sudo journalctl -u myapp.service -o json-pretty
# 查看開機日誌
sudo journalctl -b
# 查看核心訊息
sudo journalctl -k
|
日誌保留設定(/etc/systemd/journald.conf):
1
2
3
4
5
6
7
8
9
| [Journal]
# 日誌最大佔用空間
SystemMaxUse=500M
# 單一日誌檔案最大大小
SystemMaxFileSize=50M
# 日誌保留時間
MaxRetentionSec=1month
# 壓縮日誌
Compress=yes
|
參考資料