Docker Swarm 提供簡化的容器協調流程,讓開發者能輕鬆管理和擴充套件應用程式。本文從建立 Swarm 叢集開始,逐步引導讀者瞭解節點加入、服務佈署和擴充套件的步驟,並透過指令操作示範如何驗證叢集狀態和服務分佈。此外,文章也涵蓋了 Swarm 的容錯機制,模擬節點故障和服務遷移,展示其在應對突發狀況時的可靠性。最後,文章探討了 Docker Swarm 的網路設定,包含虛擬 IP、容器 IP 和主機 IP 的關係,並提供實用的 sysctl 引數調整建議,以最佳化網路效能和解決潛在的 ARP 快取溢位問題,讓讀者能更有效地管理和擴充套件 Docker Swarm 叢集。
Docker Swarm 叢集管理與擴充套件實務
Docker Swarm 是 Docker 的原生叢集管理工具,旨在簡化容器化應用的佈署、管理和擴充套件。本文將探討 Docker Swarm 的核心功能,包括節點管理、服務擴充套件和容錯機制,並透過實際操作案例進行詳細解析。
建立 Docker Swarm 叢集
首先,我們需要建立一個 Docker Swarm 叢集。這個過程涉及初始化 Swarm 模式並加入工作節點。
root@swarm3:~# docker swarm join \
--token SWMTKN-1-0445f42yyhu8z4k3lgxsbnusnd8ws83urf56t02rv1vdh1zqlj-09swsjxdz80bfxbc1aed6mack \
10.55.0.238:2377
This node joined a swarm as a manager.
內容解密:
docker swarm join命令用於將當前節點加入現有的 Swarm 叢集。--token引數提供加入叢集所需的驗證令牌,確保節點安全地加入叢集。- 指定 Swarm 管理節點的 IP 地址和埠(
10.55.0.238:2377)。
驗證叢整合員狀態
加入節點後,使用 docker node ls 命令檢查叢集狀態。
root@swarm3:~# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
4i0lko1qdwqp4x1aqwn6o7obh swarm1 Ready Active Reachable
9gyk5t22ngndbwtjof80hpg54 swarm2 Ready Active Leader
b9dyyc08ehtnl62z7e3ll0ih3 * swarm3 Ready Active Reachable
內容解密:
docker node ls列出叢集中所有節點的詳細資訊。STATUS欄顯示節點的目前狀態(例如:Ready表示正常)。MANAGER STATUS欄指示節點是否為管理節點及其角色(例如:Leader或Reachable)。
佈署可擴充套件服務
接下來,我們將建立一個可擴充套件的服務並觀察其在叢集中的分佈。
root@swarm1:~# docker service create --replicas 5 --name helloworld alpine ping google.com
5gmrllue1sgdwl1yd5ubl16md
root@swarm1:~# docker service scale helloworld=10
helloworld scaled to 10
內容解密:
docker service create用於建立一個新的服務,並指定初始的副本數量(--replicas 5)。--name helloworld為服務命名,方便後續管理。docker service scale用於動態調整服務的副本數量,以滿足負載需求。
觀察服務分佈
使用 docker service ps 命令檢視服務在各節點上的分佈情況。
root@swarm1:~# docker service ps helloworld
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
2hb76h8m7oop helloworld.1 alpine swarm1 Running Running 1 min
5lxefcjclasn helloworld.2 alpine swarm3 Running Running 1 min
95cab7hte5xp helloworld.3 alpine swarm2 Running Running 1 min
...
內容解密:
docker service ps列出指定服務的容器例項及其執行狀態。NODE欄顯示每個容器執行的節點名稱。DESIRED STATE和CURRENT STATE欄分別表示預期狀態和目前狀態,用於監控服務健康狀況。
節點容錯移轉測試
模擬節點故障,觀察 Swarm 的容錯機制。
root@swarm2:~# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
4i0lko1qdwqp4x1aqwn6o7obh swarm1 Down Active Unreachable
9gyk5t22ngndbwtjof80hpg54 * swarm2 Ready Active Leader
b9dyyc08ehtnl62z7e3ll0ih3 swarm3 Ready Active Reachable
內容解密:
- 當
swarm1節點關閉後,其狀態變為Down和Unreachable。 - Swarm 自動在其他可用節點上重新啟動受影響的容器例項,以維持服務的預期狀態。
從特定節點遷移服務
將特定節點設為 drain 狀態,以遷移其上的容器。
root@swarm2:~# docker node update --availability drain swarm3
swarm3
內容解密:
docker node update --availability drain將指定節點設為drain狀態,禁止新容器在其上啟動並逐漸遷移現有容器。- Swarm 自動將該節點上的容器遷移到其他可用節點。
調整服務規模
動態調整服務規模以滿足需求變化。
root@swarm2:~# docker service scale helloworld=20
helloworld scaled to 20
內容解密:
- 將服務擴充套件至 20 個副本,以處理更高的負載需求。
- Swarm 自動在叢集節點間分佈這些副本。
管理節點高用性考量
Swarm 管理節點的高用性設計至關重要,需確保多數決原則。
當佈署 Swarm 管理節點時,需要多數節點達成共識以解決故障。因此,建議使用奇數個管理節點(N > 2),這樣 N 個管理節點的叢集可以容忍 ((N-1)/2) 個節點故障。例如,3 個管理節點可容忍 1 個故障,5 個管理節點可容忍 2 個故障。
使用 Docker Swarm 擴充套件服務
現在我們已經設定了 Docker Swarm,接下來將使用它來協調佈署和滾動升級我們的服務。要佈署的應用程式映像應該在所有 Swarm 節點上可用,可以透過自定義登入檔或 Docker Hub 取得。為了本章的目的,我們已經將 gotwitter 映像推播到 Docker Hub。因此,該映像可以透過 titpetric/gotwitter 取得,在生產環境中,它將從您的 Docker 登入檔中取得。
磁碟空間
根據 titpetric/gotwitter 在 Docker Hub 上的頁面,該映像在撰寫本文時大約為 5MB。請注意,這是壓縮後的尺寸,實際大小將透過命令 docker images | grep gotwitter 報告:
# docker images | grep gotwitter
titpetric/gotwitter latest 65d327973482 8 secs ago 12MB
為什麼磁碟大小很重要?正如您現在所瞭解的,映像的大小從幾 MB 到幾 GB 不等。如果您想在硬體上擴充套件服務,您需要提前規劃,並提供必要的磁碟空間以相應地擴充套件服務。我們建立的 Swarm 節點組態了 160GB 的磁碟空間。為了簡化起見,我們計劃使用大約 120GB 用於容器——對於我們的應用程式容器,這將使我們能夠在一個節點上執行大約 10,000 個容器。如果容器大小約為 1GB,我們只能執行大約 120 個。當然,在我們的例子中,磁碟不是限制因素,但 RAM 使用量可能是。
RAM 使用量
我們為每個 Swarm 管理節點組態了 8GB 的 RAM。檢查 gotwitter 應用程式,我們可以看到它使用的記憶體小於 10MB。當您的應用程式執行一段時間後,這個數字可能會更高,因此在組態容器時請記住這一點。
# docker stats gotwitter
CONTAINER MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O
gotwitter 8.559 MiB / 1.886 GiB 0.44% 648 B / 648 B 8.262 MB / 0 B
我在叢集外啟動了容器。預設情況下,如果容器沒有設定任何記憶體限制,它可能會佔用系統上可用的全部記憶體(在本例中約為 2GB)。
內容解密:
此段落說明瞭檢查 gotwitter 容器記憶體使用情況的方法,並提醒讀者注意容器的記憶體限制。透過 docker stats 命令,可以即時監控容器的資源使用情況,包括記憶體使用量。
簡單估算
一個簡單的粗略估計表明,我們可以在單個 Swarm 節點上執行大約 800 個容器,根據上述記憶體消耗。由於我們有 3 個節點,估計我們可以執行大約 2000 個容器。通常,這種估計並不準確,因為我們不知道執行容器之外所需的記憶體消耗,也不知道應用程式在執行一段時間後會有什麼樣的記憶體使用情況。
建立多主機網路
此時,值得一提的是,我們在書開頭建立的橋接網路僅限於單個主機。為了使容器在 Docker Swarm 中的主機之間可被發現,我們需要在其中一個管理節點(在我們的例子中,所有節點都是管理節點,因為我們沒有工作節點)上建立一個疊加網路。
# docker network create \
--driver overlay \
--subnet 10.0.0.0/20 \
--attachable \
party-swarm
內容解密:
此命令建立了一個名為 party-swarm 的疊加網路,使用 --driver overlay 指定網路驅動程式為疊加網路,--subnet 指定了子網範圍,--attachable 允許非 Swarm 服務的容器連線到該網路。
使用多主機網路
當建立服務時,我們現在可以使用 --network party-swarm。Docker Swarm 將把網路擴充套件到容器執行的所有管理節點。使用 --attachable 開關建立 Swarm 網路時,也允許非受控容器(即 docker run)連線到網路。
# docker run --rm --net=party-swarm alpine ifconfig eth0 | grep "inet addr"
內容解密:
此命令在 party-swarm 網路中啟動一個 Alpine 容器,並顯示其網路組態,過濾出包含 “inet addr” 的行,以檢視其 IP 地址。
建立 Redis 服務
作為測試,我們將在 party-swarm 網路中建立一個 Redis 服務。
root@swarm1:~# docker service create --replicas 1 --network party-swarm --hostname redis --name redis -p 6379:6379 redis:3.2-alpine
內容解密:
此命令建立了一個名為 redis 的服務,使用 redis:3.2-alpine 映象,將主機的 6379 埠對映到容器的 6379 埠,並指定了 --network party-swarm 以連線到我們建立的疊加網路。
連線 Redis 服務
現在,我們可以檢查在同一主機上執行的 Redis 容器。你應該透過執行 docker ps 取得容器的名稱。
root@swarm1:~# docker exec -it redis.1.kcd5v3xxiwro830tn8oab6a4d ifconfig eth2 | grep "inet addr"
內容解密:
此命令進入正在執行的 Redis 容器,並執行 ifconfig eth2 命令以檢視其網路介面的 IP 地址。
虛擬 IP 和服務連線
我們的 Redis 例項正在 10.0.0.3 上執行。透過在不同主機上建立容器,我們可以驗證我們在網路中獲得了一個額外的 IP,並且我們與 Redis 服務有連線。
root@swarm3:~# docker run --rm --net=party-swarm alpine ifconfig eth0 | grep "inet addr"
root@swarm3:~# docker run -it --rm --net=party-swarm alpine sh -c "echo quit | nc redis 6379"
內容解密:
這些命令展示瞭如何在不同的 Swarm 節點上執行容器並連線到 Redis 服務,驗證了跨主機的網路連線性。
Docker Swarm 中的網路設定與效能調校
在 Docker Swarm 環境中,當我們執行多個服務時,瞭解其網路架構與相關設定是非常重要的。本篇文章將探討 Docker Swarm 的網路設定,並介紹如何透過 sysctl 調整系統引數以最佳化效能。
Docker Swarm 網路架構
首先,讓我們檢視 Redis 服務的網路設定:
root@swarm3:~# docker service inspect --format='{{json .Endpoint.VirtualIPs}}' redis
[{"NetworkID":"kc8yy8tc62qrmq4xhqu4g74yl","Addr":"10.255.0.5/16"},{"NetworkID":"q3l72085za9s20fwxfix83i7k","Addr":"10.0.0.2/20"}]
從輸出結果中,我們可以看到 Redis 服務連線到兩個網路。因為我們在執行服務時使用了 -p 6379:6379,Docker 自動將容器加入到「ingress」網路中,以便將主機的流量轉發到服務的虛擬 IP(VIP)。
網路架構解析
- 虛擬 IP(VIP):
10.0.0.2是 Redis 服務的虛擬 IP,用於路由到個別容器。 - 容器 IP:
10.0.0.3是某個 Redis 容器的 IP 地址。 - 主機 IP:
10.0.0.1是執行 Docker 的主機 IP(例如 swarm1、swarm2 或 swarm3)。
系統引數調校
當我們在單一主機上執行大量容器(如 1000 個)時,可能會遇到一些限制。為了最佳化系統效能,我們可以使用 sysctl 命令來調整核心引數。
為什麼需要調校?
預設的核心引數通常適用於筆記型電腦,而不是用於執行數千個程式的伺服器。當我們首次嘗試執行 1000 個容器的服務時,遇到了 Docker Swarm 無回應和偶爾的連線中斷問題。透過 dmesg 命令,我們發現瞭如下錯誤訊息:
neighbour: arp_cache: neighbor table overflow!
進一步的研究表明,這是由於 ARP 快取溢位所導致。為瞭解決這個問題,我們需要調整 sysctl 的設定。
實用 sysctl 設定
以下是一些有用的 sysctl 設定,用於最佳化 Docker Swarm 的效能:
# 調整 ARP 快取設定
sysctl -w net.ipv4.neigh.default.gc_thresh1=8096
sysctl -w net.ipv4.neigh.default.gc_thresh2=8096
sysctl -w net.ipv4.neigh.default.gc_thresh3=8096
# 其他有用的 sysctl 設定
net.ipv4.ip_local_port_range="1024 65000"
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_fin_timeout=15
net.core.somaxconn=4096
net.core.netdev_max_backlog=4096
net.core.rmem_max=16777216
net.core.wmem_max=16777216
net.ipv4.tcp_max_syn_backlog=20480
net.ipv4.tcp_max_tw_buckets=400000
net.ipv4.tcp_no_metrics_save=1
net.ipv4.tcp_rmem="4096 87380 16777216"
net.ipv4.tcp_syn_retries=2
net.ipv4.tcp_synack_retries=2
net.ipv4.tcp_wmem="4096 65536 16777216"
net.netfilter.nf_conntrack_max=262144
net.ipv4.netfilter.ip_conntrack_generic_timeout=120
net.netfilter.nf_conntrack_tcp_timeout_established=86400
設定解說
這些 sysctl 設定主要涉及連線數量、連線埠使用、連線回收速度等引數的調整。正確的設定可以提升 Docker Swarm 在高負載下的穩定性和效能。