Systemd vs. Docker:是敵是友?誰來管理誰?
在上一篇文章《解鎖 systemd:現代 Linux 開發者不可不知的服務管理利器》中,探討了如何利用 systemd
來優雅地管理應用程式。一個非常核心且重要的問題:「既然有了 Docker 和 Docker Compose,為什麼還需要 systemd
呢? 如果用了 Docker,還需要 systemd
嗎?」
讓我們來深入剖析這兩者之間的關係,會發現,它們並非互相取代的競爭對手,而是一對相輔相成的黃金搭檔。
理解各自的職責:分層的藝術
要理解 systemd
和 Docker
的關係,最關鍵的一點是:它們解決的是不同層面的問題。
用一個生動的比喻來理解:
Linux 作業系統
:就像一棟辦公大樓,提供了基礎設施(水、電、空間)。systemd
:是這棟大樓的總務與保全系統。它的職責是確保大樓的基礎服務正常運轉,比如確保電力系統 (network.target
) 在上班前就已啟動,並在伺服器(大樓)重啟時,自動化地讓各個辦公室(服務)恢復運作。它關心的是「程序是否在作業系統層級上運行」。Docker
:則像是一個個**「拎包入住」的模組化辦公室**。每個辦公室(Container)都自帶了所有必需的辦公用品、裝潢和特定環境(應用程式的函式庫、依賴、配置),與隔壁辦公室完全隔離。Docker
關心的是「應用程式能否在一個隔離且一致的環境中運行」。Docker Compose
:是部門規劃師。他拿著一張藍圖 (docker-compose.yml
),規劃:「這個部門需要三個辦公室,一個是前端,一個是後端,一個是資料庫,而且它們之間可以用內線電話(虛擬網路)溝通。」
從這個比喻中,可以清楚地了解:systemd
負責管理整棟大樓的運轉,而 Docker
則負責管理每個辦公室內部的環境。
為什麼不直接用 Docker 就好?
可能會想說:「應用程式和它的所有依賴都在 Docker Compose 裡定義好了,只要 docker compose up -d
就能跑起來,為什麼還需要 systemd
這個『大樓管理員』呢?」
原因有二:
1. 誰來管理 Docker 自己?
Docker Engine (即 dockerd
服務) 本身就是一個需要在作業系統上運行的背景程序。當伺服器開機時,是什麼東西自動啟動了 dockerd
服務,讓你可以使用 docker
指令?
答案正是 systemd
!
可以隨時在 Linux 伺服器上執行這個指令來驗證:
sudo systemctl status docker.service
會看到 docker.service
正在被 systemd
管理著。systemd
確保了 Docker 這個「模組化辦公室的供應商」在伺服器啟動時就已經準備就緒。
2. 追求的是終極可靠性
Docker
和 Docker Compose
提供了優秀的內部管理機制。例如,可以在 docker-compose.yml
中為服務設定 restart: always
。
# docker-compose.yml
services:
my-app:
image: my-app-image
restart: always # 當容器停止時,Docker 會自動重啟它
這在大部分情況下都很好用。但是,如果發生了更嚴重的問題,例如 Docker Engine (dockerd
) 本身崩潰了或被意外停止了呢?
這時,所有由它管理的容器(無論 restart
策略是什麼)都會停止運行,而且無法自行恢復。就像辦公室的電力總開關被關了,單個辦公室內的備用電源是沒用的。
這時,就需要更高層級的管理者——systemd
——登場了。
用 systemd
來管理 Docker Compose
這就是最佳實踐的誕生:用 systemd
來啟動、停止和監控我們的 docker-compose
應用。
這樣做,我們就建立了一個強大的、多層次的可靠性保障:
- 容器層級:Docker 負責在容器內部保持應用程式健康。
- 主機層級:
systemd
負責確保整個 Docker Compose 應用(作為一個整體單元)在主機上始終運行。
實戰:為 Docker Compose 建立一個 systemd
服務
假設 docker-compose.yml
放在 /home/user/my_docker_app/
目錄下。可以像這樣為它建立一個 systemd
服務檔:
# /etc/systemd/system/my-docker-compose-app.service
[Unit]
Description=My Docker Compose Application
# 要求 docker.service 必須先啟動
Requires=docker.service
# 在 docker.service 啟動之後再啟動本服務
After=docker.service
[Service]
# 使用你的使用者
User=myuser
# Docker Compose 檔案所在的目錄
WorkingDirectory=/home/myuser/my_docker_app
# 啟動指令:在背景中啟動 compose
# 注意:我們不再使用 -d 參數,因為 systemd 會處理背景化
ExecStart=/usr/local/bin/docker-compose up
# 停止指令
ExecStop=/usr/local/bin/docker-compose down
# 讓 systemd 自動重啟我們的服務
Restart=always
RestartSec=10s
[Install]
WantedBy=multi-user.target
注意:docker-compose
的路徑可能是 /usr/bin/docker-compose
或 /usr/local/bin/docker-compose
,請用 which docker-compose
確認。
這樣做的好處是什麼?
- 開機自啟:執行
sudo systemctl enable my-docker-compose-app.service
,整個應用集群就會在伺服器啟動時自動運行。 - 終極守護:如果 Docker Engine 崩潰後重啟,
systemd
會因為依賴關係(Requires
和After
)自動地重新啟動my-docker-compose-app
服務。 - 統一管理介面:可以像管理普通系統服務一樣管理 Docker 應用,使用
systemctl start
,systemctl stop
,systemctl status
。 - 集中日誌:
docker-compose
的所有輸出(包含所有容器的 log)都會被journald
捕獲。只需執行sudo journalctl -u my-docker-compose-app.service -f
就可以查看應用集群的所有日誌,極其方便!
結論
-
要管理一個獨立的、非容器化的程式嗎?
👉 直接使用systemd
,如上一篇文章所示。 -
要打包一個含有多個組件、複雜依賴的應用程式,並確保它在任何地方都能一致地運行嗎?
👉 使用Docker
和Docker Compose
來進行封裝。 -
希望將這個打包好的 Docker 應用,在生產環境的 Linux 伺服器上進行可靠、穩定、可維護的部署嗎?
👉 將Docker Compose
作為一個整體,用systemd
來管理它。
systemd
和 Docker
它們各自填補了現代化應用部署體系中不可或缺的一環。systemd
是穩固的地基,Docker Compose
是精美的建築。只有當地基穩固時,上面的建築才能屹立不倒。