Docker 不是唯一選擇?重新審視 Linux 上的 Web 應用部署策略

近年來,「部署 = Docker + 容器編排(Kubernetes、ECS 等)」已成為幾乎無可挑戰的常識。正因如此,將 Web 應用直接以 進程 + systemd 服務 的方式部署在 Linux 伺服器上,往往會被視為過時。

但實際情況是:

  • 單一 Web 應用
  • 小型團隊 / 簡單基礎設施
  • 本地部署或嚴格受規範的環境

在這些情境下,以 systemd 服務部署往往更簡單、更穩定、且更符合運維需求

本文將整理在 Linux 上使用 systemd.service 部署 Web 應用時,相較於 Docker 的優勢,以及 在哪些情況下 systemd 部署更有幫助


1. 簡要說明 systemd 與 Docker



先簡短說明兩者概念:

  • Docker
  • 將應用打包成映像(image)
  • 以容器(container)方式執行
  • 「整個環境封裝 → 在任何地方都能一致執行」是其強項

  • systemd

  • 現代 Linux 發行版的預設 init 系統
  • 在啟動時啟動服務(daemon),服務失效時自動重啟,並管理日誌
  • *.service 單元檔定義並管理進程

Docker 是「封裝應用環境的工具」,而 systemd 是「管理 Linux 進程的工具」。

兩者並非競爭關係,實際上常見的做法是:在 Docker 容器內部使用 systemd,或讓 systemd 管理 Docker 守護進程本身。

本文聚焦於「完全不使用 Docker,僅以 systemd 運行 Web 應用」的情境。


2. 使用 systemd.service 部署的優點

2-1. 簡化層級:減少一層

使用 Docker 時,運維棧會多出以下組件:

  • Docker 守護進程
  • 映像建置管道
  • 映像倉庫(Registry)
  • 容器執行時的權限/權限管理

相對地,systemd 部署只需:

  • 在 OS 上安裝所需的執行時(Python / Node / Java 等)
  • 部署應用程式碼
  • 以 systemd 服務註冊並執行

這是一個相對簡單的結構。

對於小型專案或內部服務:

  • 「映像建置 → 推送 → 拉取 → 重新部署」的流程往往成為負擔
  • 直接 SSH 進入伺服器,執行 git pull + systemctl restart 更快、更直觀

2-2. 與 Linux 的天然整合

systemd 是 Linux 的「門面」,與 OS 級別功能緊密結合:

  • 日誌journalctl -u myapp.service 可即時查看服務日誌
  • 自動啟動systemctl enable myapp.service 只需一次,即可在開機時自動啟動
  • 資源限制(cgroup)MemoryMaxCPUQuota 等選項可輕鬆控制資源
  • 相依性管理After=network.target / After=postgresql.service 等可控制啟動順序

若使用 Docker,則需要分別查看容器內外的日誌、資源、網路,並判斷問題是屬於容器還是宿主機。

對於僅運行一兩個 Web 服務,從運維/除錯角度看,systemd 直結結構更直觀

2-3. 低資源佔用

Docker 本身的開銷不大,但實際上往往伴隨:

  • 多個映像/層級佔用磁碟
  • 未使用的容器佔用空間
  • 容器日誌/卷管理

systemd 部署只需 OS + 執行時 + 應用程式碼,對於磁碟/記憶體緊張的環境更為輕量。

在多台小型 VM 或嵌入式/低規格伺服器上,systemd 會顯得更輕盈。

2-4. 網路結構更直觀

使用 Docker 時,需理解:

  • 容器內部 IP 與埠
  • 與宿主機的埠映射
  • 桥接網路 / 覆蓋網路

而 systemd 服務直接綁定宿主機的 IP/埠,防火牆規則亦以宿主機為基準,網路除錯更簡單

  • 埠是否開啟?
  • 防火牆是否阻擋?
  • 與同一伺服器其他服務是否衝突?

減少了一層容器網路的複雜度。

2-5. 某些環境無法使用 Docker

實際上這種情況比想像中常見:

  • 金融、公共、醫療等嚴格受規範的本地環境
  • 運維政策禁止容器執行
  • 網路受限,無法存取外部映像倉庫

