Docker Swarm 叢集編排

當你的容器應用程式需要跨越多台伺服器部署,並要求具備自動修復 (Self-healing)、水平擴展 (Scaling)、負載均衡 (Load Balancing) 與滾動更新 (Rolling Updates) 等能力時,你就需要叢集編排 (Orchestration) 工具。

雖然 Kubernetes (K8s) 是目前的主流,但對於中小型專案或追求簡單運維的團隊來說,Docker 內建的 Swarm Mode 是一個極佳的選擇,它簡單易用且與 Docker 指令高度整合。

為什麼選擇 Docker Swarm?

Docker Swarm 是 Docker 官方提供的叢集管理工具。它的最大優勢在於:開箱即用。只要你安裝了 Docker,就已經具備了 Swarm,無需額外安裝複雜的組件。

核心優勢:

  • 極簡安裝:一條指令即可初始化叢集。
  • 宣告式狀態 (Declarative Service Model):你只需定義理想狀態(例如:維持 5 個副本),Swarm 會自動確保實際運行狀態與之相符。
  • 內建負載均衡:自動處理內部與外部網路流量派送。
  • 安全性:預設啟用 TLS 相互認證,節點間通訊皆經過加密。

Swarm 核心架構

Swarm 叢集由多個 Nodes (節點) 組成,每個節點都是一個 Docker 主機。

節點角色

  • Manager Nodes
    • 管理叢集狀態、調度任務並維護集群一致性。
    • 使用 Raft 共識演算法 來同步狀態。為了維持高可用性,建議部署奇數個 (1, 3, 5) Manager 節點。
  • Worker Nodes
    • 單純接收 Manager 分派的任務並執行容器。
    • Manager 節點預設也具備執行任務的能力(可設定為僅限管理)。

服務與任務 (Service & Task)

  • Service (服務):這是你在 Swarm 中操作的最小單位。你定義「我要一個 Nginx 服務,副本數為 3」。
  • Task (任務):正在節點上執行的單個容器實例。Service 是 Blueprint,Task 是具體的實例。

實戰:建立與管理叢集

初始化叢集 (Manager)

在預計作為管理者的機器執行:

docker swarm init --advertise-addr <MANAGER_IP>

執行後會得到兩行關鍵指令:一行用於加入新的 Manager,另一行用於加入 Worker。

加入工作節點 (Worker)

在其他伺服器上貼上剛產生的 docker swarm join 指令:

docker swarm join --token <TOKEN_STR> <MANAGER_IP>:2377

查看與管理節點

Manager 上執行:

# 查看所有節點
docker node ls

# 查看特定節點詳細資訊
docker node inspect <NODE_ID>

節點維護與可用性

你可以手動控制節點的調度狀態:

  • active:正常狀態,可以接受新任務。
  • pause:暫停狀態,現有任務繼續執行,但不接受新任務。
  • drain:排空狀態,現有任務會被遷移到其他節點,並不接受新任務(常用於系統維護)。
# 將節點改為維護模式
docker node update --availability drain <NODE_ID>

# 恢復節點
docker node update --availability active <NODE_ID>

離開叢集 (Leave)

當節點不再需要參與叢集時:

# 在 Worker 節點執行
docker swarm leave

# 在 Manager 節點執行 (若要強制解散或離開)
docker swarm leave --force

部署與管理 Service

在 Swarm 中,我們使用 docker service 系列指令來管理個別服務。

建立服務

# 建立一個名為 web-service 的服務,啟動 3 個副本,對外開放 80 port
docker service create --name web-service --replicas 3 -p 80:80 nginx:latest

服務模式:Replicated vs Global

  • Replicated (預設):根據指定的副本數在各節點分佈。
  • Global:在叢集中的「每一個」合格節點上都運行一個容器(常用於監控或日誌收集工具)。
# 建立一個 global 模式的服務
docker service create --name monitor --mode global prometheus-exporter

服務維護指令

當服務上線後,你經常需要進行動態調整:

# 水平擴展 (Scaling)
docker service scale web-service=5

# 更新服務 (例如更換映像檔版本)
docker service update --image nginx:1.25 web-service

# 查看服務日誌
docker service logs -f web-service

# 刪除服務
docker service rm web-service

Swarm 網路與路由 (Routing Mesh)

Swarm 使用 Overlay Network 來實現跨主機的容器通訊。

Overlay 網路

建立一個可以跨越多台伺服器的網路:

docker network create --driver overlay my-net

將服務加入此網路後,容器間可以透過 Service Name 互相訪問,Swarm 會自動處理 VIP (Virtual IP) 的解析與負載均衡。

Ingress Routing Mesh

這是 Swarm 最神奇的功能:你只要訪問叢集中任何一個節點的對外埠號(例如 80),流量都會被自動導向後端真正有運行該容器的節點。這意味著你不需要手動維護容器與 IP 的對應關係。

安全管理:Secrets 與 Configs

在生產環境中,你不應該把密碼或配置寫死在映像檔或環境變數中。

Docker Secrets

