Docker Swarm


一、 什么是Docker Swarm

Swarm 是 Docker 公司推出的用来管理 docker 集群的平台,几乎全部用GO语言来完成的开发的,代码开源在https://github.com/docker/swarm

Docker Swarm 和 Docker Compose 一样,都是 Docker 官方容器编排项目,但不同的是,Docker Compose 是一个在单个服务器或主机上创建多个容器的工具,而 Docker Swarm 则可以在多个服务器或主机上创建容器集群服务,对于微服务的部署,显然 Docker Swarm 会更加适合。

从 Docker 1.12.0 版本开始,Docker Swarm 已经包含在 Docker 引擎中(docker swarm)。

Swarm deamon 只是一个调度器(Scheduler)加路由器(router), Swarm 自己不运行容器,它只是接受 Docker 客户端发来的请求,调度适合的节点来运行容器,这就意味着,即使 Swarm 由于某些原因挂掉了,集群中的节点也会照常运行,当 Swarm 重新恢复运行之后,他会收集重建集群信息。

二、 Swarm的几个关键概念

  1. Swarm(集群):

    • Docker Swarm 允许你将多个 Docker 主机(节点)组成一个集群。这个集群被称为 Swarm。
    • Docker 节点可以在使用 docker swarm 命令进行初始化, 或者加入已有的 Swarm 集群。
  2. Manager Node(管理节点):

    • 管理节点负责 Swarm 集群的管理和调度。
    • 它们运行 Swarm 的核心服务,处理集群状态,协调任务分配,执行集群管理任务(如服务更新和服务发现)。
    • 建议在生产环境中使用多个管理节点以确保高可用性。
  3. Worker Node(工作节点):

    • 工作节点是运行实际容器实例的节点。
    • 它们接收来自管理节点的任务,并执行这些任务。
    • 工作节点不参与集群的管理和调度,只负责容器的执行。
  4. Service(服务):

    • 服务是 Docker Swarm 中定义一组相同容器的概念。
    • 每个服务可以有多个任务(容器实例),并且这些任务可以在不同的工作节点上运行。
    • 服务可以配置为有状态(Stateful)或无状态(Stateless)服务。
  5. Task(任务):

    • 任务是服务中的一个单元工作。每个任务对应一个容器实例。
    • Docker Swarm 会将服务的定义转换为任务,并将其分配给工作节点。
    • 如果某个任务失败(例如容器崩溃),Swarm 会自动尝试重新调度该任务。
  6. Stack(栈):

    • 栈是 Docker Swarm 中的一组服务的集合。
    • 它们通常通过一个 Docker Compose 文件来定义,用于部署一组相关联的服务。
    • 栈可以简化复杂应用的部署和管理,提供更高层次的抽象。
  7. Overlay Network(覆盖网络):

    • 覆盖网络是一种跨主机网络,允许 Swarm 集群中的容器在不同的节点上相互通信,就像它们在同一个网络中一样。
    • 覆盖网络支持服务发现和负载均衡等功能。
  8. Raft Consensus Protocol(Raft 共识协议):

    • Raft 是一种分布式共识协议,用于在管理节点之间维护集群状态的一致性。
    • 在 Swarm 中,Raft 协议确保管理节点之间的一致性,尤其是在多个管理节点的情况下,确保集群的高可用性。
  9. Load Balancing(负载均衡):

    • Docker Swarm 内置了负载均衡功能,可以根据服务的需求将流量分发到不同的任务实例上。
    • 通过内置的 DNS 服务发现,Swarm 可以自动将请求路由到可用的容器实例。
  10. Service Discovery(服务发现):

    • Docker Swarm 提供了内置的服务发现机制,允许服务自动找到其他服务并与之通信。
    • 每个服务都有一个唯一的 DNS 名称,Swarm 通过 DNS 解析将请求路由到适当的服务实例。

原理

如下图所示,swarm 集群由管理节点(manager)和工作节点(work node)构成。

  • Swarm Mananger:负责整个集群的管理工作包括集群配置、服务管理等所有跟集群有关的工作。
  • Work Node:即图中的 available node,主要负责运行相应的服务来执行任务(task)。

img

三、相关命令

Docker Swarm命令:

init        初始化一个Swarm。
join        将Docker主机加入到Swarm作为工作节点或管理节点。
leave       使节点离开Swarm。
update      更新Swarm配置。

Docker Service命令:

create      创建一个新的服务。
inspect     检查一个或多个服务。
update      更新一个服务。
remove      移除一个或多个服务。
tasks       列出一个或多个服务的任务。

Docker Node命令:

