在現代化的雲端架構中,確保服務的高可用性與可擴展性是系統設計的首要目標。Docker Swarm 作為 Docker 原生的容器編排工具,提供了簡潔而強大的叢集管理能力,讓開發團隊能夠輕鬆地將容器化應用部署到多節點環境中。當 Docker Swarm 與 AWS 的負載平衡服務結合時,更能發揮出強大的流量分配與故障容錯能力。本文將深入探討如何在 AWS 環境中建構具備負載平衡與高可用性的 Docker Swarm 架構,從基礎的叢集配置到進階的跨區域容錯移轉,提供完整的實務指引。
Docker Swarm 負載平衡機制解析
Docker Swarm 內建了兩種負載平衡機制,分別是 Ingress 負載平衡與內部負載平衡。理解這兩種機制的運作原理,是設計高可用性架構的基礎。
Ingress 負載平衡是 Docker Swarm 的核心功能之一,它會自動將外部流量分配到叢集中的所有節點。當您在 Swarm 中發布一個服務並指定端口時,Swarm 會在所有節點上開啟該端口,無論該節點是否實際運行服務的容器。當請求到達任何節點時,Swarm 的路由網格會自動將請求轉發到運行服務容器的節點。這種設計大幅簡化了負載平衡的配置,您只需要將流量導向叢集中的任何節點,Swarm 就會自動處理後續的路由。
內部負載平衡則用於服務之間的通訊。當一個服務需要呼叫另一個服務時,Swarm 會透過內建的 DNS 服務解析目標服務名稱,並自動在該服務的所有容器之間進行負載平衡。這種機制讓微服務架構的實現變得更加簡單,開發者只需要使用服務名稱進行通訊,無需關心實際的容器位置與數量。
然而,Docker Swarm 的內建負載平衡有其限制。它無法處理 SSL 終止、進階的健康檢查、或是根據請求內容進行路由等功能。在生產環境中,通常需要搭配外部負載平衡器來補充這些功能。AWS 的 Elastic Load Balancer 就是一個理想的選擇,它不僅提供了豐富的負載平衡功能,還能與 AWS 的其他服務無縫整合。
@startuml
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100
' Docker Swarm 負載平衡架構
rectangle "外部流量" as external
rectangle "AWS ELB" as elb
rectangle "Docker Swarm 叢集" as swarm {
rectangle "節點 1\n(Manager)" as node1 {
rectangle "容器 A" as c1
rectangle "容器 B" as c2
}
rectangle "節點 2\n(Worker)" as node2 {
rectangle "容器 A" as c3
rectangle "容器 C" as c4
}
rectangle "節點 3\n(Worker)" as node3 {
rectangle "容器 B" as c5
rectangle "容器 C" as c6
}
}
external --> elb
elb --> node1
elb --> node2
elb --> node3
note bottom of swarm
Ingress 負載平衡
自動路由到正確容器
end note
@endumlAWS 環境準備與 Swarm 叢集建立
在 AWS 上建立 Docker Swarm 叢集之前,需要進行適當的環境準備。這包括 VPC 配置、子網規劃、安全組設定,以及 EC2 執行個體的建立。為了實現高可用性,Swarm 叢集應該跨越多個可用區域部署。
首先,您需要確保 VPC 中至少有兩個位於不同可用區域的子網。這是配置 Elastic Load Balancer 的基本要求,也是實現跨可用區域高可用性的前提。每個子網應該有適當的路由表配置,確保能夠存取網際網路與其他 AWS 服務。
安全組的配置需要特別注意。除了基本的 SSH 存取之外,還需要開放 Docker Swarm 叢集通訊所需的端口,包括 TCP 2377 用於叢集管理、TCP 與 UDP 7946 用於節點間通訊、UDP 4789 用於 Overlay 網路。此外,還需要開放您的服務所使用的端口,以便外部流量能夠到達。
Docker for AWS 是一個簡化 Swarm 叢集部署的解決方案。它提供了 CloudFormation 模板,能夠自動建立包含所有必要元件的完整環境,包括 VPC、子網、安全組、EC2 執行個體,以及外部的 Elastic Load Balancer。使用 Docker for AWS 可以大幅縮短環境建置時間,讓您能夠專注於應用的部署與管理。
# 建立 SSH 金鑰對並設定權限
# 此金鑰將用於 SSH 登入 Swarm 管理節點
chmod 400 swarm-key.pem
# SSH 登入到 Swarm 管理節點
# 使用 docker 作為使用者名稱(Docker for AWS 的預設設定)
ssh -i "swarm-key.pem" docker@<manager-public-ip>
# 檢視 Swarm 叢集中的所有節點
# 此命令會列出節點 ID、主機名稱、狀態與角色
docker node ls
執行 docker node ls 命令後,您會看到類似以下的輸出,顯示叢集中所有節點的狀態:
# Docker Swarm 節點列表輸出範例
# ID:節點的唯一識別碼
# HOSTNAME:節點的主機名稱
# STATUS:節點狀態(Ready 表示正常運作)
# AVAILABILITY:節點可用性(Active 表示可接受任務)
# MANAGER STATUS:管理節點狀態(Leader 為主要管理節點)
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
abc123def456 * ip-172-31-10-1.ap-northeast-1.compute.internal Ready Active Leader
ghi789jkl012 ip-172-31-20-2.ap-northeast-1.compute.internal Ready Active Reachable
mno345pqr678 ip-172-31-30-3.ap-northeast-1.compute.internal Ready Active Reachable
stu901vwx234 ip-172-31-40-4.ap-northeast-1.compute.internal Ready Active
yza567bcd890 ip-172-31-50-5.ap-northeast-1.compute.internal Ready Active
Elastic Load Balancer 配置與整合
Elastic Load Balancer 是 AWS 提供的受管負載平衡服務,能夠自動將流量分配到多個 EC2 執行個體。在 Docker Swarm 架構中,ELB 扮演著外部流量入口的角色,將來自網際網路的請求分配到 Swarm 叢集的各個節點。
配置 ELB 時,需要設定監聽器來定義接收流量的端口與協定。對於一般的 Web 應用,通常會設定 HTTP 監聽器在端口 80,或是 HTTPS 監聽器在端口 443。監聽器會將接收到的流量轉發到後端執行個體的指定端口,這個端口應該與 Docker Swarm 服務發布的端口一致。
健康檢查是 ELB 的關鍵功能,它會定期檢查後端執行個體的狀態,並自動將流量從不健康的執行個體移除。配置健康檢查時,需要指定檢查的協定、端口與路徑。對於 Docker Swarm 服務,健康檢查應該指向服務發布的端口,並設定適當的檢查間隔與閾值。
跨區域負載平衡是另一個重要的設定。啟用此功能後,ELB 會將流量平均分配到所有可用區域的執行個體,而不是只在同一可用區域內分配。這能夠確保流量分配更加均勻,也提供了更好的容錯能力。
@startuml
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100
' ELB 配置流程
start
:建立負載平衡器;
note right
選擇類型:
Application/Network/Classic
end note
:配置監聽器;
note right
設定端口與協定
HTTP:80 或 HTTPS:443
end note
:選擇可用區域;
note right
至少選擇兩個
不同的可用區域
end note
:配置安全組;
note right
允許必要的
入站流量
end note
:配置健康檢查;
note right
協定、端口、路徑
間隔與閾值
end note
:註冊目標執行個體;
note right
將 Swarm 節點
加入目標群組
end note
:啟用跨區域負載平衡;
:測試負載平衡器;
stop
@enduml部署 Docker Swarm 服務
完成基礎架構配置後,即可開始部署 Docker Swarm 服務。Docker Swarm 使用宣告式的服務定義,您只需要指定期望的狀態,Swarm 就會自動維護該狀態。
建立服務時,需要指定映像檔名稱、服務名稱、發布端口與副本數量。發布端口定義了外部如何存取服務,格式為 主機端口:容器端口。副本數量則定義了要運行多少個相同的容器,Swarm 會自動將這些容器分散到不同的節點上。
# 建立 Docker Swarm 服務
# 此命令會部署一個簡單的 Hello World 網頁服務
docker service create \
--name hello-world \
--publish 8080:80 \
--replicas 2 \
tutum/hello-world
# 參數說明:
# --name hello-world:指定服務名稱為 hello-world
# --publish 8080:80:將主機的 8080 端口對應到容器的 80 端口
# 外部流量透過 8080 端口存取服務
# --replicas 2:指定運行 2 個服務副本
# Swarm 會將這 2 個容器分散到不同節點
# tutum/hello-world:使用的 Docker 映像檔名稱
服務建立後,可以使用 docker service ls 查看服務狀態,使用 docker service ps 查看各個任務的分配情況:
# 列出所有服務及其狀態
docker service ls
# 輸出範例:
# ID NAME MODE REPLICAS IMAGE
# abc123def456 hello-world replicated 2/2 tutum/hello-world:latest
# 查看服務的任務分配詳情
docker service ps hello-world
# 輸出範例:
# ID NAME IMAGE NODE DESIRED STATE CURRENT STATE
# xyz789uvw123 hello-world.1 tutum/hello-world:latest ip-172-31-20-2 Running Running 30 seconds ago
# qrs456tuv789 hello-world.2 tutum/hello-world:latest ip-172-31-40-4 Running Running 30 seconds ago
當需要處理更多流量時,可以輕鬆地擴展服務的副本數量。Swarm 會自動處理新容器的調度與網路配置,整個過程不需要停機:
# 將服務擴展到 10 個副本
# Swarm 會自動將新容器分散到各個節點
docker service scale hello-world=10
# 確認擴展結果
docker service ls
# 輸出範例:
# ID NAME MODE REPLICAS IMAGE
# abc123def456 hello-world replicated 10/10 tutum/hello-world:latest
擴展後,10 個服務任務會被分散到 Swarm 叢集的各個節點上。結合 ELB 的負載平衡功能,外部流量會被均勻地分配到這些容器,實現水平擴展的效果。
使用 Route 53 實現跨區域高可用性
雖然在單一 AWS 區域內使用 ELB 與多可用區域部署已經能夠提供相當程度的高可用性,但如果整個區域發生故障,服務仍然會中斷。為了實現更高等級的可用性,需要在多個 AWS 區域部署服務,並使用 Route 53 的 DNS 容錯移轉功能進行流量管理。
Route 53 是 AWS 的 DNS 服務,提供了多種路由策略,包括簡單路由、加權路由、延遲路由、地理位置路由與容錯移轉路由。對於高可用性架構,容錯移轉路由是最適合的選擇,它能夠在主要端點失效時自動將流量切換到備援端點。
實現跨區域高可用性的架構如下:首先在兩個不同的 AWS 區域分別建立 Docker Swarm 叢集,每個叢集都有自己的 ELB。然後在 Route 53 中建立託管區域,並設定兩個記錄集分別指向這兩個 ELB,一個作為主要記錄集,另一個作為次要記錄集。Route 53 會持續監控主要端點的健康狀態,當主要端點失效時,自動將 DNS 解析切換到次要端點。
@startuml
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100
' 跨區域高可用性架構
rectangle "使用者" as user
rectangle "Route 53" as route53 {
rectangle "主要記錄集" as primary
rectangle "次要記錄集" as secondary
}
rectangle "區域 A(東京)" as region_a {
rectangle "ELB A" as elb_a
rectangle "Swarm 叢集 A" as swarm_a
}
rectangle "區域 B(新加坡)" as region_b {
rectangle "ELB B" as elb_b
rectangle "Swarm 叢集 B" as swarm_b
}
user --> route53
primary --> elb_a : "正常時"
secondary --> elb_b : "容錯時"
elb_a --> swarm_a
elb_b --> swarm_b
note bottom of route53
DNS 容錯移轉
自動切換流量
end note
@enduml建立 Route 53 託管區域
首先需要在 Route 53 中建立託管區域。託管區域是 DNS 記錄的容器,您需要為您的網域名稱建立一個公共託管區域。
建立託管區域後,Route 53 會分配一組名稱伺服器。您需要到網域名稱註冊商的控制面板,將網域的名稱伺服器設定為 Route 53 分配的這組伺服器。這個步驟完成後,對您網域的 DNS 查詢就會由 Route 53 處理。
配置容錯移轉記錄集
在託管區域中建立兩個 A 記錄集,分別指向兩個區域的 ELB。第一個記錄集設定為主要容錯移轉記錄,第二個設定為次要容錯移轉記錄。
配置主要記錄集時,選擇「Alias」為 Yes,並將 Alias Target 指向第一個區域的 ELB DNS 名稱。路由策略選擇「Failover」,容錯移轉記錄類型選擇「Primary」。重要的是,將「Evaluate Target Health」設定為 Yes,這樣 Route 53 才會根據 ELB 的健康狀態進行容錯移轉。
配置次要記錄集的步驟類似,但容錯移轉記錄類型要選擇「Secondary」,Alias Target 指向第二個區域的 ELB。
測試容錯移轉功能
配置完成後,應該測試容錯移轉功能是否正常運作。首先確認在正常情況下,DNS 解析會指向主要記錄集的 ELB。然後模擬主要區域故障,例如刪除主要區域的 Swarm 叢集或 CloudFormation Stack。
刪除主要區域的資源後,Route 53 會偵測到主要端點的健康檢查失敗,並自動將 DNS 解析切換到次要記錄集。這個過程可能需要幾分鐘,取決於 DNS 的 TTL 設定。切換完成後,使用者存取您的網域名稱時,流量會被導向次要區域的 ELB,服務能夠繼續運作。
# 使用 dig 命令測試 DNS 解析
# 觀察 ANSWER SECTION 中的 IP 位址變化
dig yourdomain.com
# 或使用 nslookup
nslookup yourdomain.com
服務更新與滾動部署
Docker Swarm 提供了內建的滾動更新功能,讓您能夠在不中斷服務的情況下更新應用。當您更新服務的映像檔或配置時,Swarm 會逐步停止舊容器並啟動新容器,確保始終有足夠的容器在運行以處理請求。
# 更新服務的映像檔版本
# Swarm 會執行滾動更新,逐步替換容器
docker service update \
--image tutum/hello-world:v2 \
hello-world
# 配置更新策略
# --update-parallelism:同時更新的容器數量
# --update-delay:每批更新之間的等待時間
# --update-failure-action:更新失敗時的處理方式
docker service update \
--image tutum/hello-world:v2 \
--update-parallelism 2 \
--update-delay 10s \
--update-failure-action rollback \
hello-world
# 如果更新出現問題,可以回滾到前一個版本
docker service rollback hello-world
更新策略的配置對於生產環境非常重要。--update-parallelism 控制每次更新多少個容器,較小的數值能夠降低更新過程中的風險。--update-delay 設定每批更新之間的等待時間,讓您有機會觀察新版本是否正常運作。--update-failure-action 設定為 rollback 可以在更新失敗時自動回滾,避免服務中斷。
Docker Compose 與 Stack 部署
對於複雜的多服務應用,使用 Docker Compose 檔案來定義服務是更好的做法。Docker Swarm 支援使用 docker stack deploy 命令來部署 Compose 檔案中定義的所有服務。
# docker-compose.yml
# Docker Swarm Stack 配置範例
version: '3.8'
services:
# 前端網頁服務
web:
image: nginx:alpine
ports:
- "80:80"
deploy:
# 副本數量
replicas: 3
# 更新配置
update_config:
parallelism: 1
delay: 10s
failure_action: rollback
# 重啟策略
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
# 資源限制
resources:
limits:
cpus: '0.5'
memory: 256M
reservations:
cpus: '0.25'
memory: 128M
# 部署約束
placement:
constraints:
- node.role == worker
networks:
- frontend
# 健康檢查
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# 後端 API 服務
api:
image: myapp/api:latest
deploy:
replicas: 2
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure
networks:
- frontend
- backend
environment:
- DATABASE_URL=postgres://db:5432/myapp
depends_on:
- db
# 資料庫服務
db:
image: postgres:13
deploy:
replicas: 1
placement:
constraints:
- node.labels.db == true
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
environment:
- POSTGRES_PASSWORD_FILE=/run/secrets/db_password
secrets:
- db_password
# 網路定義
networks:
frontend:
driver: overlay
backend:
driver: overlay
# 內部網路,不對外暴露
internal: true
# 持久化儲存
volumes:
db-data:
driver: local
# 機密資料
secrets:
db_password:
external: true
使用 Stack 部署這個應用:
# 建立機密資料
echo "mysecretpassword" | docker secret create db_password -
# 部署 Stack
# -c 指定 Compose 檔案
# myapp 是 Stack 名稱
docker stack deploy -c docker-compose.yml myapp
# 查看 Stack 中的所有服務
docker stack services myapp
# 查看特定服務的任務
docker service ps myapp_web
# 查看服務日誌
docker service logs myapp_web
# 移除 Stack
docker stack rm myapp
監控與日誌管理
在生產環境中運行 Docker Swarm 叢集時,監控與日誌管理是不可或缺的。良好的監控能夠幫助您及時發現問題,而集中式的日誌管理則能夠簡化故障排除的過程。
Docker Swarm 本身提供了基本的監控資訊,可以使用 docker stats 查看容器的資源使用情況,使用 docker service logs 查看服務日誌。然而,對於生產環境,通常需要更完善的監控解決方案。
Prometheus 與 Grafana 是廣泛使用的監控組合。Prometheus 負責收集與儲存指標資料,Grafana 則提供視覺化的儀表板。您可以在 Swarm 叢集中部署 cAdvisor 來收集容器指標,然後由 Prometheus 抓取這些指標。
對於日誌管理,ELK Stack(Elasticsearch、Logstash、Kibana)或 EFK Stack(Elasticsearch、Fluentd、Kibana)是常見的選擇。您可以配置 Docker 的 logging driver 將容器日誌發送到集中式的日誌系統,方便進行搜尋與分析。
# 使用 docker stats 監控容器資源使用
docker stats
# 查看服務日誌
# --follow:持續輸出新日誌
# --tail:顯示最後 N 行
docker service logs --follow --tail 100 myapp_web
# 查看節點資訊
docker node inspect <node-id>
# 查看服務詳細資訊
docker service inspect myapp_web
安全性最佳實踐
在生產環境中運行 Docker Swarm 時,安全性是重要的考量。以下是一些關鍵的安全性最佳實踐。
首先,確保 Swarm 叢集的通訊是加密的。Docker Swarm 預設會使用 TLS 加密節點之間的通訊,您應該確認這個功能是啟用的。同時,定期輪換 Swarm 的加密金鑰也是良好的安全實踐。
使用 Docker Secrets 來管理敏感資料,例如資料庫密碼、API 金鑰等。Secrets 會被加密儲存在 Swarm 的 Raft 日誌中,只有被授權的服務才能存取。避免將敏感資料放在環境變數或映像檔中。
限制容器的權限是另一個重要的安全措施。避免使用 privileged 模式運行容器,限制容器的 capabilities,使用 read-only 檔案系統,並設定適當的資源限制。這些措施能夠降低容器被攻破後的影響範圍。
網路隔離也很重要。使用不同的 overlay 網路來隔離不同的服務群組,並將不需要對外暴露的網路設定為 internal。這樣即使某個服務被攻破,攻擊者也難以存取其他服務。
# 輪換 Swarm 加密金鑰
docker swarm ca --rotate
# 建立與使用 Secret
echo "mysecretvalue" | docker secret create my_secret -
# 在服務中使用 Secret
docker service create \
--name myservice \
--secret my_secret \
myimage
# Secret 會被掛載到容器的 /run/secrets/ 目錄
故障排除技巧
在運營 Docker Swarm 叢集時,難免會遇到各種問題。掌握故障排除的技巧能夠幫助您快速定位並解決問題。
當服務無法正常運行時,首先檢查服務的狀態與任務分配。使用 docker service ps 查看各個任務的狀態,如果任務處於 Rejected 或 Failed 狀態,可以查看錯誤訊息了解原因。常見的問題包括映像檔無法拉取、資源不足、健康檢查失敗等。
如果節點出現問題,可以使用 docker node inspect 查看節點的詳細資訊。檢查節點的狀態是否為 Ready,可用性是否為 Active。如果節點處於 Down 狀態,需要檢查網路連線與 Docker daemon 的運行狀態。
網路問題是另一個常見的故障來源。確認 overlay 網路是否正確建立,服務是否加入了正確的網路。可以使用 docker network inspect 查看網路的詳細資訊,包括連接到該網路的容器清單。
# 查看服務的任務狀態與錯誤訊息
docker service ps --no-trunc myservice
# 查看失敗任務的詳細錯誤
docker inspect <task-id>
# 檢查節點狀態
docker node ls
docker node inspect <node-id>
# 檢查網路狀態
docker network ls
docker network inspect mynetwork
# 進入運行中的容器進行除錯
docker exec -it <container-id> sh
# 查看 Docker daemon 日誌
journalctl -u docker.service
總結與展望
Docker Swarm 結合 AWS 的負載平衡與 DNS 服務,能夠建構出高可用性、可擴展的容器化應用架構。透過本文的介紹,我們學習了 Swarm 的負載平衡機制、ELB 的配置與整合、服務的部署與擴展,以及使用 Route 53 實現跨區域容錯移轉。
在實務應用中,建議從小規模的環境開始,逐步熟悉各項功能與操作。建立完善的監控與告警機制,確保能夠及時發現並處理問題。定期測試容錯移轉功能,確認在故障發生時能夠正常切換。同時,持續關注 Docker 與 AWS 的更新,運用新功能來優化架構。
隨著 Kubernetes 的普及,Docker Swarm 在市場上的份額有所下降。然而,對於規模較小、追求簡潔的團隊來說,Docker Swarm 仍然是一個值得考慮的選擇。它的學習曲線較平緩,與 Docker 生態系統的整合更加緊密,對於已經熟悉 Docker 的團隊來說能夠快速上手。無論選擇哪種編排工具,理解負載平衡與高可用性的基本原理都是非常重要的,這些知識能夠幫助您設計出更加穩健的系統架構。