第六課:docker-swarm
簡介
Swarm是Docker官方提供的一款叢集管理工具,其主要作用是把若干臺Docker主機抽象為一個整體,並且通過一個入口統一管理這些Docker主機上的各種Docker資源。Swarm和Kubernetes比較類似,但是更加輕,具有的功能也較kubernetes更少一些。
swarm叢集提供給使用者管理叢集內所有容器的操作介面與使用一臺Docker主機基本相同。
swarm的一些基本概念
1. 節點
執行 Docker 的主機可以主動初始化一個 Swarm 叢集或者加入一個已存在的 Swarm 叢集,這樣這個執行 Docker 的主機就成為一個 Swarm 叢集的節點 (node) 。
節點分為管理 (manager) 節點和工作 (worker) 節點。
管理節點用於 Swarm 叢集的管理,docker swarm 命令基本只能在管理節點執行(節點退出叢集命令 docker swarm leave 可以在工作節點執行)。一個 Swarm 叢集可以有多個管理節點,但只有一個管理節點可以成為 leader,leader 通過 raft 協議實現。
工作節點是任務執行節點,管理節點將服務 (service) 下發至工作節點執行。管理節點預設也作為工作節點。你也可以通過配置讓服務只執行在管理節點。
叢集中管理節點和工作節點的關係,來自docker官網。
2. 服務和任務 service and task
- 任務(task)是swarm中的最小排程單元,目前來說就是一個單一的容器。
- 服務(service)是指一組任務的合集,服務定義了任務的屬性。服務有兩種模式:
- replicated services 按照一定規則在各個工作節點上執行指定個數的任務。
- global services 每個工作節點上執行一個任務。
兩種模式通過docker service create --mode 引數指定。
容器,任務,服務的關係:來自docker官網
swarm排程策略
swarm在scheduler節點(lead 節點)執行容器的時候,會根據指定的策略來結算最適合執行容器的節點,目前支援的策略有:spread,binpack,random。
- random
隨機算則一個Node來執行容器,一般用作除錯,spread和binpack策略會根據各個節點的可用的CPU,RAM以及正在執行的容器的數量來計算應該執行容器的節點。 - spread
在同等條件下,spread策略會選擇執行容器最少的Node來執行新的容器。使用spread策略會容器會均衡的分佈在叢集中的各個節點上執行,一旦一個節點掛掉只會損失少部分的容器。 - binpack
binpack策略最大化的避免容器碎片化,就是說binpack策略儘可能的把還未使用的節點留給需要更大空間的容器執行,儘可能的把容器執行在一個節點上。
swarm命令說明
叢集管理
命令 | 說明 |
---|---|
docker swarm: | 叢集管理 |
init | 初始化叢集 |
join | 將節點加入叢集 |
join-token | 管理加入令牌 |
leave | 從叢集中刪除某個節點,強制刪除加引數--force |
update | 更新叢集 |
unlock | 解鎖叢集 |
節點管理
命令 | 說明 |
---|---|
docker node | 節點管理 |
demote | 將及群眾一個或多個節點降級 |
inspect | 顯示一個或多個節點的詳細資訊 |
ls | 列出叢集中的節點 |
promote | 將一個或多個幾點提升為管理節點 |
rm | 從叢集中刪除停止的節點,--force強制刪除 |
ps | 列出一個或多個節點上執行的任務 |
update | 更新節點 |
服務管理
命令 | 說明 |
---|---|
docker service | 服務管理 |
create | 建立一個新的服務 |
inspect | 列出一個或多個服務的詳細資訊 |
ps | 列出一個或多個服務中的任務資訊 |
ls | 列出服務 |
rm | 刪除一個或多個服務 |
scale | 擴充套件一個或多個服務 |
update | 更新服務 |
安裝部署swarm叢集服務
主機名 | IP地址 | 作用 |
---|---|---|
docker-man143 | 192.168.68.143 | manager |
docker-node140 | 192.168.68.140 | worker |
docker-node141 | 192.168.68.141 | worker |
docker-node142 | 192.168.68.142 | worker |
1.修改主機名,配置host檔案
#在manager,node1,node2上分別執行:
cat >>/etc/hosts<<EOF
192.168.68.143 docker-man143
192.168.68.140 docker-node140
192.168.68.141 docker-node141
EOF
2.開放埠
Open protocols and ports between the hosts
The following ports must be available. On some systems, these ports are open by default.
TCP port 2377 for cluster management communications
TCP and UDP port 7946 for communication among nodes
UDP port 4789 for overlay network traffic
3.安裝docker
$ sudo yum install -y yum-utils
$ sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
$ sudo yum install docker-ce docker-ce-cli containerd.io
systemctl start docker
systemctl enable docker
4. 管理節點初始化
$ docker swram init --advertise-addr 192.168.68.143
Swarm initialized: current node (41yp9s0thoorpwxognm7ut1vw) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-0vk6rqv84fy0sxhm24lu7oucar42xa76abtwa77jaebwp63ddp-4ql5xm0vtk1izaqvzfqutx177 192.168.68.143:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
5. 將node節點加入到叢集
$ docker swarm join --token SWMTKN-1-0vk6rqv84fy0sxhm24lu7oucar42xa76abtwa77jaebwp63ddp-4ql5xm0vtk1izaqvzfqutx177 192.168.68.143:2377
6. 管理節點檢視叢集中節點狀態
[root@docker-man143 ~]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
41yp9s0thoorpwxognm7ut1vw * docker-man143 Ready Active Leader 19.03.12
r53tu2gd5fvhsxh08nwvdrazs docker-node140 Ready Active 19.03.12
so81lopbcdtnecvp7lls8ur9p docker-node141 Ready Active 19.03.12
7.swarm的web管理
使用portainer管理swarm可以使用官方提供的部署方式
portainer官網:https://www.portainer.io/
agent部署文件:https://portainer.readthedocs.io/en/stable/agent.html
7.1 建立overlay網路
docker network create --driver overlay --attachable portainer_agent_network
7.2 在叢集中建立agent全域性服務
$ docker service create \
--name portainer_agent \
--network portainer_agent_network \
--mode global \
--constraint 'node.platform.os == linux' \
--mount type=bind,src=//var/run/docker.sock,dst=/var/run/docker.sock \
--mount type=bind,src=//var/lib/docker/volumes,dst=/var/lib/docker/volumes \
portainer/agent
採用全域性方式在新加入node以後會自動部署agent到新的node上,不需要再手動建立agent容器。
7.3 建立portainer服務
$ docker service create \
--name portainer \
--network portainer_agent_network \
--publish 9000:9000 \
--publish 8000:8000 \
--replicas=1 \
--constraint 'node.role == manager' \
portainer/portainer -H "tcp://tasks.portainer_agent:9001" --tlsskipverify
瀏覽器訪問http://192.168.68.143:9000,首次登陸並設定admin密碼後進入頁面管理
docker swarm部署服務
我們以部署nginx服務為例:
步驟:
- 部署服務前建立用於叢集內不同主機之間容器通訊的網路
docker network create -d overlay nginx_net
[root@docker-man143 ~]# docker network ls | grep nginx
maiqmdcgpki4 nginx_net overlay swarm
- 建立nginx服務,副本數為3
docker service create --replicas 3 --network nginx_net --name my_nginx -p 80:80 nginx
# --replicas 指定副本數量
[root@docker-man143 ~]# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
sg0gweqid90s my_nginx replicated 3/3 nginx:latest *:80->80/tcp
- 線上擴容服務
可以通過`docker service scale service_name=N(副本數量)擴縮容服務。
[root@docker-man143 ~]# docker service scale my_nginx=4
my_nginx scaled to 4
overall progress: 4 out of 4 tasks
1/4: running [==================================================>]
2/4: running [==================================================>]
3/4: running [==================================================>]
4/4: running [==================================================>]
verify: Service converged
[root@docker-man143 ~]# docker service ps my_nginx
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
ow24ahxijyju my_nginx.1 nginx:latest docker-man143 Running Running 9 days ago
zlb5jqqjgznt my_nginx.2 nginx:latest docker-node141 Running Running 9 days ago
i4valcpimsj6 my_nginx.3 nginx:latest docker-node142 Running Running 42 seconds ago
s0lr0emnwfl5 my_nginx.4 nginx:latest docker-node140 Running Running 9 days ago
- 節點故障
我們通過關閉node142的docker程序模擬節點故障,觀察在節點出現故障以後叢集會出現哪些操作
在node142上檢視docker容器
[root@docker-node142 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0ff44aa14367 nginx:latest "/docker-entrypoint.…" 3 minutes ago Up 3 minutes 80/tcp my_nginx.3.i4valcpimsj68jq387gq0a89t
03d79bdce38e portainer/agent:latest "./agent" 19 minutes ago Up 19 minutes portainer_agent.ijb0eg2a06fwv2ap9s9b4ob0c.m7co4p8ilnxw94eb9uha22ann
關閉docker程序
[root@docker-node142 ~]# systemctl stop docker
檢視叢集node狀態,可以看到docker-node142狀態為Down。
[root@docker-man143 ~]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
41yp9s0thoorpwxognm7ut1vw * docker-man143 Ready Active Leader 19.03.12
r53tu2gd5fvhsxh08nwvdrazs docker-node140 Ready Active 19.03.12
so81lopbcdtnecvp7lls8ur9p docker-node141 Ready Active 19.03.12
ijb0eg2a06fwv2ap9s9b4ob0c docker-node142 Down Active 19.03.12
檢視nginx服務狀態
原來執行在node142上的my_nginx.3狀態變為shutdown,同時在node140上重新啟動一個my_nginx.3的副本。
[root@docker-man143 ~]# docker service ps my_nginx
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
ow24ahxijyju my_nginx.1 nginx:latest docker-man143 Running Running 9 days ago
zlb5jqqjgznt my_nginx.2 nginx:latest docker-node141 Running Running 9 days ago
j11badxpt18i my_nginx.3 nginx:latest docker-node140 Running Running 43 seconds ago
i4valcpimsj6 \_ my_nginx.3 nginx:latest docker-node142 Shutdown Running 22 minutes ago
s0lr0emnwfl5 my_nginx.4 nginx:latest docker-node140 Running Running 9 days ago
在node140上檢視容器
節點故障前: 只執行nginx和portainer agent2個容器
[root@docker-node140 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4544679904a4 portainer/agent:latest "./agent" 3 hours ago Up 3 hours portainer_agent.r53tu2gd5fvhsxh08nwvdrazs.2rob119x0xmf032ut12gn43w9
c315236add70 nginx:latest "/docker-entrypoint.…" 9 days ago Up 9 days 80/tcp my_nginx.4.s0lr0emnwfl5dwtwsnu7star5
節點故障後: 增加了一個my_nginx的副本。
[root@docker-node140 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
10ecbde19917 nginx:latest "/docker-entrypoint.…" 3 minutes ago Up 3 minutes 80/tcp my_nginx.3.j11badxpt18iuk9l1o38fyq8b
4544679904a4 portainer/agent:latest "./agent" 4 hours ago Up 4 hours portainer_agent.r53tu2gd5fvhsxh08nwvdrazs.2rob119x0xmf032ut12gn43w9
c315236add70 nginx:latest "/docker-entrypoint.…" 9 days ago Up 9 days 80/tcp my_nginx.4.s0lr
此時將node142節點恢復,容器並不會自動在node142上再次啟動,但是portainer agent由於是全域性服務模式,會重新啟動agent容器。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d970de5fe140 portainer/agent:latest "./agent" 18 minutes ago Up 18 minutes portainer_agent.ijb0eg2a06fwv2ap9s9b4ob0c.uoaaojlj9nnmefy1ta6i8i7en
0ff44aa14367 nginx:latest "/docker-entrypoint.…" 54 minutes ago Exited (0) 32 minutes ago my_nginx.3.i4valcpimsj68jq387gq0a89t
service mode
swarm可以在service建立或者執行過程中靈活的通過--replicas調整容器的副本數量,內部調整排程器則會根據當前叢集資源使用的情況在不通的node上啟動或停止容器,這就是service預設的replicated mode。在此模式下,node上執行的副本數有多有少,一般情況下,資源更豐富的node執行的副本數更多,反之亦然。
除了replicated mode,service還提供了一個global mode,作用是強制在每個node上執行一個且最多一個副本。
此模式特別適合需要執行daemon的叢集環境。比如要收集所有容器的日誌,就可以以global mode 建立service,在所有的node上執行gliderlabs/logspout容器,即使之後有新的node加入,swarm也會自動在新的node上啟動一個gliderlabs/logspout副本。
docker service create \
--mode global \
--name logspout \
--mount type=bind,src=//var/run/docker.sock,dst=/var/run/docker.sock \
gliderlabs/logspout
[root@docker-man143 ~]# docker service create \
> --mode global \
> --name logspout \
> --mount type=bind,src=//var/run/docker.sock,dst=/var/run/docker.sock \
> gliderlabs/logspout
p2nl849pe9udxtzy6bagvkal6
overall progress: 4 out of 4 tasks
so81lopbcdtn: running [==================================================>]
r53tu2gd5fvh: running [==================================================>]
ijb0eg2a06fw: running [==================================================>]
41yp9s0thoor: running [==================================================>]
verify: Service converged
[root@docker-man143 ~]# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
p2nl849pe9ud logspout global 4/4 gliderlabs/logspout:latest
[root@docker-man143 ~]# docker service ps logspout
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
okcnv4y6hlww logspout.ijb0eg2a06fwv2ap9s9b4ob0c gliderlabs/logspout:latest docker-node142 Running Running about a minute ago
08csr3murw8a logspout.so81lopbcdtnecvp7lls8ur9p gliderlabs/logspout:latest docker-node141 Running Running about a minute ago
1fftct1fgb9g logspout.r53tu2gd5fvhsxh08nwvdrazs gliderlabs/logspout:latest docker-node140 Running Running about a minute ago
w5ax02nlp24b logspout.41yp9s0thoorpwxognm7ut1vw gliderlabs/logspout:latest docker-man143 Running Running about a minute ago
注:如果建立service時不指定mode,預設使用replicated。
無論是採用global mode還是replicated mode,副本執行在哪些節點上都是由swarm決定的。如何做到精細的控制service的執行位置呢?
答案是:使用label。
邏輯分為兩步:
1.為每個node定義label。
2.設定service執行在指定label的node上。
label可以靈活描述node的屬性,其形式為key=value,使用者可以任意指定。
例如將node140作為測試環境,為其新增label env=test
docker node update --label-add env=test docker-node140
[root@docker-man143 ~]# docker node update --label-add env=test docker-node140
docker-node140
docker node inspect docker-node140 --pretty
[root@docker-man143 ~]# docker node inspect docker-node140 --pretty
ID: r53tu2gd5fvhsxh08nwvdrazs
Labels: #標籤內容
- env=test
Hostname: docker-node140
Joined at: 2020-07-24 08:38:57.391083869 +0000 utc
Status:
State: Ready
Availability: Active
Address: 192.168.68.140
Platform:
Operating System: linux
Architecture: x86_64
Resources:
CPUs: 8
Memory: 15.51GiB
Plugins:
Log: awslogs, fluentd, gcplogs, gelf, journald, json-file, local, logentries, splunk, syslog
Network: bridge, host, ipvlan, macvlan, null, overlay
Volume: local
Engine Version: 19.03.12
TLS Info:
TrustRoot:
-----BEGIN CERTIFICATE-----
MIIBazCCARCgAwIBAgIURyN5aj+50pCZV54KyPtxIUFGbRIwCgYIKoZIzj0EAwIw
EzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMjAwNzI0MDgyNDAwWhcNNDAwNzE5MDgy
NDAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH
A0IABJT4AC7CvIAQ3wbmCqGf9K77mvPOpDsZOBBdKY7UmfHAZ9PyeDUjALhSxwCu
csMjQw4WwZL2ms1IXQedOTPstbmjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
Af8EBTADAQH/MB0GA1UdDgQWBBSePlf/3aV/E6UXZSNWFmH5vRRESDAKBggqhkjO
PQQDAgNJADBGAiEAoxTu/y7H8V2j7a40mTYPu8yRRw2rRGc8DVPWD6EC7yMCIQCG
3qN57Oa6zpJJjjORgnugPZ/6RjZA2RzEWaco9yqRkw==
-----END CERTIFICATE-----
Issuer Subject: MBMxETAPBgNVBAMTCHN3YXJtLWNh
Issuer Public Key: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAElPgALsK8gBDfBuYKoZ/0rvua886kOxk4EF0pjtSZ8cBn0/J4NSMAuFLHAK5ywyNDDhbBkvaazUhdB505M+y1uQ==
對應的將docker-node141作為生產環境,新增label env=prod。
docker node update --label-add env=prod docker-node141
[root@docker-man143 ~]# docker node update --label-add env=prod docker-node141
docker-node141
docker node inspect docker-node141 --pretty
[root@docker-man143 ~]# docker node inspect docker-node141 --pretty
ID: so81lopbcdtnecvp7lls8ur9p
Labels:
- env=prod
Hostname: docker-node141
Joined at: 2020-07-24 09:21:53.789961627 +0000 utc
Status:
State: Ready
Availability: Active
Address: 192.168.68.141
現在部署service到測試環境:
docker service create --name web-label --constraint node.labels.env==test --replicas 3 --publish 8081:80 httpd
[root@docker-man143 ~]# docker service create --name web-label --constraint node.labels.env==test --replicas 3 --publish 8081:80 httpd
vzt8q3oyfjr3p2dpkstl9y6o7
overall progress: 3 out of 3 tasks
1/3: running [==================================================>]
2/3: running [==================================================>]
3/3: running [==================================================>]
verify: Service converged
[root@docker-man143 ~]# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
sg0gweqid90s my_nginx replicated 4/4 nginx:latest *:80->80/tcp
i8r172y5i6zw portainer replicated 1/1 portainer/portainer:latest *:8000->8000/tcp, *:9000->9000/tcp
pfcl416481x9 portainer_agent global 4/4 portainer/agent:latest
vzt8q3oyfjr3 web-label replicated 3/3 httpd:latest *:8081->80/tcp
[root@docker-man143 ~]# docker service ps web-label
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
ykqa7nlkepp8 web-label.1 httpd:latest docker-node140 Running Running 3 minutes ago
6uxe5lufqm50 web-label.2 httpd:latest docker-node140 Running Running 3 minutes ago
wjw5xrvow1s7 web-label.3 httpd:latest docker-node140 Running Running 3 minutes ago
在node140上檢視容器
[root@docker-node140 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ee8d4de5163b httpd:latest "httpd-foreground" 23 seconds ago Up 22 seconds 80/tcp web-label.1.ykqa7nlkepp8di32h4wlt7dil
7593b6fdb6f4 httpd:latest "httpd-foreground" 23 seconds ago Up 22 seconds 80/tcp web-label.3.wjw5xrvow1s7kk5xyx85kzjh5
cd6dbd176ddb httpd:latest "httpd-foreground" 23 seconds ago Up 22 seconds 80/tcp web-label.2.6uxe5lufqm50x0z652bhtqx0a
--constraint node.labels.env==test 限制將service部署到label==test的node,即docker-node140上,從上述部署的結果看,三個副本全都執行在docker-node140上。
可以通過docker service inspect檢視--constraint的設定
[root@docker-man143 ~]# docker service inspect web-label --pretty
ID: vzt8q3oyfjr3p2dpkstl9y6o7
Name: web-label
Service Mode: Replicated
Replicas: 3
Placement:
Constraints: [node.labels.env==test]
更新service,將其遷移到生產環境
先將web-label service的label刪除
docker service update --constraint-rm node.labels.env==test web-label
[root@docker-man143 ~]# docker service update --constraint-rm node.labels.env==test web-label
web-label
overall progress: 3 out of 3 tasks
1/3: running [==================================================>]
2/3: running [==================================================>]
3/3: running [==================================================>]
verify: Service converged
[root@docker-man143 ~]# docker service ps web-label
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
ykqa7nlkepp8 web-label.1 httpd:latest docker-node140 Running Running 14 minutes ago
6uxe5lufqm50 web-label.2 httpd:latest docker-node140 Running Running 14 minutes ago
wjw5xrvow1s7 web-label.3 httpd:latest docker-node140 Running Running 14 minutes ago
重新設定web-label service的label
docker service update --constraint-add node.labels.env==prod web-label
[root@docker-man143 ~]# docker service update --constraint-add node.labels.env==prod web-label
web-label
overall progress: 3 out of 3 tasks
1/3: running [==================================================>]
2/3: running [==================================================>]
3/3: running [==================================================>]
verify: Service converged
[root@docker-man143 ~]# docker service ps web-label
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
k4gfnensmqit web-label.1 httpd:latest docker-node141 Running Running 32 seconds ago
ykqa7nlkepp8 \_ web-label.1 httpd:latest docker-node140 Shutdown Shutdown 33 seconds ago
v5rzvrde7wi3 web-label.2 httpd:latest docker-node141 Running Running 42 seconds ago
6uxe5lufqm50 \_ web-label.2 httpd:latest docker-node140 Shutdown Shutdown about a minute ago
qf4n9kpqhs9p web-label.3 httpd:latest docker-node141 Running Running 37 seconds ago
wjw5xrvow1s7 \_ web-label.3 httpd:latest docker-node140 Shutdown Shutdown 38 seconds ago
可以看到,副本全部改到docker-node141上。
通過docker service inspect 檢視constraint
[root@docker-man143 ~]# docker service inspect web-label --pretty
ID: vzt8q3oyfjr3p2dpkstl9y6o7
Name: web-label
Service Mode: Replicated
Replicas: 3
UpdateStatus:
State: completed
Started: 5 minutes ago
Completed: 5 minutes ago
Message: update completed
Placement:
Constraints: [node.labels.env==prod]
label還可以和global模式總和起來使用,比如只收集生產環境中的容器的日誌
docker service create
--mode global
--constraint-add node.labels.env==prod
--mount type=bind,src=//var/run/docker.sock,dst=/var/run/docker.sock
--name logspout
gliderlabs/logspout
只有docker-node141節點才會執行logspout。