accept      接受加入到Swarm的请求。
promote     将节点提升为Swarm中的管理节点。
demote      将管理节点降级为Swarm中的工作节点。
inspect     检查一个或多个节点。
update      更新一个节点。
tasks       列出分配给一个或多个节点的任务。
ls          列出Swarm中的节点。
rm          从Swarm中移除一个或多个节点。

Docker Stack命令:

config      输出最终的配置文件,在完成合并和插值后
deploy      部署一个新的堆栈或更新现有的堆栈
ls          列出堆栈
ps          列出堆栈中的任务
rm          移除一个或多个堆栈
services    列出堆栈中的服务

四、swarm集群部署

4.1、 部署前准备

以下操作在所有节点上进行:

IP地址 计算机名 角色
192.168.8.150 server01 swarm_manager
192.168.8.151 server02 swarm_node
192.168.8.152 server03 swarm_node
# 所有节点安装 docker

## CentOS7系统
yum install -y yum-utils device-mapper-persistent-data lvm2
wget https://download.docker.com/linux/centos/docker-ce.repo -P /etc/yum.repos.d/
sed -i 's#download.docker.com#mirrors.tuna.tsinghua.edu.cn/docker-ce#g' /etc/yum.repos.d/docker-ce.repo
yum -y install  docker-ce

# 关闭firewalld
systemctl disable firewalld
systemctl stop firewalld
iptables -F

# 关闭 selinux
#设置为 disabled 后需要重启计算机生效
SELINUX=disabled

## Ubuntu系统
apt-get -y install ca-certificates curl gnupg lsb-release
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
apt-get -y install docker-ce docker-ce-cli containerd.io
sudo usermod -aG docker $USER

# 设置镜像加速和私有镜像站
cat >> /etc/docker/daemon.json << EOF
{
 "registry-mirrors":["https://docker.rainbond.cc"],
 "insecure-registries": ["http://192.168.3.200:8099"]
}

EOF

systemctl daemon-reload
systemctl restart docker
# 所有节点设置 hosts 解析
cat >> /etc/hosts << EOF
192.168.8.150 server01
192.168.8.151 server02
192.168.8.152 server03
EOF

4.2、 创建swarm集群

# 1.Manager节点初始化集群-init
[root@server01 ~]# docker swarm init --advertise-addr 192.168.8.150
#--advertise-addr参数表示其它swarm中的worker节点使用此ip地址与manager联系
# Swarm initialized: current node (dh6qthwwctbrl0y3hx1k41icl) is now a manager.
To add a worker to this swarm, run the following command:
# 保存下列命令与token令牌,用于添加工作节点
docker swarm join --token SWMTKN-1-0vdbyxq80uk8sf9nlnahsnkv6w3gaf5necl992ia0g8dmc5x8c-bkenoigc7kwizoch08r3fc4wq 192.168.8.150:2377
# 添加Manager节点到Swarm集群时,执行'docker swarm join-token manager'获取令牌
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

4.3、添加worker(node工作节点)到swarm

# 复制你自己上一步中输出的完整命令到工作节点中。
[root@server02 ~]# docker swarm join --token SWMTKN-1-0vdbyxq80uk8sf9nlnahsnkv6w3gaf5necl992ia0g8dmc5x8c-bkenoigc7kwizoch08r3fc4wq 192.168.8.150:2377
This node joined a swarm as a worker.

[root@server03 ~]# docker swarm join --token SWMTKN-1-0vdbyxq80uk8sf9nlnahsnkv6w3gaf5necl992ia0g8dmc5x8c-bkenoigc7kwizoch08r3fc4wq 192.168.8.150:2377
This node joined a swarm as a worker.

4.4、 验证加入情况

 [root@server01 ~]# docker node ls
 ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
jnfl110hy5f72bohyowdjsxi8 *     server1    Ready     Active         Leader           27.3.1
lzzdgg96qo7vud6uz3pjt8mdr       server2    Ready     Active                          27.3.1
sr414k02ngx8vz9e1gx4vzlo4       server3    Ready     Active                          27.3.1

4.5、 在Swarm中部署服务(nginx为例)

# 创建网络在部署服务
# 创建网络
[root@server01 ~]# docker network create -d overlay nginx_net
a52jy33asc5o0ts0rq823bf0m

[root@server01 ~]# docker network ls | grep nginx_net
a52jy33asc5o        nginx_net           overlay             swarm
# 部署服务
[root@server01 ~]# docker service create --replicas 1 --network nginx_net --name my_nginx -p 80:80 nginx    # 就创建了一个具有一个副本(--replicas 1 )的nginx服务,使用镜像nginx

olexfmtdf94sxyeetkchwhehg
overall progress: 1 out of 1 tasks
1/1: running   [==================================================>]
verify: Service converged

