上一篇文章《Docker Swarm 集群管理利器核心概念掃盲》中我們把 Swarm 重要的概念性知識給大家講解了一波,理論完事就該實戰(zhàn)了,這篇文章帶大家從零開始,搭建 Docker Swarm 集群環(huán)境,并通過 Swarm 實現(xiàn)服務的彈性部署,滾動更新服務及回滾服務等功能。
集群搭建
環(huán)境準備

- 五臺安裝了 Docker 的 CentOS 機器,版本為:
CentOS 7.8.2003 - Docker Engine 1.12+(最低要求 1.12,本文使用 19.03.12)
- 防火墻開啟以下端口或者關(guān)閉防火墻:
- TCP 端口 2377,用于集群管理通信;
- TCP 和 UDP 端口 7946,用于節(jié)點之間通信;
- UDP 端口 4789,用于覆蓋網(wǎng)絡。
機器分布
| 角色 | IP | HOSTNAME | Docker 版本 |
|---|---|---|---|
| Manager | 192.168.10.101 | manager1 | 19.03.12 |
| Manager | 192.168.10.102 | manager2 | 19.03.12 |
| Manager | 192.168.10.103 | manager3 | 19.03.12 |
| Worker | 192.168.10.10 | worker1 | 19.03.12 |
| Worker | 192.168.10.11 | worker2 | 19.03.12 |
- 可以通過
hostname 主機名修改機器的主機名(立即生效,重啟后失效); - 或者
hostnamectl set-hostname 主機名修改機器的主機名(立即生效,重啟也生效); - 或者
vi /etc/hosts編輯 hosts 文件,如下所示, 給 127.0.0.1 添加主機名(重啟生效)。
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 manager1
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
創(chuàng)建集群
在任意節(jié)點下通過 docker swarm init 命令創(chuàng)建一個新的 Swarm 集群并加入,且該節(jié)點會默認成為 Manager 節(jié)點。根據(jù)我們預先定義的角色,在 101 ~ 103 的任意一臺機器上運行該命令即可。
通常,第一個加入集群的管理節(jié)點將成為 Leader,后來加入的管理節(jié)點都是 Reachable。當前的 Leader 如果掛掉,所有的 Reachable 將重新選舉一個新的 Leader。
[root@localhost ~]# docker swarm init --advertise-addr 192.168.10.101
Swarm initialized: current node (clumstpieg0qzzxt1caeazg8g) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-5ob7jlej85qsygxubqypjuftiwruvew8e2cr4u3iuo4thxyrhg-3hbf2u3i1iagurdprl3n3yra1 192.168.10.101:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

加入集群
Docker 中內(nèi)置的集群模式自帶了公鑰基礎設施(PKI)系統(tǒng),使得安全部署容器變得簡單。集群中的節(jié)點使用傳輸層安全協(xié)議(TLS)對集群中其他節(jié)點的通信進行身份驗證、授權(quán)和加密。
默認情況下,通過 docker swarm init 命令創(chuàng)建一個新的 Swarm 集群時,Manager 節(jié)點會生成新的根證書頒發(fā)機構(gòu)(CA)和密鑰對,用于保護與加入群集的其他節(jié)點之間的通信安全。
Manager 節(jié)點會生成兩個令牌,供其他節(jié)點加入集群時使用:一個 Worker 令牌,一個 Manager 令牌。每個令牌都包括根 CA 證書的摘要和隨機生成的密鑰。當節(jié)點加入群集時,加入的節(jié)點使用摘要來驗證來自遠程管理節(jié)點的根 CA 證書。遠程管理節(jié)點使用密鑰來確保加入的節(jié)點是批準的節(jié)點。

Manager
若要向該集群添加 Manager 節(jié)點,管理節(jié)點先運行 docker swarm join-token manager 命令查看管理節(jié)點的令牌信息。
docker swarm join-token manager


然后在其他節(jié)點上運行 docker swarm join 并攜帶令牌參數(shù)加入 Swarm 集群,該節(jié)點角色為 Manager。


Worker
通過創(chuàng)建集群時返回的結(jié)果可以得知,要向這個集群添加一個 Worker 節(jié)點,運行下圖中的命令即可?;蛘吖芾砉?jié)點先運行 docker swarm join-token worker 命令查看工作節(jié)點的令牌信息。

