第六课: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。