在 manager与node 节点上使用上面这个覆盖网络创建 nginx 服务
其中,--replicas 参数指定服务由几个实例组成
注意:不需要提前在节点上下载 nginx 镜像,这个命令执行后会自动下载这个容器镜像

1) 使用 docker service ls 查看正在运行服务的列表

[root@server01 ~]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
olexfmtdf94s        my_nginx            replicated          1/1                 nginx:latest        *:80->80/tcp

2) 查询Swarm中服务的信息 -pretty 使命令输出格式化为可读的格式,不加 --pretty 可以输出更详细的信息:

[root@server01 ~]# docker service inspect --pretty my_nginx

ID:             zs7fw4ereo5w7ohd4n9ii06nt
Name:           my_nginx
Service Mode:   Replicated
 Replicas:      1
Placement:
UpdateConfig:
 Parallelism:   1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Update order:      stop-first
RollbackConfig:
 Parallelism:   1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Rollback order:    stop-first
ContainerSpec:
 Image:         nginx:latest@sha256:b73f527d86e3461fd652f62cf47e7b375196063bbbd503e853af5be16597cb2e
 Init:          false
Resources:
Networks: nginx_net
Endpoint Mode:  vip
Ports:
 PublishedPort = 80
  Protocol = tcp
  TargetPort = 80
  PublishMode = ingress
# 查询到哪个节点正在运行该服务
[root@server01 ~]# docker service ps my_nginx

scale是在Swarm中的动态扩展服务,它提供了容器复制的功能。 可以通过 docker service scale 命令来设置服务中容器的副本数。 比如将上面的 my_nginx 容器动态扩展到 4 个

[root@server01 ~]# 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

和创建服务一样,增加 scale 数之后,将会创建新的容器,这些新启动的容器也会经历从准备到运行的过程,过一分钟左右,服务应该就会启动完成,这时候可以再来看一下 nginx 服务中的容器

[root@server01 ~]# docker service ps my_nginx
升级镜像/升级业务/回滚业务
[root@server01 ~]# docker service update --image nginx:new my_nginx
删除服务
[root@server01 ~]# docker service rm my_nginx

五、使用docker-compose.yml文件来定义服务

5.1 部署服务

前面我们使用docker service create 一次只能部署一个服务,这次使用 docker-compose.yml我们可以一次启动多个关联的服务。

以部署之前部署过的wordpress博客网站为例

1)创建wordpress文件夹

[root@server01 ~]# mkdir -p /data/wordpress
[root@server01 ~]# cd /data/wordpress/

2)编辑docker-compose.yml文件

[root@server01:/data/wordpress/]# vim docker-compose.yml

version: "3"

services:
  wordpress:
    image: wordpress
    ports:
      - 80:80
    networks:
      - overlay
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
    deploy:
      mode: replicated
      replicas: 3

  db:
    image: mysql:5.7
    networks:
       - overlay
    volumes:
      - db-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: root123
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
    deploy:
      placement:
        constraints: [node.role == manager]

  visualizer:
    image: dockersamples/visualizer:stable
    ports:
      - "8080:8080"
    stop_grace_period: 1m30s
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      placement:
        constraints: [node.role == manager]

volumes:
  db-data:
networks:
  overlay:

在这里我们写了三个服务,分别是wordpress、db和visualizer,visualizer容器是一个提供可视化界面方便我们查看集群中各个服务运行节点状态的容器。

deploy 部分用于定义服务的部署策略,node.role 用于根据节点的角色来选择节点。

  • mode: replicated: 使用副本模式
  • replicas: 3: 启动副本数量为3
  • node.role == manager:服务只能部署在 Swarm 集群的管理节点上。
  • node.role == worker:服务只能部署在 Swarm 集群的工作节点上。

3)部署服务

[root@server01:/data/wordpress/]# docker stack deploy -c docker-compose.yml wordpress

# 部署服务使用docker stack deploy命令
# -c:指定compose文件名

[root@server01:/data/wordpress/]# docker stack ls

4)查看效果

打开浏览器输入 任一节点IP:8080 即可看到各节点运行状态

image-20211012172627417

5.2 查看服务

[root@server01:/data/wordpress/]# docker stack ls

可以看到wordpress项目运行了3个服务

image-20211012172747649

[root@server01:/data/wordpress/]# docker stack ps wordpress

可以看到db,visualizer容器分布在server01上,wordpress有三个分别分布在三台服务器上。

image-20211012173004230

5.3 删除服务

删除wordpress服务

[root@server01:/data/wordpress/]# docker stack down wordpress

六、管理密钥

我们以前将密钥、证书等敏感信息放入镜像中或者设置环境变量以及volume 动态挂载都是不安全的方式。

所以docker提供了secrets来管理密钥,它不仅能在Swarm集群中安全的管理密钥,还能在多个 Docker 容器实例之间共享访问指定的敏感数据。

