Docker swarm部署
本教程將介紹 Docker Engine Swarm 模式。先介紹 swarm 模式幾個關鍵的概念,然後通過動手實踐帶你體驗一下 swarm 模式。
幾個關鍵概念
Swarm
Docker Engline 中集成的集群管理和編排功能都是基於 SwarmKit 實現。參與到集群中的 Docker Engine 會進入 swarm 模式。比如初始化一個 swarm 或加入已有的 swarm。
一個 swarm 就是個一個 Docker Engine 集群,你可以在上面部署服務。Docker Engine CLI 提供了用於 swarm 管理的命令,比如添加或移除一個節點。同樣還提供了用於部署服務到 swarm 和管理服務編排的命令。
當 Docker Engine 運行在 swarm 模式時,你管理容器。當 Docker Engine 運行在 swarm 模式時,你編排服務。
節點
每個參與到 swarm 中的 Docker Engine 都稱之為一個節點。
將服務的定義提交到管理節點即可將應用部署到 swarm。然後管理節點將叫作任務的工作單元分發到工作節點。
為了維持 swarm 的目標狀態,管理節點還將承當編排和集群管理的功能。一般有多個管理節點,它們之間會選出一個領導來進行編排任務。
工作節點接收並執行來自管理節點分發的任務。默認情況下,管理節點也是工作節點,你可以把它配置成只當管理節點。代理通知管理節點已分配任務的當前狀態,以便管理節點維護所需的狀態。
服務和任務
服務定義了需要在工作節點上執行的任務。它是 swarm 系統的中心結構,也是用戶和 swarm 交互的主要根源。
服務包括要使用的容器鏡像,以及在容器中執行的指令。
對於復制服務,管理節點根據服務的規模和目標狀態將一定數量的任務副本分發到各節點上。
對於全局服務,每個節點上都將分發一個任務副本。
任務包含一個容器和需要在容器中執行的指令。它是 swarm 原子調度單位。管理節點根據服務規模中定義的副本數量將任務分配給工作節點。一旦某個任務被分配到某個節點,就不能再移動到其他節點。它只能在分配的節點上運行或者失敗。
負載均衡
swarm 管理節點使用 入口負載均衡 的方式暴露你想要讓外部訪問的服務。Swarm 管理節點可以自動將一個服務分配到某個 發布端口
外部組件,比如雲負載均衡器,可以通過集群中的任意節點訪問發布端口上的服務,不管當前節點上是否有服務對應的任務在運行,swarm 中的所有節點都會將進入連接路由到正在運行任務的實例上。
Swarm 模式有一個內置的 DNS 組件,它會自動給 swarm 中的每個服務分配一個 DNS 條目。Swarm 管理器使用internal load balancing 基於服務對應的 DNS 名稱在服務之間分發請求。
開始實踐
本教程將指導你完成以下任務:
在 Docker Engline swarm 模式下初始化一個集群
添加節點到 swarm
部署服務到 swarm
在一切就緒後管理 swarm
準備工作
在開始本教程之前,你需要準備一下幾樣東西:
三臺通過網絡連接的主機
每臺主機安裝 Docker Engine 1.12 或更新版本
充當管理節點的主機 IP
主機之間開放下面提到的端口
主機之間端口開放
主機之間的以下端口必須是開放。某些環境下,這些端口默認是允許的:
TCP 端口 2377 用於集群管理通信(管理節點)
TCP 和 UDP 端口 7946 用於節點間通信(所有節點)
TCP 和 UDP 端口 4789 用於 overlay 網絡流量(所有節點)
如果你的這些端口沒有打開,可以用iptables
命令打開它們:
iptables -A INPUT -p tcp --dport 2377 -j ACCEPT iptables -A INPUT -p tcp --dport 7946 -j ACCEPT iptables -A INPUT -p udp --dport 7946 -j ACCEPT iptables -A INPUT -p tcp --dport 4789 -j ACCEPT iptables -A INPUT -p udp --dport 4789 -j ACCEPT
192.168.33.160 swarm_manager
192.168.33.161 node1
192.168.33.162 node2
創建 swarm
創建一個 swarm
隨意選擇一個主機作為管理節點,在上面初始化一個 swarm:
[root@swarm_manager ~]# docker swarm init --advertise-addr 192.168.33.160 Swarm initialized: current node (7ik7wqhe5wcag8k5tp816c7ck) is now a manager. To add a worker to this swarm, run the following command: docker swarm join \ --token SWMTKN-1-0p0p5f96e1w4xblhw2eeookrv46spwf4yx7qmve2srxe9wec5g-ellbnyt4cwwvvdkssaj0cbtus 192.168.33.160:2377
--advertise-addr
標誌配置了管理節點的 IP 地址。如果你的機器只有一個 IP 地址,可以省略--adbertise-addr
選項,docker 會自動選擇正確的 IP。上輸出信息說明了怎樣加入新的工作節點。也說明了執行docker swarm join-token manager
可以查詢怎樣加入新的管理節點。
執行docker info
命令查看swarm
的當前狀態
[root@swarm_manager ~]# docker info ... Swarm: active NodeID: 7ik7wqhe5wcag8k5tp816c7ck Is Manager: true ClusterID: 2scd04fv8c9mua1jiaq6n0370 Managers: 1 Nodes: 1 ... 執行 docker node ls 命令查看節點信息 [root@swarm_manager ~]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS 9e21bk67ey1abzje69lmpvbe1 * swarm_manager Ready Active Leader
節點 id 後面的*
表示你當前連接到了該節點。
添加節點到 swarm
添加兩個工作節點到swarm
在第二臺主機上,執行前面創建 swarm
時 docker swarm init
輸出信息中命令創建工作節點並加入到 swarm
[root@node1 ~]# docker swarm join \ --token SWMTKN-1-0p0p5f96e1w4xblhw2eeookrv46spwf4yx7qmve2srxe9wec5g-ellbnyt4cwwvvdkssaj0cbtus 192.168.33.160:2377 This node joined a swarm as a worker.
輸出信息表示當前節點已是 swarm
中的一個工作節點了。如果你忘記了該命令,可以在管理節點上執行 docker swarm join-token worker
查詢怎麽加入。
[root@swarm_manager ~]# docker swarm join-token worker To add a worker to this swarm, run the following command: docker swarm join \ --token SWMTKN-1-3wi7tszkolocsbc7vopv1tfx2r2h1owtqegwevdqqdk3fj195u-ejpeq0afjvfmujlvzboux9zjs 192.168.33.160:2377
到第三臺主機上,繼續講第三臺主機加入到 swarm
中
[root@node1 ~]# docker swarm join \ --token SWMTKN-1-0p0p5f96e1w4xblhw2eeookrv46spwf4yx7qmve2srxe9wec5g-ellbnyt4cwwvvdkssaj0cbtus 192.168.59.128:2377 This node joined a swarm as a worker.
查看所有節點的狀態
在管理節點上
[root@swarm_manager ~]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
622ih8ji5t428lazjx233pvks node2 Ready Active
9e21bk67ey1abzje69lmpvbe1 * swarm_manager Ready Active Leader
f3wzagmtgsn8qyqzidxtw98d3 node1 Ready Active
輸出信息第二行 id 後面的*
表示當前連接到了該節點。HOSTNAME
欄輸出節點的 hostname。MANAGER
用於指示 swarm
中的管理節點,該欄值為 Leader
表示為管理節點,空值表示為工作節點。
部署一個服務到 swarm
創建服務
在管理節點上創建一個服務,每隔三秒輸出一個 “hello world”:
[root@swarm_manager ~]# docker service create --replicas 1 --name helloworld busybox:1.25.1-musl /bin/sh -c "while true; do echo hello world; sleep 3; done" 04a3iqg8zlhba84kpi2tatssf
docker service create
命令創建服務。--name
標誌將服務命名為helloworld
。--replicas
標誌指定了期望狀態為 1 個運行示例。參數
busybox:1.25.1-musl /bin/sh -c "while true; do echo hello world; sleep 3; done
將服務定義為使用鏡像busybox:1.25.1-musl
創建容器,並在裏面執行/bin/sh -c "while true; do echo hello world; sleep 3; done
。
查看服務列表
還是在管理節點上
[root@swarm_manager ~]# docker service ls ID NAME REPLICAS IMAGE COMMAND c3hvgwhyim4n helloworld 1/1 busybox:1.25.1-musl /bin/sh -c while true; do echo hello world; sleep 3; done
查看服務的詳細信息
查看服務的詳細信息
在管理節點上。
[root@swarm_manager ~]# docker service inspect --pretty helloworld ID: c3hvgwhyim4nllg1qqix7kli6 Name: helloworld Mode: Replicated Replicas: 1 Placement: UpdateConfig: Parallelism: 1 On failure: pause ContainerSpec: Image: busybox:1.25.1-musl Args: /bin/sh -c while true; do echo hello world; sleep 3; done Resources:
參數--pretty
表示以可讀性良好的格式輸出。如果想輸出詳細的 json 格式信息,去掉--pretty
參數即可。
查看哪個節點在運行該服務
還是在管理節點上:
[root@swarm_manager ~]# docker service ps helloworld ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR 556c2lpvr4489yrclo52cjlo5 helloworld.1 busybox:1.25.1-musl node2 Running Running 3 minutes ago
輸出信息表明,helloworld
服務的一個實例在 node2 節點上執行。這是因為,默認情況下管理節點是工作節點。
DESIRED STATE
和CURRENT STATE
表示服務的期望狀態和當前狀態,你可以對比它們,判斷服務是否想期望的那樣運行。這裏的Running
和Running 3 minutes ago
說明服務運行正常。
在執行任務的節點上使用docker ps
命令查看相關容器的詳細信息
[root@node2 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 964ddb3220b6 busybox:1.25.1-musl "/bin/sh -c ‘while tr" 5 minutes ago Up 5 minutes helloworld.1.556c2lpvr4489yrclo52cjlo5
伸縮服務
伸縮服務的任務數量
在管理節點上
[root@node2 ~]# docker service scale helloworld=5 helloworld scaled to 5 我們將服務的數量伸縮到5。
查看服務列表
在管理節點上:
[root@swarm_manager ~]# docker service ps helloworld ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR 556c2lpvr4489yrclo52cjlo5 helloworld.1 busybox:1.25.1-musl node2 Running Running 10 minutes ago e2tw7i9bkjb32jrr3sdztskwe helloworld.2 busybox:1.25.1-musl swarm_manager Running Running 24 seconds ago d5plppbjvtr1rany4tzb88czc helloworld.3 busybox:1.25.1-musl node2 Running Running 28 seconds ago a0hs8ik837jl7mlgeaowws1i3 helloworld.4 busybox:1.25.1-musl node1 Running Running 18 seconds ago bo27jnf7n59hqzl9m9jnpwbks helloworld.5 busybox:1.25.1-musl swarm_manager Running Running 24 seconds ago
在各節點上查看服務
首先是管理節點:
[root@swarm_manager ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 46aa83031ad7 busybox:1.25.1-musl "/bin/sh -c ‘while tr" About a minute ago Up About a minute helloworld.2.e2tw7i9bkjb32jrr3sdztskwe e1cb3bd1bfb0 busybox:1.25.1-musl "/bin/sh -c ‘while tr" About a minute ago Up About a minute helloworld.5.bo27jnf7n59hqzl9m9jnpwbks
再是工作節點1
[root@node1 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1c200722ace5 busybox:1.25.1-musl "/bin/sh -c ‘while tr" About a minute ago Up About a minute helloworld.4.a0hs8ik837jl7mlgeaowws1i3
再是工作節點2
[root@node2 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2dba702ccd68 busybox:1.25.1-musl "/bin/sh -c ‘while tr" About a minute ago Up About a minute helloworld.3.d5plppbjvtr1rany4tzb88czc 964ddb3220b6 busybox:1.25.1-musl "/bin/sh -c ‘while tr" 11 minutes ago Up 11 minutes helloworld.1.556c2lpvr4489yrclo52cjlo5
可以看到:管理節點上運行了兩個任務,工作節點1運行了兩個任務,工作節點2運行了1個任務。
刪除 swarm
上運行的服務
刪除
在管理節點上
[root@swarm_manager ~]# docker service rm helloworld
helloworld
確認
在管理節點上
[root@swarm_manager ~]# docker service ls
ID NAME REPLICAS IMAGE COMMAND
[root@swarm_manager ~]#
看不到任何服務了。
滾動更新
在這部分,我們將部署一個基於 Rddis 3.07 鏡像的服務。然後使用滾動更新將服務更新到使用 Redis 3.2.5 鏡像。
在swarm
中部署 Redis 3.0.7,並配置 10 秒更新延遲
[root@swarm_manager ~]# docker service create --replicas 3 --name redis --update-delay 10s redis:3.0.7-alpine 6vw26iief1y2nxmi6a01tzco6
我們在部署服務指定滾動更新策略。--update-delay
表示更新服務對應的任務或一組任務之間的時間間隔。時間間隔用數字和時間單位表示,m 表示分,h 表示時,所以 10m30s 表示 10 分 30 秒的延時。
默認情況下,調度器一次更新一個任務。你可以使用 --update-parallelism
標誌配置調度器每次同時更新的最大任務數量。
默認情況下,如果更新某個任務返回了RUNNING
狀態,調度器會轉去更新另一個任務,直到所有任務都更新完成。如果在更新某個任務的任意時刻返回了FAILED
,調度器暫停更新。我們可以在執行 docker service create
命令和 docker service update
命令時使用 --update-failure-action
標誌來覆蓋這種默認行為。
查看redis
服務
[root@swarm_manager ~]# docker service inspect --pretty redis ID: 6vw26iief1y2nxmi6a01tzco6 Name: redis Mode: Replicated Replicas: 3 Placement: UpdateConfig: Parallelism: 1 Delay: 10s On failure: pause ContainerSpec: Image: redis:3.0.7-alpine Resources:
更新redis
服務使用的容器鏡像
swarm
管理節點會根據UpdateConfig
策略來更新節點
[root@swarm_manager ~]# docker service update --image redis:3.2.5-alpine redis redis
調度器根據下面默認的策略來應用滾動更新:
停止第一個任務。
為停止的任務應用更新。
為更新的任務啟動容器。
如果更新任務時返回
RUNNING
,等待一個指定的延時後停止下一個任務。如果,在更新的任意時刻,某個任務返回
FAILED
,暫停更新。
查看新鏡像的狀態
[root@swarm_manager ~]# docker service update --image redis:3.2.5-alpine redis redis [root@swarm_manager ~]# docker service inspect --pretty redis ID: 6vw26iief1y2nxmi6a01tzco6 Name: redis Mode: Replicated Replicas: 3 Update status: State: updating Started: 46 seconds ago Message: update in progress Placement: UpdateConfig: Parallelism: 1 Delay: 10s On failure: pause ContainerSpec: Image: redis:3.2.5-alpine Resources:
可以看到 redis 服務的鏡像已經變成了redis:3.2.5-alpine
。不過狀態還在更新中。過一會再查看:
[root@swarm_manager ~]# docker service inspect --pretty redis ID: 6vw26iief1y2nxmi6a01tzco6 Name: redis Mode: Replicated Replicas: 3 Update status: State: completed Started: 2 minutes ago Completed: about a minute ago Message: update completed Placement: UpdateConfig: Parallelism: 1 Delay: 10s On failure: pause ContainerSpec: Image: redis:3.2.5-alpine Resources:
可以看到更新完成。
查看滾動更新後服務的狀態
[root@swarm_manager ~]# docker service ps redis ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR e69zhhxz66jmlm0h15gj89s2x redis.1 redis:3.2.5-alpine swarm_manager Running Running 2 minutes ago 63h5wy36474k01vmr5jppbbxs \_ redis.1 redis:3.0.7-alpine node1 Shutdown Shutdown 2 minutes ago 1h9e8m9v3rx3hgx5x2bn71kim redis.2 redis:3.2.5-alpine node2 Running Running 3 minutes ago 39jitd0mzztl0mpy6k6rppkx5 \_ redis.2 redis:3.0.7-alpine swarm_manager Shutdown Shutdown 3 minutes ago 8pwrkq6558fwp8oiiu0uq484h redis.3 redis:3.2.5-alpine node1 Running Running about a minute ago 6usd4p2mj7p597ilgs490ou7a \_ redis.3 redis:3.0.7-alpine node2 Shutdown Shutdown 2 minutes ago
可以看到有三個鏡像為redis:3.0.7-alpine
的任務狀態為Shutdown
,三個鏡像為redis:3.2.5-alpine
的任務狀態為Running
。說明滾動更新已完成。
再看看容器信息
[root@swarm_manager ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f7c5ebb8678b redis:3.2.5-alpine "docker-entrypoint.sh" 4 minutes ago Up 4 minutes 6379/tcp redis.1.e69zhhxz66jmlm0h15gj89s2x 524aadad84b8 redis:3.0.7-alpine "docker-entrypoint.sh" 7 minutes ago Exited (0) 5 minutes ago redis.2.39jitd0mzztl0mpy6k6rppkx5
可以看出更新後,swarm
並沒有刪除舊的容器。
下線某個節點
在前面的步驟中,所有的節點都處於運行狀態且可用性為ACTIVE
。swarm 管理器可以將任務分配給任何可用性為 ACTIVE
的節點,所以到目前為止,所有節點都可以接收任務。
有時候,比如到了計劃的維護時間,你需要將節點的可用性設為DRAIN
。可用性為DRAIN
的節點不會從 swarm 接收任何新任務。同時,管理器將停止運行在該節點上的任務,並在另外可用性為 ACTIVE
的節點上啟動相應的任務副本。
確認所有節點都是活躍可用的
[root@swarm_manager ~]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS 622ih8ji5t428lazjx233pvks node2 Ready Active 9e21bk67ey1abzje69lmpvbe1 * swarm_manager Ready Active Leader f3wzagmtgsn8qyqzidxtw98d3 node1 Ready Active
下線一個被分配了任務的節點
將分配了任務的工作節點node2
下線:
[root@swarm_manager ~]# docker node update --availability drain node2 node2
查看被下線節點的詳細信息
[root@swarm_manager ~]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS 622ih8ji5t428lazjx233pvks node2 Ready Drain 9e21bk67ey1abzje69lmpvbe1 * swarm_manager Ready Active Leader f3wzagmtgsn8qyqzidxtw98d3 node1 Ready Active [root@swarm_manager ~]# docker node inspect --pretty node2 ID: 622ih8ji5t428lazjx233pvks Hostname: node2 Joined at: 2017-10-25 06:45:04.369968305 +0000 utc Status: State: Ready Availability: Drain Platform: Operating System: linux Architecture: x86_64 Resources: CPUs: 1 Memory: 985.6 MiB Plugins: Network: bridge, host, null, overlay Volume: local Engine Version: 1.12.6
可以看到該節點的狀態為Ready
,但可用性為Drain
。
再次查看任務的分配情況
[root@swarm_manager ~]# docker service ps redis ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR e69zhhxz66jmlm0h15gj89s2x redis.1 redis:3.2.5-alpine swarm_manager Running Running 8 minutes ago 63h5wy36474k01vmr5jppbbxs \_ redis.1 redis:3.0.7-alpine node1 Shutdown Shutdown 9 minutes ago 6q046y1camb43b146kj2jaxe4 redis.2 redis:3.2.5-alpine node1 Running Running about a minute ago 1h9e8m9v3rx3hgx5x2bn71kim \_ redis.2 redis:3.2.5-alpine node2 Shutdown Shutdown about a minute ago 39jitd0mzztl0mpy6k6rppkx5 \_ redis.2 redis:3.0.7-alpine swarm_manager Shutdown Shutdown 9 minutes ago 8pwrkq6558fwp8oiiu0uq484h redis.3 redis:3.2.5-alpine node1 Running Running 8 minutes ago 6usd4p2mj7p597ilgs490ou7a \_ redis.3 redis:3.0.7-alpine node2 Shutdown Shutdown 8 minutes ago
再次將被下線的節點重置為活動狀態
[root@swarm_manager ~]# docker node update --availability active node2 node2
確認該節點的新狀態
[root@swarm_manager ~]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS 622ih8ji5t428lazjx233pvks node2 Ready Active 9e21bk67ey1abzje69lmpvbe1 * swarm_manager Ready Active Leader f3wzagmtgsn8qyqzidxtw98d3 node1 Ready Active
說明現在該節點又可以重新接收任務了。
再看看 node2
節點上是否被分配了任務:
[root@swarm_manager ~]# docker service ps -f desired-state=running redis ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR e69zhhxz66jmlm0h15gj89s2x redis.1 redis:3.2.5-alpine swarm_manager Running Running 10 minutes ago 6q046y1camb43b146kj2jaxe4 redis.2 redis:3.2.5-alpine node1 Running Running 2 minutes ago 8pwrkq6558fwp8oiiu0uq484h redis.3 redis:3.2.5-alpine node1 Running Running 9 minutes ago
desired-state
表示只列出處於活動狀態的任務。說明 node2雖然可用,但沒被分配任務。
一個可用性為Active
的節點在以下情況下可以接收到新任務:
當一個服務在伸縮規模時
滾動更新時
當你把其他某個節點的可用性設為
Drain
時當某個任務在另外某個
Active
節點上啟動失敗時
Docker swarm部署