用於存取機密資訊(如資料庫密碼、SSL 證書)。Secret 會加密儲存在 Manager 節點中,並僅在任務啟動時掛載給特定的容器。

如何使用 Secrets?

  1. 掛載路徑:Secrets 預設會被掛載到容器內的 /run/secrets/<secret_name> 檔案中(這是一個內存文件系統,不會寫入硬碟)。
  2. 存取內容:應用程式可以直接讀取該檔案來取得密碼。
  3. 環境變數模式:許多官方映像檔(如 MySQL、Postgres)支援 _FILE 結尾的環境變數,讓你指定 Secret 檔案的路徑。
# 建立一個名為 db_password 的 secret
echo "my_secure_password" | docker secret create db_password -

# 在服務中使用該 secret,並告知 MySQL 從該路徑讀取密碼
docker service create \
  --name db \
  --secret db_password \
  -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db_password \
  mysql

Docker Configs

類似於 Secrets,但用於非加密的設定檔(如 nginx.confprometheus.yml),讓你可以動態更新配置而無需重新建置映像檔。

如何使用 Configs?

  1. 掛載路徑:預設也是掛載到容器根目錄下的某處,但通常我們會自訂掛載位置。
  2. 動態更新:當你更新 Config 時,Swarm 會重新啟動關聯的 Service 以套用新設定。
# 1. 建立一個 config (從本地 nginx.conf 檔案)
docker config create my_nginx_config ./nginx.conf

# 2. 建立服務,並將 config 掛載到 Nginx 預設讀取的地方
docker service create \
  --name web \
  --config source=my_nginx_config,target=/etc/nginx/nginx.conf \
  -p 80:80 \
  nginx

如何達成 Zero Downtime (零停機) 更新

在生產環境中,更新服務時不希望造成斷線。Docker Swarm 具備強大的滾動更新 (Rolling Update) 機制,其核心在於 update_config 的設定。

滾動更新的關鍵參數

要達成零停機更新,你必須在 deploy 段落配置以下參數:

  • parallelism:每次同時更新的容器數量。建議設為 1 或較小比例,確保其他容器能繼續服務。
  • order (關鍵)
    • stop-first (預設):先停掉舊容器,再啟動新容器。這會導致短暫的停機。
    • start-first:先啟動新容器,等到新容器健康後,才停掉舊容器。這是達成 Zero Downtime 的關鍵。
  • delay:每組容器更新之間的等待時間,讓新容器有時間暖機。
  • monitor:新容器啟動後,Swarm 會監控一段時間,確保容器沒有立即閃退。

Health Checks 的重要性

Swarm 判斷容器是否「準備好」進入 Service 負載均衡器,是依據 Health Check (健康檢查)

如果你的應用程式啟動很慢(例如 Java 或大型框架),但你沒有設定 Health Check,Swarm 可能在應用程式還沒真正啟動完成前就以為它好了,並把流量導過去,這就會造成錯誤。

務必在 Dockerfiledocker-compose.yaml 中定義 healthcheck,Swarm 才能精準控制更新節奏。

大規模部署:Docker Stack

當應用程式包含多個服務時(例如:Frontend + API + DB),我們會使用 docker-compose.yaml 並透過 Docker Stack 進行一次性部署。

範例:docker-compose.yaml

在 Swarm 模式下,Compose 檔案支援 deploy 段落來定義叢集行為:

version: '3.8'
services:
  webapp:
    image: my-app:v1
    networks:
      - app-net
    deploy:
      replicas: 5
      update_config:
        parallelism: 1
        delay: 10s
        order: start-first # 先啟動新容器再停止舊容器
        monitor: 20s # 監控新容器健康狀況 20 秒
      restart_policy:
        condition: on-failure
      placement:
        constraints:
          - 'node.role == worker'
    healthcheck:
      test: ['CMD', 'curl', '-f', 'http://localhost:8080/health']
      interval: 30s
      timeout: 10s
      retries: 3
    ports:
      - '80:8080'

networks:
  app-net:
    driver: overlay

管理指令

  • 部署或更新 Stackdocker stack deploy -c docker-compose.yaml my-stack
  • 查看所有 Stacksdocker stack ls
  • 查看 Stack 中的服務docker stack services my-stack
  • 查看 Stack 的任務詳情docker stack ps my-stack
  • 移除整個 Stackdocker stack rm my-stack

Swarm vs. Kubernetes (K8s)

特性Docker SwarmKubernetes (K8s)
安裝與學習極低,與 Docker 完全一致高,有大量的專有名詞與組件
功能性基本編排功能紮實,適合 90% 場景極其強大,適合極大規模微服務
生態系統較小巨大 (CNCF 生態圈)
跨雲支援需手動管理各雲端節點各大雲端皆有 Managed Service (EKS, GKE, AKS)

總結

Docker Swarm 是進入容器編排世界的最佳起點。它對於中小型企業或需要快速部署的場景來說,提供了極高的投資報酬率。如果你已經熟悉 Docker Compose,轉移到 Docker Swarm 只需幾分鐘的時間,卻能讓你的系統具備真正的運維彈性。