然后在其他節(jié)點上運行 docker swarm join 并攜帶令牌參數(shù)加入 Swarm 集群,該節(jié)點角色為 Worker。


查看集群信息
在任意 Manager 節(jié)點中運行 docker info 可以查看當前集群的信息。

查看集群節(jié)點
在任意 Manager 節(jié)點中運行 docker node ls 可以查看當前集群節(jié)點信息。
docker node ls

*代表當前節(jié)點,現(xiàn)在的環(huán)境為 3 個管理節(jié)點構(gòu)成 1 主 2 從,以及 2 個工作節(jié)點。
節(jié)點 MANAGER STATUS 說明:表示節(jié)點是屬于 Manager 還是 Worker,沒有值則屬于 Worker 節(jié)點。
-
Leader:該節(jié)點是管理節(jié)點中的主節(jié)點,負責該集群的集群管理和編排決策; -
Reachable:該節(jié)點是管理節(jié)點中的從節(jié)點,如果 Leader 節(jié)點不可用,該節(jié)點有資格被選為新的 Leader; -
Unavailable:該管理節(jié)點已不能與其他管理節(jié)點通信。如果管理節(jié)點不可用,應該將新的管理節(jié)點加入群集,或者將工作節(jié)點升級為管理節(jié)點。
節(jié)點 AVAILABILITY 說明:表示調(diào)度程序是否可以將任務分配給該節(jié)點。
-
Active:調(diào)度程序可以將任務分配給該節(jié)點; -
Pause:調(diào)度程序不會將新任務分配給該節(jié)點,但現(xiàn)有任務仍可以運行; -
Drain:調(diào)度程序不會將新任務分配給該節(jié)點,并且會關(guān)閉該節(jié)點所有現(xiàn)有任務,并將它們調(diào)度在可用的節(jié)點上。
刪除節(jié)點
Manager
刪除節(jié)點之前需要先將該節(jié)點的 AVAILABILITY 改為 Drain。其目的是為了將該節(jié)點的服務遷移到其他可用節(jié)點上,確保服務正常。最好檢查一下容器遷移情況,確保這一步已經(jīng)處理完成再繼續(xù)往下。
docker node update --availability drain 節(jié)點名稱|節(jié)點ID
然后,將該 Manager 節(jié)點進行降級處理,降級為 Worker 節(jié)點。
docker node demote 節(jié)點名稱|節(jié)點ID
然后,在已經(jīng)降級為 Worker 的節(jié)點中運行以下命令,離開集群。
docker swarm leave
最后,在管理節(jié)點中對剛才離開的節(jié)點進行刪除。
docker node rm 節(jié)點名稱|節(jié)點ID
Worker
刪除節(jié)點之前需要先將該節(jié)點的 AVAILABILITY 改為 Drain。其目的是為了將該節(jié)點的服務遷移到其他可用節(jié)點上,確保服務正常。最好檢查一下容器遷移情況,確保這一步已經(jīng)處理完成再繼續(xù)往下。
docker node update --availability drain 節(jié)點名稱|節(jié)點ID
然后,在準備刪除的 Worker 節(jié)點中運行以下命令,離開集群。
docker swarm leave
最后,在管理節(jié)點中對剛才離開的節(jié)點進行刪除。
docker node rm 節(jié)點名稱|節(jié)點ID
服務部署
注意:跟集群管理有關(guān)的任何操作,都是在 Manager 節(jié)點上操作的。
創(chuàng)建服務
下面這個案例,使用 nginx 鏡像創(chuàng)建了一個名為 mynginx 的服務,該服務會被隨機指派給一個工作節(jié)點運行。
docker service create --replicas 1 --name mynginx -p 80:80 nginx

