Docker swarm与docker-compose一样,都是docker官方推出的docker容器的编排工具。但不同的是,Docker Compose 是一个在单个服务器或主机上创建多个容器的工具,而 Docker Swarm 则可以在多个服务器或主机上创建容器集群服务,对于微服务的部署,显然 Docker Swarm 会更加适合。
Docker swarm:其作用就是把若干个Docker主机抽象为一个整体,并且通过一个入口统一管理这些Docker主机上的各种Docker资源。Swarm和Kubernetes比较类似,但是更加轻,具有的功能也较kubernetes更少一些。
从 Docker 1.12.0 版本开始,Docker Swarm 已经包含在 Docker 引擎中(docker swarm),并且已经内置了服务发现工具,我们就不需要像之前一样,再配置 Etcd 或者 Consul 来进行服务发现配置了。
Docker swarm中有三种角色:
Manager node:负责执行容器的编排和集群的管理工作,保持并维护swarm处于期望的状态,swarm可以有多个mana gernode,他们会自动协商选举出一个leader执行编排任务;但相反,不能没有manager node;
Worker node:接受并执行由manager node派发的任务,并且默认manager node也是一个worknode,不过可以将它设置manager-only node,让它负责编排和管理工作;
Service:用来定义worker上执行的命令;
注意:在一个Docker Swarm群集中,每台docker服务器的角色可以都是manager,但是,不可以都是worker,也就是说,不可以群龙无首,并且,参与群集的所有主机名,千万不可以冲突。
系统版本 | docker版本 | 主机名 | ip地址 |
---|---|---|---|
node01 | 192.168.10.52 | ||
centos 7.5 | 18.09.0 | node02 | 192.168.10.53 |
node03 | 192.168.10.54 |
注意事项:
保证时间同步;
关闭防火墙与SElinux(实验环境);
更改主机名;
编写host文件,保证可以i进行域名解析;
确保docker服务正在运行
[root@node01 ~]# tail -3 /etc/hosts
192.168.10.52 node01
192.168.10.53 node02
192.168.10.54 node03
//三台主机都需配置hosts文件实现域名解析的效果
[root@node01 ~]# docker swarm init --advertise-addr 192.168.10.52
//--advertise-addr:指定与其他node通信的地址
node02的操作如下
[root@node02 ~]# docker swarm join --token SWMTKN-1-1dng6ya431doiv4zco0ctidewipqtmdtazho5x8dm86y3cpugm-1j61jldff1deanqug6bxsxd5i 192.168.10.52:2377
This node joined a swarm as a worker.
node03的操作如下
[root@node03 ~]# docker swarm join --token SWMTKN-1-1dng6ya431doiv4zco0ctidewipqtmdtazho5x8dm86y3cpugm-1j61jldff1deanqug6bxsxd5i 192.168.10.52:2377
This node joined a swarm as a worker.
//node02、node03默认是以worker身份加入的
node01的操作如下
[root@node01 ~]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
cs215etnv76dfzxu6ogmu2nk2 node02 Ready Active 18.09.0
oec4ev02mg6zyb38rkwxydyel node03 Ready Active 18.09.0
xojmrky2j13xr6fiq07eub57j * npde01 Ready Active Leader 18.09.0
//可以看出node01、node02、node03的状态为Active
node02、node03申请离开集群
[root@node02 ~]# docker swarm leave
[root@node03 ~]# docker swarm leave
node01的操作如下
[root@node01 ~]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
cs215etnv76dfzxu6ogmu2nk2 node02 Down Active 18.09.0
oec4ev02mg6zyb38rkwxydyel node03 Down Active 18.09.0
xojmrky2j13xr6fiq07eub57j * npde01 Ready Active Leader 18.09.0
///可以看到node02、node03的状态为Down
[root@node01 ~]# docker node rm node02
[root@node01 ~]# docker node rm node03
//node01将node02、node03移除群集
[root@node01 ~]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
xojmrky2j13xr6fiq07eub57j * npde01 Ready Active Leader 18.09.0
//如果worker节点没有辞职,manager节点可以使用“-f”表示强制开出worker节点
加入群集时,可以指定使用manager、worker身份,但是也可以通过以下命令,进行降级、升级,操作
[root@node01 ~]# docker swarm join-token manager
//查询以manager身份加入群集的命令
[root@node01 ~]# docker swarm join-token worker
//查询以worker身份加入群集的命令
[root@node01 ~]# docker node demote node02
[root@node01 ~]# docker node demote node03
//将node02、node03降级为worker
[root@node01 ~]# docker node promote node02
[root@node01 ~]# docker node promote node03
//将node02、node03升级为manager
[root@node01 ~]# docker run -d -p 8080:8080 -e HOST=172.16.0.10 -e PORT=8080 -v /var/run/docker.sock:/var/run/docker.sock --name visualizer dockersamples/visualizer
//-e HOST指定的是容器
node01发布一个任务,(必须在manager角色的主机上)运行五个容器,命令如下:
[root@node01 ~]# docker service create --replicas 5 --name web -p 80:80 nginx
// --replicas:副本数量;大概可以理解为一个副本就是一个容器
注意:如果另外两台节点服务器上没有相应的镜像,则默认会从docker Hub上自动进行下载!
[root@node01 ~]# docker service ls //查看创建的service
ID NAME MODE REPLICAS IMAGE PORTS
qein8zix8an1 web replicated 5/5 nginx:latest *:80->80/tcp
[root@node01 ~]# docker service ps web //查看创建的service都运行在那些容器上
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
bhetrut34wa8 web.1 nginx:latest node01 Running Running about a minute ago
ao7cauwtgwdh web.2 nginx:latest node02 Running Running about a minute ago
9vn7c6feas61 web.3 nginx:latest node03 Running Running about a minute ago
pooq631f4evk web.4 nginx:latest node02 Running Running about a minute ago
hn1bfur0u2ri web.5 nginx:latest node03 Running Running about a minute ago
如果现在node02、node03发生宕机时,service并不会因为节点的当即而死掉,而是自动跑到正常的节点上。
模拟node02宕机
[root@node02 ~]# systemctl stop docker
恢复node02
[root@node02 ~]# systemctl start docker
即使node02恢复正常,也不会将service分配给node02。
因此,可以得出一个结论:如果node发生故障,service会自动跑到可用的节点上;反之,如果node没有发生故障,默认情况下,service不会轻易更改节点!
(1)service扩容 扩容:就是添加几台service;
[root@node01 ~]# docker service scale web=8
//原本有5个service,现在增加到8台
关于service分配到那台node节点上,是根据docker swarm自身的算法进行分配的。
(2)service收缩 收缩:就是减少几台service;
[root@node01 ~]# docker service scale web=4
//原本有8个service,现在减少到4台
(3)设置某个node不运行service
上述环境中,一台manager、两台worker默认情况manager也是进行工作的,可以通过设置,使某台节点不运行service,如下:
[root@node01 ~]# docker node update --availability drain node01
//设置noder01以后不运行容器,但已经运行的容器并不会停止
// --availability:选项后面共有三个选项可配置,如下:
active:工作;pause:暂时不工作;drain:永久性的不工作
[root@node01 ~]# docker node update --availability drain node02
//node02也不参加工作,但已经运行的容器并不会停止
docker swarm集群会产生两种不同类型的流量:
1.控制和管理层面:包括swarm消息管理等,例如请求加入或离开swarm,这种类型的流量总是被加密的(涉及到集群内部的hostname、ip-address、subnet、gateway等);
2.应用数据层面:包括容器与客户端的通信等(涉及到 防火墙、端口映射、VIP等);
在swarm中有三个重要的概念:
overlay networks:管理swarm中Docker守护进程间的通信。你可以将服务附加到一个或多个已存在的overlay网络上,使得服务与服务之间能够通信;
ingress network:是一个特殊的overlay网络,用于服务节点间的负载均衡。当然任何swarm节点在发布的端口上接收到请求后,将请求交给一个名为IPVS的模块。IPVS跟踪参与该服务的所有IP地址,选择其中的一个,并通过ingress网络将请求到它;
docker_gwbridge:是一种桥接网络,将overlay网络(包括ingress网络)连接到一个单独的Docker守护进程的物理网络。默认情况下,服务正在运行的每个容器都连接到本地Docker守护进程主机的docker_gwbridge网络;
docker_gwbridge网络在初始化Swarm或加入Swarm时自动创建。大多数情况下,用户不需要自定义配置,但是Docker允许自定义;
查看node01上默认的网络,如图:
注意:图中的SCOPE,注意其作用范围!
除了Swarm群集默认创建的两个网络以外,我们还可以自定义创建overlay网络,连接到此网络的容器,即可互相通信,,但是需要注意,自定义的网络只能是创建的manager主机才可查看到!
创建自定义overlay网络
[root@node01 ~]# docker network create -d overlay --subnet 200.0.0.0/24 --gateway 200.0.0.1 --attachable my_net
//Docker swarm群集创建overlay网络时,必须使用--attachable选项来指定名称,否则其他节点的容器运行时无法使用此网络
创建自定义的overlay网络时,必须是manager才可以创建,并且只在manager节点上才显示的,别的worker节点是查看不到的,但是可以使用。
如下:
[root@node02 ~]# docker run -itd --name test01 --ip 200.0.0.10 --network my_net busybox
//node02使用刚才自定义的overlay网络创建容器
[root@node03 ~]# docker run -itd --name test02 --ip 200.0.0.20 --network my_net busybox
//node03使用自定义的overlay网络创建容器
这是node02、node03已经使用过这个自定义的网络了,这是在node02、node03上就可以查看到了!
而且基于docker swarm创建的overlay网络也符合自定义跨主机网络的特点,可以使用主机名进行通信
通过搭建registry私有仓库,可以便于让其他node下载镜像。搭建私有仓库可以参考Docker——搭建私有仓库registry+Harbor
[root@node01 ~]# docker run -itd --name registry -p 5000:5000 -v /registry:/var/lib/registry --restart=always registry:2
[root@node01 ~]# vim /usr/lib/systemd/system/docker.service
//更改内容为
ExecStart=/usr/bin/dockerd --insecure-registry 192.168.10.52:5000
[root@node01 ~]# systemctl daemon-reload
[root@node01 ~]# systemctl restart docker
[root@node01 ~]# docker ps -a -q | xargs docker start
//由于刚才创建的容器并没有设置自动启动,所以在重启docker服务的时候,需要手动启动
[root@node01 ~]# ssh-keygen -t rsa
[root@node01 ~]# ssh-copy-id root@node02
[root@node01 ~]# ssh-copy-id root@node03
//设置免密登录
[root@node01 ~]# scp /usr/lib/systemd/system/docker.service root@node02:/usr/lib/systemd/system/docker.service
[root@node01 ~]# scp /usr/lib/systemd/system/docker.service root@node03:/usr/lib/systemd/system/docker.service
//将docker的配置文件复制到node02、node03上,因为docker的配置文件都是一样的内容
[root@node02 ~]# systemctl daemon-reload
[root@node02 ~]# systemctl restart docker
[root@node03 ~]# systemctl daemon-reload
[root@node03 ~]# systemctl restart docker
//重新启动node02、node03节点的docker服务
[root@node01 ~]# docker pull httpd
[root@node01 ~]# docker tag httpd:latest 192.168.10.52:5000/httpd:latest
[root@node01 ~]# docker push 192.168.10.52:5000/httpd:latest
//将httpd镜像上传到私有仓库中
//node02下载刚刚上传私有仓库的镜像
[root@node02 ~]# docker images //先查看一下镜像
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx 08393e824c32 5 days ago 132MB
busybox latest 018c9d7b792b 13 days ago 1.22MB
[root@node02 ~]# docker pull 192.168.10.52:5000/httpd:latest //下载
latest: Pulling from httpd
bf5952930446: Already exists
3d3fecf6569b: Pull complete
b5fc3125d912: Pull complete
679d69c01e90: Pull complete
76291586768e: Pull complete
Digest: sha256:fc717ed0d0b55ada05af1c1a95a2d4ee1153a5858fd65b654644a1a5add0c28b
Status: Downloaded newer image for 192.168.10.52:5000/httpd:latest
[root@node02 ~]# docker images //在此查看
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.10.52:5000/httpd latest a6ea92c35c43 4 days ago 166MB
nginx 08393e824c32 5 days ago 132MB
busybox latest 018c9d7b792b 13 days ago 1.22MB
如果是基于上面的环境做的,你需要使用docker node update node01 --availability active 这条命令使node01继续工作,才能得到如下结果图
(1)准备环境
[root@node01 ~]# mkdir version{1,2,3,}
[root@node01 ~]# cd version1
[root@node01 version1]# echo "version1" >> index.html
[root@node01 version1]# echo -e "FROM httpd:latest\nADD index.html /usr/local/apache2/htdocs/index.html" > Dockerfile
[root@node01 version1]# docker build -t 192.168.10.52:5000/httpd:v1 .
//version1目录下模拟生成版本v1
[root@node01 version1]# cp Dockerfile ../version2
[root@node01 version1]# cd !$
cd ../version2
[root@node01 version2]# echo "version2" >> index.html
[root@node01 version2]# docker build -t 192.168.10.52:5000/httpd:v2 .
//vesion2目录下模拟生成版本v2
[root@node01 version2]# cp Dockerfile ../version3
[root@node01 version2]# cd !$
cd ../version3
[root@node01 version3]# echo "version3" >> index.html
[root@node01 version3]# docker build -t 192.168.10.52:5000/httpd:v3 .
//vesion3目录下模拟生成版本v3
//注意在主页面做一些区分
[root@node01 ~]# docker push 192.168.10.52:5000/httpd:v1
[root@node01 ~]# docker push 192.168.10.52:5000/httpd:v2
[root@node01 ~]# docker push 192.168.10.52:5000/httpd:v3
//将生成的镜像上传到私有仓库
[root@node01 ~]# docker service create --replicas 3 --name httpd 192.168.10.52:5000/httpd:v1
//基于192.168.10.52:5000/httpd:v1创建三个service副本
浏览器访问测试:
三个service副本是轮询的方式来服务的,根据node02、node03的首页内容进行测试!
(2)版本升级
[root@node01 ~]# docker service update --image 192.168.10.52:5000/httpd:v2 httpd
//更新容器的镜像为版本2
浏览器进行测试:
默认情况下,swarm一次只更新一个副本,并且两个副本之间并没有等待时间
[root@node01 ~]# docker service update --replicas 6 --image 192.168.10.52:5000/httpd:v3 --update-parallelism 2 --update-delay 1m httpd
//--update-parallelism:设置更新的副本数量;
//--update-delay:更新的间隔时间
// --replicas 6:并在升级的过程中另外再创建3个副本
从更新的过程中可以看出效果!
[root@node01 ~]# docker service rollback httpd
//回滚为上一个版本
注意:当我们执行回滚操作的时候,默认是回滚到上一次操作的版本,并且不可以连续回滚。
[root@node02 ~]# docker swarm leave
//那个节点想退出swarm群集,就在那台节点上执行这条命令
//节点自动退出swarm群集(相当于辞职)
[root@node01 ~]# docker node rm 节点名称
//由manager主动删除节点(相当于开除)
[root@node01 ~]# docker node promote 节点名称
//将节点升级
[root@node01 ~]# docker node demote 节点名称
//将节点降级
[root@node01 ~]# docker node ls
//查看swarm群集的信息(只可以在manager角色的主机上查看)
[root@node01 ~]# docker node update --availability drain 节点名称
//调整节点不参加工作
[root@node01 ~]# docker node update 节点名称 --availability active
//调整节点在参加工作
[root@node01 ~]# docker swarm join-token worker
//查看加入swarm群集的令牌(可以是worker也可以是manager)
[root@node01 ~]# docker service scale web=4
//扩容、收缩swarn群集servie的数量(取决与群集原本的数量)
//比原本群集数量多,就是扩容,反之、收缩
[root@node01 ~]# docker service ls
//查看创建的service
[root@node01 ~]# docker service ps service的名称
//查看创建的service运行在那些容器上
[root@node01 ~]# docker service create --replicas 6 --name web -p 80:80 nginx
//指定运行的service副本数量
[root@node01 ~]# docker service create --replicas 3 --constraint node.hostname==node03 --name test nginx
//指定node节点,创建名为test的容器
[root@node01 ~]# docker node update --label-add mem=max node02
//以键值对的方式给docker02主机打上标签“mem=max”,等号两边的内容是可以自定义的
[root@node01 ~]# docker service create --name test1 --replicas 3 --constraint 'node.labels.mem==max' nginx
//基于nginx镜像在标签为“mem==max”的主机上运行3个名为test1的服务
[root@node01 ~]# docker node inspect node02
//标签相关的信息,在Spec{ }中有显示
1.参与群集的主机名一定不能冲突,并且可以互相解析对方的主机名;
2.集群内的所有节点可以都是manager角色,但是不可以都是worker角色;
3.当指定运行的镜像时,如果群集中的节点本地没有该镜像,那么它将会自动下载对应的镜像;
4.当群集正常工作时,若一个运行着容器的docker服务器发生宕机,那么,其所运行的所有容器,都将转移到其他正常运行的节点之上,而且,就算发生宕机的服务器恢复正常运行,也不会再接管之前运行的容器;