前言
《了解和使用Docker》中有提到容器编排工具 docker compose ,不过只限于单机。如果现在需要搭建一个集群环境,提供了10台服务器用来部署应用以及其依赖的组件,比如5个 Tomcat 应用容器、3个Redis、5个 Mysql、3个 Nginx ,你会如何部署?
重复执行部署操作?如果需要扩缩容,手动处理吗?如果上百个应用,容器如何管理?集群中容器之前如何通信?数据如何管理?
很显然,我们需要一个工具帮助我们更快、更高效的做这些事。本文对 Docker Swarm 进行介绍,详细说明在集群环境中如何统一部署、统一管理、统一调度容器。
下面还有投票,一起参与进来吧👍
@[TOC]
Docker Swarm介绍
Docker Swarm是 Docker 官方提供的一款集群管理工具,和 Kubernetes 比较类似,但是更加轻,具有的功能也较 Kubernetes 更少一些。其本质是把若干台 Docker 主机抽象为一个整体,并且通过一个入口统一管理这些 Docker 主机上的各种 Docker 资源,如下图。
其中节点分为两类:
- 管理节点(manager node) 负责管理集群中的节点并向工作节点分配任务
- 工作节点(worker node) 接收管理节点分配的任务,运行任务
Docker Swarm 集群部署
部署 Docker Swarm 集群不论管理节点还是工作节点都需要先安装 Docker,然后某个管理节点执行集群初始化操作后,其他节点才可以加入集群。
Docker 安装
这里基于 CentOS 操作系统进行 Docker 安装
# 设置 Docker YUM 源并下载
wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 安装 docker-ce
yum -y install docker-ce
# 启动docker服务并设置为开机自启动
systemctl enable docker
systemctl start docker
systemctl restart docker
Docker Swarm集群初始化
# 获取docker swarm命令使用帮助
docker swarm --help
Usage: docker swarm COMMAND
Manage Swarm
Commands:
ca Display and rotate the root CA
init Initialize a swarm 初始化
join Join a swarm as a node and/or manager 加入集群
join-token Manage join tokens 集群加入时token管理
leave Leave the swarm 离开集群
unlock Unlock swarm
unlock-key Manage the unlock key
update Update the swarm 更新集群
在管理节点进行初始化
# --advertise-addr 当主机有多块网卡时使用其选择其中一块用于广播,用于其它节点连接管理节点使用--listen-addr 监听地址,用于承载集群流量使用
docker swarm init --advertise-addr 192.168.10.10 --listen-addr 192.168.10.10:2377
初始化命令执行后会输出其他节点加入集群的命令
Swarm initialized: current node (j42cwubrr70pwxdpmesn1cuo6) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-297iry1n2jeh30oopsjecvsco1uuvl15t2jz6jxabdpf0xkry4-6pddlyiq5f1i35w8d7q4bl1co 192.168.10.10:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
Docker 节点加入集群
添加工作节点到集群
直接复制初始化后命令加入集群
docker swarm join --token SWMTKN-1-297iry1n2jeh30oopsjecvsco1uuvl15t2jz6jxabdpf0xkry4-6pddlyiq5f1i35w8d7q4bl1co 192.168.10.10:2377
查看已加入的集群
docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
j42cwubrr70 * xxx1 Ready Active Leader 20.10.12
4yb34kuma6i xxx2 Ready Active 20.10.12
可以看到管理节点是有主从角色的,所以如果备份的管理节点要加入集群,需要 Leader 节点生成管理节点到集群的命令
docker swarm join-token manager
如果使用的token已过期,可以在管理节点再次生成新的token
# 生成工作节点加入集群的token
docker swarm join-token worker
# 生成管理节点加入集群的token
docker swarm join-token manager
Docker Swarm 集群应用
Docker Swarm 集群环境部署好后就对容器镜像进行部署操作了。在 Docker Swarm 中,对外暴露的是服务(service),而不是容器。为了保持高可用架构,它允许同时启动多个容器共同支撑一个服务,如果一个容器挂了,它会自动使用另一个容器。
Docker Swarm 基本命令
# 发布服务
docker service create
# 查看已发布服务
docker service ls
# 服务更新
docker service update
# 服务扩/缩容
docker service scale
# 服务删除
docker service rm
# 创建服务网络
docker network create
# 查看服务网络
docker service ls
发布服务
在发布服务时可以指定副本个数进行部署,也就是上述所说的高可用,创建一个服务名为 sn1 ,副本个数为3,命令如下
docker service create --name sn1 --replicas 3 192.168.10.10/library/imagetest1:v1
此命令执行成功后会在 Docker Swarm 集群中的3个节点上部署镜像为 imagetest1 的容器。包含多个容器时,每次访问将以轮询的方式访问到每个容器,后面服务网络中有说明。
服务扩缩
如果现在需要对服务 sn1 进行扩缩容可以执行以下命令
docker service scale sn1=2
此命令执行成功后会将服务 sn1 的容器数量由3个缩减到2个。
服务版本更新
如果现在需要对服务中的镜像进行更新,比如升级、回退等操作,执行以下命令即可
docker service update sn1 --image 192.168.10.10/library/imagetest1:v2
同时还支持滚动间隔更新,也就是在指定的间隔时间后更新指定的数量,比如 30s 更新一个,这样在出现问题后可以及时停止。
# --update-parallelism 指定并行更新数量
# --update-delay 指定更新间隔时间
docker service update sn1 --image 192.168.10.10/library/imagetest1:v2 --update-parallelism 1 --update-delay 30s
服务互联与服务发现
集群中的这些服务如何进行通信?比如 tomcat 服务和 Mysql 服务通信,暴露端口吗?这个是非常不安全的;还有服务重新部署后 IP 发生变化,连接它的服务也需要修改吗?这些问题在 Docker Swarm 中可以使用overlay 网络实现,在发布服务时选用同一个网络,服务的使用者都不需要知道服务运行在哪里,IP是多少,有多少个副本,就能让服务之间通信。
在 Docker Swarm 中有三个重要的网络概念:
- Overlay networks 管理 Swarm 中 Docker 守护进程间的通信。可以将服务附加到一个或多个已存在的 overlay 网络上,使得服务与服务之间能够通信。
- ingress network 是一个特殊的 overlay 网络,用于服务的负载均衡。当任何节点在发布的端口上接收到请求时,它将该请求交给一个名为 IPVS 的模块。IPVS 跟踪参与该服务的所有容器 IP 地址,选择其中的一个,并通过 ingress 网络将请求路由到它。大多数情况下,用户不需要自定义配置,初始化或加入 Swarm 集群时会自动创建 ingress网络。
- docker_gwbridge是一种桥接网络,将 overlay 网络(包括 ingress 网络)连接到一个单独的 Docker 守护进程的物理网络。默认情况下,服务中的每个容器都连接到本地 Docker 守护进程主机的 docker_gwbridge 网络。
# 创建Overlay网络
docker network create -d overlay mynet
# 发布服务时加入mynet网络
docker service create --name sntest1 --network mynet -p 8080:8080 --replicas 2 192.168.10.10/library/imagetest1:v2
# 发布服务时加入mynet网络
docker service create --name sntest2 --network mynet -p 8081:8081 --replicas 2 192.168.10.10/library/imagetest1:v2
通过以上命令,服务 sntest1 和 sntest2 之间就可以通过服务名互相连接了。
服务数据持久化
Docker Swarm 发布服务时挂载本地目录到容器中直接通过参数设置即可,如下
docker service create --name sntest1 --mount "type=bind,source=/data/localtest,target=/usr/share/" --replicas 2 192.168.10.10/library/imagetest1:v2
如果容器之间的数据需要共享,这种方式就不适用了,通过网络存储卷可以实现跨宿主机的数据共享(需要集群节点都创建该网络存储卷)。
以 NFS 提供远程存储为例,在存储节点上安装 NFS 服务并设置共享目录
# 安装nfs-utils
yum -y install nfs-utils
# 设置nfs共享目录目录及权限
echo "/opt/dockervolume *(rw,sync,no_root_squash)" > /etc/exports
systemctl enable nfs-server
systemctl start nfs-server
# 查看nfs共享目录
showmount -e
然后在 Docker Swarm 各个节点部署 NFS 服务,创建存储卷
# 安装nfs-utils
yum -y install nfs-utils
# 查看nfs服务节点的共享目录
showmount -e 192.168.10.10
# 创建存储卷
docker volume create --driver local --opt type=nfs --opt o=addr=192.168.10.10,rw --opt device=:/opt/dockervolume testnetvolume
在发布服务时挂载 testnetvolume 即可达到容器之间的数据共享
docker service create --name sntest1 --mount "type=volume,source=testnetvolume,target=/usr/share/" --replicas 2 192.168.10.10/library/imagetest1:v2
Docker Stack
发布服务每次只能发布一个,Docker Stack 属于集群版的 docker-compose,一组有关联的服务的组合,可以一起编排,一起发布, 一起管理。与单机版的 docker-compose 不同的是 Docker Stack 会忽略了“构建”指令,只能使用预先已经构建好的镜像;另外 docker-compose 属于一个项目,需要单独安装, Docker Stack功能包含在Docker引擎中,属于 Docker Swarm 一部分。
Docker Stack 基本命令
# 部署更新现有堆栈
docker stack deploy
# 查看现有堆栈
docker stack ls
# 查看堆栈中的任务
docker stack ps
# 删除一个或多个堆栈
docker stack rm
# 列出堆栈中的服务
docker stack services
使用 Docker Stack 发布
编写一个包括自定义的服务、 visualizer服务、portainer服务的YAML文件并发布,stack.yaml示例如下:
# stack 不支持基于第2版写的docker-compose.yml ,version版本至少为3
version: "3"
services:
nginx:
image: 192.168.10.10/library/imagetest1:v2
ports:
- 80:80
deploy:
mode: replicated
replicas: 3
visualizer:
# docker swarm 集群可视化
image: dockersamples/visualizer
ports:
- "9001:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
replicas: 1
# 该服务限制发布到管理节点
placement:
constraints: [node.role == manager]
portainer:
# 可视化管理 docker swarm 集群
image: portainer/portainer
ports:
- "9000:9000"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
replicas: 1
placement:
constraints: [node.role == manager]
# 部署堆栈
docker stack deploy -c stack.yaml stacktest