-
docker service create:創(chuàng)建服務; -
--replicas:指定一個服務有幾個實例運行; -
--name:服務名稱。
查看服務
可以通過 docker service ls 查看運行的服務。
[root@manager1 ~]# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
hepx06k5ik5n mynginx replicated 1/1 nginx:latest *:80->80/tcp
可以通過 docker service inspect 服務名稱|服務ID 查看服務的詳細信息。
[root@manager1 ~]# docker service inspect mynginx
[
{
"ID": "k0dbjg1zzy3l3g71kdwa56ect",
"Version": {
"Index": 127
},
"CreatedAt": "2020-09-16T10:05:55.627974095Z",
"UpdatedAt": "2020-09-16T10:05:55.629507771Z",
"Spec": {
"Name": "mynginx",
"Labels": {},
"TaskTemplate": {
"ContainerSpec": {
"Image": "nginx:latest@sha256:c628b67d21744fce822d22fdcc0389f6bd763daac23a6b77147d0712ea7102d0",
"Init": false,
"StopGracePeriod": 10000000000,
"DNSConfig": {},
"Isolation": "default"
},
"Resources": {
"Limits": {},
"Reservations": {}
},
"RestartPolicy": {
"Condition": "any",
"Delay": 5000000000,
"MaxAttempts": 0
},
"Placement": {
"Platforms": [
{
"Architecture": "amd64",
"OS": "linux"
},
{
"OS": "linux"
},
{
"OS": "linux"
},
{
"Architecture": "arm64",
"OS": "linux"
},
{
"Architecture": "386",
"OS": "linux"
},
{
"Architecture": "mips64le",
"OS": "linux"
},
{
"Architecture": "ppc64le",
"OS": "linux"
},
{
"Architecture": "s390x",
"OS": "linux"
}
]
},
"ForceUpdate": 0,
"Runtime": "container"
},
"Mode": {
"Replicated": {
"Replicas": 1
}
},
"UpdateConfig": {
"Parallelism": 1,
"FailureAction": "pause",
"Monitor": 5000000000,
"MaxFailureRatio": 0,
"Order": "stop-first"
},
"RollbackConfig": {
"Parallelism": 1,
"FailureAction": "pause",
"Monitor": 5000000000,
"MaxFailureRatio": 0,
"Order": "stop-first"
},
"EndpointSpec": {
"Mode": "vip",
"Ports": [
{
"Protocol": "tcp",
"TargetPort": 80,
"PublishedPort": 80,
"PublishMode": "ingress"
}
]
}
},
"Endpoint": {
"Spec": {
"Mode": "vip",
"Ports": [
{
"Protocol": "tcp",
"TargetPort": 80,
"PublishedPort": 80,
"PublishMode": "ingress"
}
]
},
"Ports": [
{
"Protocol": "tcp",
"TargetPort": 80,
"PublishedPort": 80,
"PublishMode": "ingress"
}
],
"VirtualIPs": [
{
"NetworkID": "st2xiy7pjzap093wz4w4u6nbs",
"Addr": "10.0.0.15/24"
}
]
}
}
]
可以通過 docker service ps 服務名稱|服務ID 查看服務運行在哪些節(jié)點上。

在對應的任務節(jié)點上運行 docker ps 可以查看該服務對應容器的相關(guān)信息。

調(diào)用服務
接下來我們測試一下服務是否能被正常訪問,并且該集群下任意節(jié)點的 IP 地址都要能訪問到該服務才行。
測試結(jié)果:5 臺機器均可正常訪問到該服務。

彈性服務
將 service 部署到集群以后,可以通過命令彈性擴縮容 service 中的容器數(shù)量。在 service 中運行的容器被稱為 task(任務)。
通過 docker service scale 服務名稱|服務ID=n 可以將 service 運行的任務擴縮容為 n 個。
通過 docker service update --replicas n 服務名稱|服務ID 也可以達到擴縮容的效果。
將 mynginx service 運行的任務擴展為 5 個:
[root@manager1 ~]# docker service scale mynginx=5
mynginx scaled to 5
overall progress: 5 out of 5 tasks
1/5: running [==================================================>]
2/5: running [==================================================>]
3/5: running [==================================================>]
4/5: running [==================================================>]
5/5: running [==================================================>]
verify: Service converged
通過 docker service ps 服務名稱|服務ID 查看服務運行在哪些節(jié)點上。

我們再來一波縮容的操作,命令如下:
[root@manager1 ~]# docker service update --replicas 3 mynginx
mynginx
overall progress: 3 out of 3 tasks
1/3: running [==================================================>]
2/3: running [==================================================>]
3/3: running [==================================================>]
verify: Service converged
通過 docker service ps 服務名稱|服務ID 查看服務運行在哪些節(jié)點上。

