第 4 課 · 服務管理:systemd 單元、開機自啓、日志
現代 Linux 的服務都由 systemd 統一管理:啓動順序、崩潰拉起、開機自啓、日志歸集——學會 systemctl 與 journalctl 兩個命令,你就掌握了服務器上所有服務的「生老病死」。
概念三分鍾:unit、service、target
systemd 管理的一切對象叫 unit(單元),配置文件在 /etc/systemd/system/(自己寫的)與 /lib/systemd/system/(軟件包帶的)。最常用的 unit 類型是 .service(服務);.timer(定時任務,cron 的現代替代)與 .target(運行級別組)了解即可。服務的狀態機:inactive(停)→ active/running(跑)→ failed(掛了)。
systemctl:五個動詞覆蓋日常
systemctl status nginx # 狀態總覽:在不在跑、PID、最近日志、開機自啓否
systemctl start nginx # 啓動
systemctl stop nginx # 停止
systemctl restart nginx # 重啓(reload 是不斷連接重讀配置,幫助的服務優先用 reload)
systemctl enable --now nginx # 開機自啓 + 立即啓動(--now 一步到位)
systemctl disable nginx # 取消自啓(list-unit-files --type=service 看全部自啓清單)
journalctl:日志的時間機器
systemd 把服務日志統一收進 journal——按服務、按時間、按優先級檢索:
journalctl -u nginx --since "1 hour ago" | tail -50 # 某服務最近一小時
journalctl -u nginx -f # 實時追蹤(等效 tail -f)
journalctl -p err -b # 本次開機的所有錯誤級日志
journalctl --disk-usage # journal 佔用(可配置上限防喫盤)
傳統日志文件(/var/log/syslog、應用自己的日志)仍在——journal 是補充不是替代,兩邊都學會查。
寫一個最小 service:把你的腳本變成服務
# /etc/systemd/system/mybot.service —— 讓一個腳本開機自啓+崩潰自動拉起
[Unit]
Description=My background bot
After=network-online.target # 等網絡就緒再啓動
[Service]
ExecStart=/usr/local/bin/mybot.sh # 啓動命令(絕對路徑)
Restart=on-failure # 異常退出自動拉起
RestartSec=5
User=mybot # 專用低權限用戶運行(別用 root)
[Install]
WantedBy=multi-user.target
# 生效三步:
systemctl daemon-reload # 重載 unit 定義(改過文件就要跑)
systemctl enable --now mybot
systemctl status mybot && journalctl -u mybot -n 20
這個模板覆蓋了託管腳本的八成需求;User= 一行是安全習慣:服務用專用低權限用戶跑,被攻破時的損失面小一個量級。
服務起不來:四步定位
# ① 狀態裏的退出碼與最後幾行日志(八成的答案直接寫在這)
systemctl status mybot -l | tail -15
# ② 手動前臺跑一次啓動命令(錯誤直接打到臉上)
sudo -u mybot /usr/local/bin/mybot.sh
# ③ 檢查 unit 語法與路徑(相對路徑/權限/依賴順序是三大常見錯)
systemd-analyze verify /etc/systemd/system/mybot.service
# ④ 端口衝突類:目標端口被誰佔了
ss -tlnp | grep :端口號
與 cron 的分工
定時任務兩條路線:傳統 cron(crontab -e,一行一任務,簡單直接)與 systemd timer(unit 化,有日志、有依賴管理、錯過可補跑)。經驗口徑:簡單定時用 cron 不丟人,需要日志歸集與失敗重試的用 timer——兩者的任務都要進你的運維文檔,「機器上到底跑了什麼定時任務」必須可回答。
依賴順序:After 與 Wants 的語義差
unit 文件裏的依賴有兩個容易混淆的關鍵字:After/Before 只管順序(網絡就緒後再啓動我),Requires/Wants 管綁定(它掛了/停了怎麼辦)。常用組合是 After=network-online.target + Wants=network-online.target——既等網絡又聲明需要它;Requires 比 Wants 強(被依賴方故障會連帶停你),日常服務用 Wants 足夠,濫用 Requires 會把小故障放大成連鎖停機。改完 unit 文件必須 systemctl daemon-reload 再操作服務——忘了這一步,systemd 還在用舊定義,「我明明改了怎麼不生效」的第一嫌疑人。
服務加固:unit 裏的安全選項
systemd 自帶一層服務沙箱能力,寫進 [Service] 段即可,成本幾乎爲零:User=/Group=(低權限身份運行,前一課講過);NoNewPrivileges=true(進程及其子進程永遠不能獲得新特權——擋掉一類提權路徑);ProtectSystem=strict + ReadWritePaths=(文件系統只讀,只開放它必須寫的目錄);PrivateTmp=true(私有 /tmp,與其他服務隔離);Restart=on-failure + RestartSec=5(崩潰拉起但別無限快循環)。逐項加、每加一項 systemctl restart 驗證服務仍正常——加固與可用性的平衡就是這樣一小步一小步試出來的;這套選項的完整文檔在 man systemd.exec,值得通讀一遍目錄。
本節小結
- systemctl 五動詞(status/start/stop/restart/enable)管理服務生命周期,reload 優於 restart;
- journalctl -u 服務名是查日志的第一入口,-f 實時追、-p err 看錯誤級;
- 自建 service 三要素:After 依賴、Restart 拉起、User 低權限——起不來按四步定位。