还能在Docker Compose 中使用。

6.1 使用secret

1)创建secret

创建密码secret文件,创建成功后会返回ID号

#这里创建的wp跟mysql的root密码
[root@server01 ~]# echo "wordpress" | docker secret create wp_db_password -
[root@server01 ~]# echo "root123"   | docker secret create mysql_root_password -

#这是随机生成的密码,不建议使用
[root@server01 ~]# openssl rand -base64 20 | docker secret create mysql_password -
[root@server01 ~]# openssl rand -base64 20 | docker secret create mysql_root_password -

img

2)查看secret

[root@server01 ~]# docker secret ls

img

6.2 案例

1)部署Mysql服务

创建一个名为mysql_private的overlay网络

[root@server01 ~]# docker network create -d overlay mysql_private

创建mysql服务

docker service create \
     --name mysql \
     --replicas 1 \
     --network mysql_private \
     --mount type=volume,source=mydata,destination=/var/lib/mysql \
     --secret source=mysql_root_password,target=mysql_root_password \
     --secret source=wp_db_password,target=wp_db_password \
     -e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/mysql_root_password" \
     -e MYSQL_PASSWORD_FILE="/run/secrets/wp_db_password" \
     -e MYSQL_USER="wordpress" \
     -e MYSQL_DATABASE="wordpress" \
     mysql:latest

这里挂载了数据卷,如果之前创建了同名数据一定要删除,切记,一定要删除,不然mysql是登录不上的,有残留数据。

还有你没有在 target 中指定路径时,secret 默认通过 tmpfs 文件系统挂载到容器的 /run/secrets 目录中。

2)部署wordpress服务

docker service create \
     --name wordpress \
     --replicas 1 \
     --network mysql_private \
     -p 8080:80 \
     --mount type=volume,source=wpdata,destination=/var/www/html \
     --secret source=wp_db_password,target=wp_db_password \
     -e WORDPRESS_DB_USER="wordpress" \
     -e WORDPRESS_DB_PASSWORD_FILE="/run/secrets/wp_db_password" \
     -e WORDPRESS_DB_HOST="mysql:3306" \
     -e WORDPRESS_DB_NAME="wordpress" \
     wordpress:latest

3)查看服务

[root@server01 ~]# docker service ls

4)访问效果

浏览器访问,开始 WordPress 的安装与使用。

image-20211012235925757

七、管理配置信息

除了之前介绍的使用secret管理密钥,这里还能使用config管理配置文件。

使用docker config 子命令来管理集群中的配置信息,以后无需将配置文件放入镜像或挂载到容器中就可实现对服务的配置。

7.1 使用config

1)编辑redis配置文件,让redis监听6380端口

[root@server01 ~]# mkdir -p /data/redis
[root@server01 ~]# cd /data/redis/
[root@server01:/data/redis/]# echo "port 6380" > redis.conf

2)创建config

[root@server01:/data/redis/]# docker config create redis.conf redis.conf

3)查看config

[root@server01:/data/redis/]# docker config ls

7.2 案例

1)部署redis服务

docker service create \
     --name redis \
     # --config source=redis.conf,target=/etc/redis.conf \
     --config redis.conf \
     -p 6379:6380 \
     redis:latest \
     redis-server /redis.conf

看注释那一行,如果没有在 target 中显式的指定路径,默认的 redis.conf 会以 tmpfs 文件系统挂载到容器的 /config.conf。

采用 docker config 来管理服务的配置信息,我们只需修改在集群中的管理节点创建的config,集群会自动的将配置文件分发到运行服务的各个节点中,大大降低了配置信息的管理和分发难度。

另外需要注意的是,config命令仅能在 Swarm 集群中使用。

八、滚动升级

在Swarm升级服务版本,将Nginx1.18版本升级为Nginx:latest,可以使用docker service update命令实现。

8.1 升级

docker service update \
    --image nginx:latest \
    nginx


# --image:选择服务更新的镜像
# --secret-add:增加一个密钥
# --secret-rm:移除一个密钥

8.2 回退

升级后出现问题,可以使用docker service rollback一键回退。

docker service rollback nginx

#查看nginx服务详情
docker service ps nginx

九、总结

  • 节点分为管理 (manager) 节点和工作 (worker) 节点。
  • 一个 Swarm 集群可以有多个管理节点,但只有一个管理节点可以成为 leader,leader 通过 raft 协议实现。
  • 工作节点是任务执行节点,管理节点将服务 (service) 下发至工作节点执行。管理节点默认也作为工作节点。你也可以通过配置让服务只运行在管理节点。

图示如下

img

Swarm通用用于搭建小型服务器集群,例如10台以下的服务集群

大型服务器集群使用更加方便的k8s