在 Swarm 集群模式下真正意義實現(xiàn)了所謂的彈性服務,動態(tài)擴縮容一行命令搞定,簡單、便捷、強大。
刪除服務
通過 docker service rm 服務名稱|服務ID 即可刪除服務。
[root@manager1 ~]# docker service rm mynginx
mynginx
[root@manager1 ~]# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
滾動更新及回滾
以下案例將演示 Redis 版本如何滾動升級至更高版本再回滾至上一次的操作。
首先,創(chuàng)建 5 個 Redis 服務副本,版本為 5,詳細命令如下:
# 創(chuàng)建 5 個副本,每次更新 2 個,更新間隔 10s,20% 任務失敗繼續(xù)執(zhí)行,超出 20% 執(zhí)行回滾,每次回滾 2 個
docker service create --replicas 5 --name redis \
--update-delay 10s \
--update-parallelism 2 \
--update-failure-action continue \
--rollback-monitor 20s \
--rollback-parallelism 2 \
--rollback-max-failure-ratio 0.2 \
redis:5
-
--update-delay:定義滾動更新的時間間隔; -
--update-parallelism:定義并行更新的副本數(shù)量,默認為 1; -
--update-failure-action:定義容器啟動失敗之后所執(zhí)行的動作; -
--rollback-monitor:定義回滾的監(jiān)控時間; -
--rollback-parallelism:定義并行回滾的副本數(shù)量; -
--rollback-max-failure-ratio:任務失敗回滾比率,超過該比率執(zhí)行回滾操作,0.2 表示 20%。
然后通過以下命令實現(xiàn)服務的滾動更新。
docker service update --image redis:6 redis

回滾服務,只能回滾到上一次操作的狀態(tài),并不能連續(xù)回滾到指定操作。
docker service update --rollback redis

常用命令
docker swarm
| 命令 | 說明 |
|---|---|
| docker swarm init | 初始化集群 |
| docker swarm join-token worker | 查看工作節(jié)點的 token |
| docker swarm join-token manager | 查看管理節(jié)點的 token |
| docker swarm join | 加入集群 |
docker node
| 命令 | 說明 |
|---|---|
| docker node ls | 查看集群所有節(jié)點 |
| docker node ps | 查看當前節(jié)點所有任務 |
| docker node rm 節(jié)點名稱|節(jié)點ID | 刪除節(jié)點(-f強制刪除) |
| docker node inspect 節(jié)點名稱|節(jié)點ID | 查看節(jié)點詳情 |
| docker node demote 節(jié)點名稱|節(jié)點ID | 節(jié)點降級,由管理節(jié)點降級為工作節(jié)點 |
| docker node promote 節(jié)點名稱|節(jié)點ID | 節(jié)點升級,由工作節(jié)點升級為管理節(jié)點 |
| docker node update 節(jié)點名稱|節(jié)點ID | 更新節(jié)點 |
docker service
| 命令 | 說明 |
|---|---|
| docker service create | 創(chuàng)建服務 |
| docker service ls | 查看所有服務 |
| docker service inspect 服務名稱|服務ID | 查看服務詳情 |
| docker service logs 服務名稱|服務ID | 查看服務日志 |
| docker service rm 服務名稱|服務ID | 刪除服務(-f強制刪除) |
| docker service scale 服務名稱|服務ID=n | 設置服務數(shù)量 |
| docker service update 服務名稱|服務ID | 更新服務 |
參考資料
- https://docs.docker.com/engine/swarm/swarm-tutorial/
- https://docs.docker.com/engine/swarm/swarm-mode/
- https://docs.docker.com/engine/swarm/how-swarm-mode-works/pki/
- https://docs.docker.com/engine/swarm/join-nodes/
- https://docs.docker.com/engine/swarm/swarm-tutorial/rolling-update/
本文采用 知識共享「署名-非商業(yè)性使用-禁止演繹 4.0 國際」許可協(xié)議。
大家可以通過 分類 查看更多關(guān)于 Docker 的文章。
?? 您的點贊和轉(zhuǎn)發(fā)是對我最大的支持。
?? 關(guān)注公眾號 哈嘍沃德先生「文檔 + 視頻」每篇文章都配有專門視頻講解,學習更輕松噢 ~