背景介绍#

借助一个Redis实例来学习 Docker Swarm,背景:standalone 部署模式故障转移机制:独立部署 Redis ,借助 docker swarm 故障转移机制做到基本HA,多节点的Redis通过 NFS 实现容器数据共享。

环境准备#

独立的 NFS 服务器

192.168.158.143部署NFS服务

Swarm 集群由 管理节点 和 工作节点 组成。这里创建一个包含一个管理节点和两个工作节点的最小 Swarm 集群

IPIsManager
192.168.158.144Yes
192.168.158.145
192.168.158.146

Docker Swarm#

Docker Swarm 是 Docker 官方三剑客项目之一,提供 Docker 容器集群服务,是 Docker 官方对容器云生态进行支持的核心方案。使用它可以将多个 Docker 主机封装为单个大型的虚拟 Docker 主机,快速打造一套容器云平台。

注意:Docker 1.12.0+ Swarm mode 已经内嵌入 Docker 引擎,成为了 docker 子命令 docker swarm,Docker 引擎 API 已经删除 Docker Swarm

Swarm mode 内置 kv 存储功能,提供了众多新特性,比如:具有容错能力的去中心化设计、内置服务发现、负载均衡、路由网格、动态伸缩、滚动更新、安全传输等。

Swarm 是使用 [SwarmKit](https://github.com/docker/swarmkit/) 构建的 Docker 引擎内置(原生)的集群管理和编排工具。使用 Swarm 集群之前需要了解以下几个概念。

节点#

运行 Docker 的主机可以主动初始化一个 Swarm 集群或者加入一个已存在的 Swarm 集群,这样这个运行 Docker 的主机就成为一个 Swarm 集群的节点 (node) 。节点分为管理 (manager) 节点和工作 (worker) 节点。管理节点用于 Swarm 集群的管理,docker swarm 命令基本只能在管理节点执行(节点退出集群命令 docker swarm leave 可以在工作节点执行)。一个 Swarm 集群可以有多个管理节点,但只有一个管理节点可以成为 leaderleader 通过 raft 协议实现。工作节点是任务执行节点,管理节点将服务 (service) 下发至工作节点执行。管理节点默认也作为工作节点。也可以通过配置让服务只运行在管理节点。

集群中管理节点与工作节点的关系

服务和任务#

任务 (Task)是 Swarm 中的最小的调度单位,目前来说就是一个单一的容器。服务 (Services) 是指一组任务的集合,服务定义了任务的属性。服务有两种模式:

  • replicated services 按照一定规则在各个工作节点上运行指定个数的任务
  • global services 每个工作节点上运行一个任务

两种模式通过 docker service create--mode 参数指定。

容器/任务/服务的关系

NFS 服务搭建#

服务端192.168.158.143安装 nfs-server

yum -y install rpcbind nfs-utils
systemctl start rpcbind
systemctl enable rpcbind
systemctl start nfs-server  //NFS依赖rpcbind进行通讯,所以要先启动rpcbind
systemctl enable nfs-server

客户端192.168.158.145/192.168.158.146 安装 nfs-utils,这里管理节点 192.168.158.144 并不打算部署服务故不需要安装nfs-utils

yum -y install nfs-utils

创建共享目录

//服务端
[root@centos-01 /]# mkdir -p /mnt/nfs_file/redis 
//客户端
[root@centos-01 /]# mkdir -p /mnt/nfs_file/redis 

服务端NFS配置#

vim /etc/exports
/mnt/nfs_file/ 192.168.158.143/24(rw,sync,no_root_squash)

//ro只读权限
//rw读写权限
//sync同步写入内存与磁盘当中
//no_all_squash保留共享文件的UID和GID(默认)
//no_root_squash使得root用户具有根目录的完全访问权限
[root@centos-01 ~]# vi /etc/exports
[root@centos-01 ~]# cat /etc/exports
/mnt/nfs_file/ 192.168.57.0/24(rw,sync,no_root_squash)

配置生效

[root@centos-01 ~]# exportfs -rv
exporting 192.168.158.143/24:/mnt/nfs_file

客户端NFS配置#

关联服务器

mount -t nfs 192.168.158.143:/mnt/nfs_file /mnt/nfs_file
//挂载测试
[root@centos-01 ~]# showmount -e 192.168.158.143
Export list for 192.168.158.143:
/mnt/nfs_file 192.168.158.143/24

备注:出现 clnt_create:RPC:Port mapper failure - Unable to receive:error 113(NO route to host) 报错时,需要关闭服务端与客户端之间的防火墙,或者开放NFS使用的2049端口。

systemctl stop firewalld

//添加规则(指定端口,--permanent永久生效,没有此参数重启后失效)
//firewall-cmd --zone=public --add-port=2049/tcp --permanent

Docker 集群搭建#

创建集群#

管理节点192.168.158.144 

[root@centos-01 ~]# docker swarm init
Swarm initialized: current node (khtc8jboe8dy7wm73x1cacnqf) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-4fixdycxiue0273gkral83cn9bgqvkct13r9fo1k01iy6oaadm-e3rd668t3ww1b2w3e0xfxi8yo 192.168.158.144:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

工作节点1192.168.158.145

[root@centos-01 ~]#  docker swarm join --token SWMTKN-1-4fixdycxiue0273gkral83cn9bgqvkct13r9fo1k01iy6oaadm-e3rd668t3ww1b2w3e0xfxi8yo 192.168.158.144:2377
This node joined a swarm as a worker.

工作节点2192.168.158.146

[root@centos-01 ~]# docker swarm join --token SWMTKN-1-4fixdycxiue0273gkral83cn9bgqvkct13r9fo1k01iy6oaadm-e3rd668t3ww1b2w3e0xfxi8yo 192.168.158.144:2377
This node joined a swarm as a worker.

更改节点可用性#

[root@centos-01 ~]# docker node ls
ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
0aw4rk8kwos84yi0ca57q5pcq     centos-01   Ready     Active                          20.10.6
579nqzz3p512aobe6mp4g93ep     centos-01   Ready     Active                          20.10.6
khtc8jboe8dy7wm73x1cacnqf *   centos-01   Ready     Active         Leader           20.10.6
[root@centos-01 ~]# docker node update --availability drain khtc8jboe8dy7wm73x1cacnqf
khtc8jboe8dy7wm73x1cacnqf
[root@centos-01 ~]# docker node ls
ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
0aw4rk8kwos84yi0ca57q5pcq     centos-01   Ready     Active                          20.10.6
579nqzz3p512aobe6mp4g93ep     centos-01   Ready     Active                          20.10.6
khtc8jboe8dy7wm73x1cacnqf *   centos-01   Ready     Drain          Leader           20.10.6

查看集群状态#

192.168.158.144

[root@centos-01 ~]# docker node ls
ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
0aw4rk8kwos84yi0ca57q5pcq     centos-01   Ready     Active                          20.10.6
579nqzz3p512aobe6mp4g93ep     centos-01   Ready     Active                          20.10.6
khtc8jboe8dy7wm73x1cacnqf *   centos-01   Ready     Active         Leader           20.10.6

解散集群#

docker swarm leave                       # 工作节点:主动离开集群,让节点处于down状态,才能删除
docker node rm g36lvv23ypjd8v7ovlst2n3yt # 管理节点:删除指定节点
docker swarm leave --force               # 管理节点:解散集群

Redis部署#

standalone 部署模式区别于传统 Redis Cluster 部署,首先需要借助 NFS 实现多主机 Redis配置和持久化数据共享 借助 Docker Swarm 的故障转移机制来达到 基本的HA

Redis配置共享#

[root@centos-01 ~]# cd /mnt/nfs_file/redis/
[root@centos-01 redis]# ls
redis.conf

备注:redis.conf 需要关闭 Cluster-Enable 

Redis服务部署#

[root@centos-01 ~]# docker service create -p 6379:6379 --name redis --mount type=bind,src=/mnt/nfs_file/redis/redis.conf,dst=/etc/redis/redis.conf --mount type=bind,src=/mnt/nfs_file/redis,dst=/data redis redis-server /etc/redis/redis.conf --appendonly yes
gc4q2nrqwp6qbimjwy3un0lmn
overall progress: 1 out of 1 tasks 
1/1: running   [==================================================>] 
verify: Service converged 

Docker Swarm 会随机选择一个工作节点(这里是 192.168.158.145 )部署 一个Redis容器。

查看运行服务#

[root@centos-01 ~]# docker service ls
ID             NAME      MODE         REPLICAS   IMAGE          PORTS
gc4q2nrqwp6q   redis     replicated   1/1        redis:latest   *:6379->6379/tcp

 查看服务详情#

[root@centos-01 ~]# docker service  ps redis 
ID             NAME      IMAGE          NODE        DESIRED STATE   CURRENT STATE           ERROR     PORTS
zf137g379xj6   redis.1   redis:latest   centos-01   Running         Running 3 minutes ago  

查看服务日志#

[root@centos-01 ~]# docker service logs redis 
redis.1.zf137g379xj6@centos-01    | 1:C 16 Jul 2021 05:46:38.388 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis.1.zf137g379xj6@centos-01    | 1:C 16 Jul 2021 05:46:38.388 # Redis version=6.2.4, bits=64, commit=00000000, modified=0, pid=1, just started
redis.1.zf137g379xj6@centos-01    | 1:C 16 Jul 2021 05:46:38.389 # Configuration loaded
redis.1.zf137g379xj6@centos-01    | 1:M 16 Jul 2021 05:46:38.389 * monotonic clock: POSIX clock_gettime
redis.1.zf137g379xj6@centos-01    | 1:M 16 Jul 2021 05:46:38.391 # Warning: Could not create server TCP listening socket ::1:6379: bind: Cannot assign requested address
redis.1.zf137g379xj6@centos-01    | 1:M 16 Jul 2021 05:46:38.393 * Running mode=standalone, port=6379.
redis.1.zf137g379xj6@centos-01    | 1:M 16 Jul 2021 05:46:38.394 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis.1.zf137g379xj6@centos-01    | 1:M 16 Jul 2021 05:46:38.394 # Server initialized
redis.1.zf137g379xj6@centos-01    | 1:M 16 Jul 2021 05:46:38.394 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
redis.1.zf137g379xj6@centos-01    | 1:M 16 Jul 2021 05:46:38.396 * Ready to accept connections

这里保证只有一个 Redis 容器运行(standalone 部署),所以不需要使用 --replicas number 。 关于服务动态伸缩/服务更新与回滚/滚动更新等相关知识参考:https://www.bookstack.cn/read/docker_practice-v1.1.0/swarm_mode-README.md。

删除服务#

docker service rm redis

测试#

基本功能测试#

使用 RedisClient 连接Redis 192.168.158.146 

故障转移测试#

这里手动将 192.168.158.146 Redis容器停止,查看Swarm会怎么处理

[root@centos-01 ~]# docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS      NAMES
9855ebf35829   redis:latest   "docker-entrypoint.s…"   4 minutes ago   Up 4 minutes   6379/tcp   redis.1.vys54q07u7egrmc64rnn2frj4
[root@centos-01 ~]# docker stop redis.1.vys54q07u7egrmc64rnn2frj4 
redis.1.vys54q07u7egrmc64rnn2frj4
[root@centos-01 ~]# docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS                     PORTS     NAMES
9855ebf35829   redis:latest   "docker-entrypoint.s…"   4 minutes ago   Exited (0) 4 seconds ago             redis.1.vys54q07u7egrmc64rnn2frj4

发现 192.168.158.145 上启动了一个新的Redis容器

[root@centos-01 ~]# docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS         PORTS      NAMES
ef95253a0d79   redis:latest   "docker-entrypoint.s…"   16 seconds ago   Up 9 seconds   6379/tcp   redis.1.jb9b26y4ikj8vc1k04j2gj35w

管理节点中查看服务运行情况

[root@centos-01 ~]# docker service ps redis 
ID             NAME          IMAGE          NODE        DESIRED STATE   CURRENT STATE            ERROR     PORTS
jb9b26y4ikj8   redis.1       redis:latest   centos-01   Running         Running 2 minutes ago              
vys54q07u7eg    \_ redis.1   redis:latest   centos-01   Shutdown        Complete 2 minutes ago  

发现 Redis 已经被转移到了192.168.158.145 使用 RedisClient 连接192.168.158.145 使用 get name 发现可以找到数据,说明Redis容器的数据共享是没问题的。一旦某个节点挂掉,Swarm会自动转移到其他可用的工作节点,结合NFS的文件共享就可以实现Redis独立部署但拥有基本的HA。

Portainer可视化#

192.168.158.1434 管理节点上运行 Portainer 容器。