在這些情況下,唯一可行的選擇往往是「OS + systemd」。掌握 systemd 後,即可實現:

  • 自動重啟
  • 日誌管理
  • 資源限制
  • 健康檢查(間接)

3. systemd.service 範例:Web 應用部署



以下以 gunicorn 服務 Django/Flask 為例。

3-1. 單元檔範例

/etc/systemd/system/myapp.service

[Unit]
Description=My Web Application (Gunicorn)
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/srv/myapp
EnvironmentFile=/etc/myapp.env
ExecStart=/usr/bin/gunicorn \
    --workers 4 \
    --bind 0.0.0.0:8000 \
    config.wsgi:application

# 失效時自動重啟
Restart=on-failure
RestartSec=5

# 資源限制範例(可選)
# MemoryMax=512M
# CPUQuota=50%

[Install]
WantedBy=multi-user.target

環境變數可放在 /etc/myapp.env

DJANGO_SETTINGS_MODULE=config.settings.prod
SECRET_KEY=super-secret-key
DATABASE_URL=postgres://...

後續指令非常簡單:

# 註冊服務並開機自動啟動
sudo systemctl enable myapp.service

# 啟動 / 停止 / 重啟
sudo systemctl start myapp.service
sudo systemctl restart myapp.service
sudo systemctl stop myapp.service

# 查看狀態 / 日誌
sudo systemctl status myapp.service
sudo journalctl -u myapp.service -f

對熟悉 Linux 伺服器的運維團隊而言,無需額外學習即可直接上手。


4. 何時更適合使用 systemd 而非 Docker?

總結來說,以下情境值得考慮 systemd 部署

4-1. 單一/小型服務,無需複雜編排

  • 只運行 1~2 個 Web 應用
  • 資料庫使用 RDS 等托管服務
  • 伺服器數量不多(1~5 台)

在此情況下,Docker + 編排的成本往往高於收益,systemd + 簡易部署腳本(Ansible、Fabric 等)即可滿足需求。

4-2. 運維團隊熟悉 Linux 服務

  • 現有系統大多以 systemd 為基礎
  • 運維人員已熟悉 systemctljournalctlrsysloglogrotate

在這種環境下,直接在現有運維棧上部署 Web 應用更高效。

4-3. 嚴格規範或 Docker 被限制

  • 金融、公共、國防、醫療等
  • 封閉網路/內部網路
  • 容器安全評估/認證繁瑣

Docker 的引入本身可能成為風險,使用 OS + systemd 是更安全、可驗證的做法。

4-4. 想減少宿主機與容器之間的隔離

  • 需要直接使用 straceperf/proc 進行調優
  • 想一次性觀察網路/檔系統/資源問題

此時,直接在宿主機上執行 Web 應用比在容器內部更方便。


5. 當然 Docker 仍有其適用場景

雖然已說明 systemd 的優勢,但 Docker 仍有明顯好處:

  • 以映像建置 → 在任何地方都能一致執行
  • 減少本地/測試/生產環境差異
  • 與 CI/CD 流程自然整合
  • 多服務(Web + worker + cron + DB 等)組合

若需要在多台伺服器或多個環境重複部署相同堆疊,或團隊內部環境差異大,Docker 可能是更佳選擇。

最終關鍵在於:

「我們的服務規模、團隊結構、基礎設施環境,哪一個工具能更簡單、更穩定、更易運維?」


image

6. 結語:工具不是重點,情境才是關鍵

在 Linux 上部署 Web 應用時,不是「一定要 Docker」也不是「Docker 就好」

  • 單一服務、簡單基礎設施、嚴格規範環境 → systemd.service 可能更實際
  • 多服務、不同環境、頻繁部署/擴容 → Docker 可能帶來更大價值

如果已經在使用 Linux 伺服器,值得思考:

  • 「這個服務真的需要 Docker 嗎?」
  • 「用 systemd 會不會更簡單?」

工具只是達成目標的手段,簡單與易運維才是長期最具生產力的關鍵。