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

avator

2. 服务和任务 service and task

  • 任务(task)是swarm中的最小调度单元,目前来说就是一个单一的容器。
  • 服务(service)是指一组任务的合集,服务定义了任务的属性。服务有两种模式:
  • replicated services 按照一定规则在各个工作节点上运行指定个数的任务。
  • global services 每个工作节点上运行一个任务。
    两种模式通过docker service create --mode 参数指定。
    容器,任务,服务的关系:来自docker官网
    avtor

swarm调度策略

swarm在scheduler节点(lead 节点)运行容器的时候,会根据指定的策略来结算最适合运行容器的节点,目前支持的策略有:spread,binpack,random。

  1. random
    随机算则一个Node来运行容器,一般用作调试,spread和binpack策略会根据各个节点的可用的CPU,RAM以及正在运行的容器的数量来计算应该运行容器的节点。
  2. spread
    在同等条件下,spread策略会选择运行容器最少的Node来运行新的容器。使用spread策略会容器会均衡的分布在集群中的各个节点上运行,一旦一个节点挂掉只会损失少部分的容器。
  3. 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密码后进入页面管理
avator

docker swarm部署服务

我们以部署nginx服务为例:
步骤:

  1. 部署服务前创建用于集群内不同主机之间容器通信的网络
docker network create -d overlay nginx_net
[root@docker-man143 ~]# docker network ls | grep nginx
maiqmdcgpki4        nginx_net                 overlay             swarm
  1. 创建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
  1. 在线扩容服务
    可以通过`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                           
  1. 节点故障

我们通过关闭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。

posted @ 2020-08-03 17:18  Doc-Yu  阅读(877)  评论(0编辑  收藏  举报