基于 Swarm 的 Docker 集群管理

基于 Swarm 的 Docker 集群管理

一、Swarm 简介

​ Swarm 是 Docker 的一个编排工具,参考官网:https://docs.docker.com/engine/swarm/

1、Swarm 模式简介

​ 要在 Swarm 模式下运行 docker,需要先安装 docker,参考安装教程

​ 当前版本的 docker 包含了 swarm 模式,用于管理 docker 集群。可以使用命令行来创建 swarm 集群,部署应用,管理 swarm 的行为。

​ 如果你使用低于 1.12.0 版本的 docker,可以使用独立模式的是 swarm,但是建议使用最新版本

2、Swarm 特性

  • 与 docker 集成的集群管理工具
  • 去中心化设计,只使用 docker 引擎即可创建各类节点
  • 声明式服务模型。可以声明的方式来定义应用。
  • 动态伸缩。管理节点自动调整服务数量。
  • 高可用,对于服务期望状态做到动态调整,swarm 的管理节点会持续监控集群状态,集群中有没有达到期望状态的服务,管理节点会自动调度来达到期望状态。
  • 自定义网络。可以为你的服务指定一个网络,容器创建的时候分配一个 IP
  • 服务发现。管理节点给集群中每个服务一个特定的 DNS 名字,并给运行的容器提供负载均衡。
  • 负载均衡。你可以暴露服务端口给外部的负载均衡。内部 swarm 提供可配置的容器分配到节点的策略。
  • 默认的安全机制。swarm 集群中各个节点强制 TLS 协议验证。连接加密,你可以自定义根证书。
  • 滚动更新。增量跟新,可以自定义更新下个节点的时间间隔,如果有问题,可以会滚到上个版本。

3、Swarm 主要概念

(1)开始使用 Swarm 模式

后续文档按如下流程进行:

  • 在 swarm 模式下初始化一个基于 docker 引擎的 swarm 集群
  • 在 swarm 集群中添加节点
  • 部署应用服务到 swarm 集群中
  • 管理 swarm 集群
  • 本教程使用 docker 命令行的方式交互

(2)安装环境要求

  • 准备 3 台主机,3 台可以网络通信的 linux 主机,可以是物理机,虚拟机,云主机,甚至是 docker machine 创建的主机,并且 3 台主机都要安装 docker(docker 版本要大于 1.12.0,安装步骤参考:在 linux 上安装 docker),本例 3 台主机名称分别为:cnkanon-1、cnkanon-2、cnkanon-3
  • 安装 1.12.0 以上的 docker,本例中 docker 版本为:v18.09.6, build 481bc77156
  • 管理节点的 IP 地址
  • 主机之间开放端口

(3)管理节点的 IP 地址

​ 所有 swarm 集群中的节点都能连接到管理节点的 IP 地址。

(4)端口开放

  • 以下端口需要开放

2377/tcp 为集群管理通信

7946/tcp、7946/udp 为节点间通信

4789/udp 为网络间流量

  • 如果你想使用加密网络(–opt encrypted)也需要确保 ip protocol 50 (ESP) 是可用的

二、创建一个 Swarm 集群

完成上面的开始过程后,可以开始创建一个 swarm 集群,确保 docker 的后台应用已经在主机上运行了。

  • 登陆到 cnkanon-1 上,如果使用 docker-machine 创建的主机,要求可以 docker-machine ssh cnkanon-1
  • 运行以下命令来创建一个新的 swarm 集群:
docker swarm init --advertise-addr <MANAGER1-IP>
  • 使用如下命令在 cnkanon-1 上创建 swarm 集群:
[root@cnkanon-1 ~]# docker swarm init --advertise-addr 192.168.56.3
Swarm initialized: current node (82a19cjqf5gvorp2p5jxwhnn6) is now a manager.

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

    docker swarm join --token SWMTKN-1-2if9pe4h2bvnv2izdaqckxsbhxferygh9h9enh7uqpalyi284o-3hp093o5gyb9oimfn4v64zqz1 192.168.56.3:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
  • –advertise-addr 选项表示管理节点公布它的 IP 是多少。其它节点必须能通过这个 IP 找到管理节点。
  • 命令输出了加入 swarm 集群的命令。通过 --token 选项来判断是加入为管理节点还是工作节点

3、运行 docker info 来查看当前 swarm 集群的状态:

[root@cnkanon-1 ~]# docker info
Containers: 8
 Running: 1
 Paused: 0
 Stopped: 7
Images: 5
Server Version: 18.09.6
Storage Driver: overlay2
 Backing Filesystem: xfs
 Supports d_type: true
 Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 Volume: local
 Network: bridge host macvlan null overlay
 Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: active
 NodeID: 82a19cjqf5gvorp2p5jxwhnn6
 Is Manager: true
 ClusterID: 7jmo6jykf14u1lpd90lwinxso
 Managers: 1
 Nodes: 1
 Default Address Pool: 10.0.0.0/8  
 SubnetSize: 24
 Orchestration:
  Task History Retention Limit: 5
 Raft:
  Snapshot Interval: 10000
  Number of Old Snapshots to Retain: 0
  Heartbeat Tick: 1
  Election Tick: 10
 Dispatcher:
  Heartbeat Period: 5 seconds
 CA Configuration:
  Expiry Duration: 3 months
  Force Rotate: 0
 Autolock Managers: false
 Root Rotation In Progress: false
 Node Address: 192.168.56.3
 Manager Addresses:
  192.168.56.3:2377
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: bb71b10fd8f58240ca47fbb579b9d1028eea7c84
runc version: 2b18fe1d885ee5083ef9f0838fee39b62d653e30
init version: fec3683
Security Options:
 seccomp
  Profile: default
Kernel Version: 3.10.0-957.21.2.el7.x86_64
Operating System: CentOS Linux 7 (Core)
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 991.2MiB
Name: cnkanon-1
ID: RZDA:2RQT:Q5M5:HHTW:VTTD:E4GW:ZNHK:E7GI:D6HV:PHFD:NGDZ:TOUE
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
 127.0.0.0/8
Registry Mirrors:
 https://registry.docker-cn.com/
 http://hub-mirror.c.163.com/
 https://docker.mirrors.ustc.edu.cn/
 http://ef017c13.m.daocloud.io/
Live Restore Enabled: false
Product License: Community Engine

WARNING: API is accessible on http://0.0.0.0:2375 without encryption.
         Access to the remote API is equivalent to root access on the host. Refer
         to the 'Docker daemon attack surface' section in the documentation for
         more information: https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface

4、运行 docker node ls 来查看节点信息:

[root@cnkanon-1 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
82a19cjqf5gvorp2p5jxwhnn6 *   cnkanon-1           Ready               Active              Leader              18.09.6
  • nodeId 旁边的 * 号表示你当前连接到的节点
  • docker 引擎的 swarm 模式自动使用宿主机的主机名作为节点名

三、将节点加入到 Swarm 集群

1、找回指令

如果你找不到加入命令了,可以在管理节点运行下列命令找回加入命令:

[root@cnkanon-1 ~]# docker swarm join-token worker
To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-2if9pe4h2bvnv2izdaqckxsbhxferygh9h9enh7uqpalyi284o-3hp093o5gyb9oimfn4v64zqz1 192.168.56.3:2377

2、加入节点到集群

一旦前面的创建 swarm 集群完成,你就可以加入工作节点了。

登录到服务器 cnkanon-2、cnkanon-3,将这两个服务器加入到集群 cnkanon-1

运行如下指令加入到集群中:

# 服务器 cnkanon-2
[root@cnkanon-2 ~]# docker swarm join --token SWMTKN-1-2if9pe4h2bvnv2izdaqckxsbhxferygh9h9enh7uqpalyi284o-3hp093o5gyb9oimfn4v64zqz1 192.168.56.3:2377
This node joined a swarm as a worker.

# 服务器 cnkanon-3
[root@cnkanon-3 ~]# docker swarm join --token SWMTKN-1-2if9pe4h2bvnv2izdaqckxsbhxferygh9h9enh7uqpalyi284o-3hp093o5gyb9oimfn4v64zqz1 192.168.56.3:2377
This node joined a swarm as a worker.

返回服务器 cnkanon-1 管理节点查看集群中节点列表:

[root@cnkanon-1 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
82a19cjqf5gvorp2p5jxwhnn6 *   cnkanon-1           Ready               Active              Leader              18.09.6
a9durycfoospewwyf7gvyoo35     cnkanon-2           Ready               Active                                  18.09.6
s879hzzvfqc9l2ixmj130ved4     cnkanon-3           Ready               Active                                  18.09.6

3、部署服务

创建好 swarm 集群后,就可以部署服务了(也可以不加入工作节点,直接在管理节点单节点上部署服务),回到管理节点 cnkanon-1,基于 portainer/portainer 镜像创建服务:

[root@cnkanon-1 ~]# docker service create --replicas=1 --name=dev-portainer --publish=9000:9000 portainer/portainer
3k2ptlq025amaevlb2zmebsj4
overall progress: 1 out of 1 tasks 
1/1: running   [==================================================>] 
verify: Service converged 

–replicas:表示期望 1 个服务实例

–name:表示创建服务的名称

–publish:表示映射的端口

如果指定的镜像未下载,则系统会自动下载,本例中的 portainer/portainer 镜像是提前下载好的

在管理节点 cnkanon-1 上查看运行的服务:

[root@cnkanon-1 ~]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                        PORTS
3k2ptlq025am        dev-portainer       replicated          1/1                 portainer/portainer:latest   *:9000->9000/tcp

4、查看服务详情

在管理节点 cnkanon-1 上运行如下命令查看服务详情

[root@cnkanon-1 ~]# docker service inspect dev-portainer --pretty
ID:             3k2ptlq025amaevlb2zmebsj4
Name:           dev-portainer
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:         portainer/portainer:latest@sha256:cc226d8a06b6d5e24b44a4f10d0d1fd701741e84a852adc6d40bef9424a000ec
 Init:          false
Resources:
Endpoint Mode:  vip
Ports:
 PublishedPort = 9000
  Protocol = tcp
  TargetPort = 9000
  PublishMode = ingress 

–pretty:表示以 yaml 格式显示,不加此参数将以 json 格式显示

5、查看服务运行在哪个节点

在管理节点 cnkanon-1 上运行指令查看 dev-portainer 服务运行在 swarm 集群中的哪个节点:

[root@cnkanon-1 ~]# docker service ps dev-portainer 
ID           NAME                 IMAGE                       NODE       DESIRED STATE  CURRENT STATE           ERROR                       PORTS
ei18defdqie6 dev-portainer.1      portainer/portainer:latest  cnkanon-1  Running        Running 4 minutes ago                            
in1rwx6g63kd  \_ dev-portainer.1  portainer/portainer:latest  cnkanon-1  Shutdown       Failed 4 minutes ago    "task: non-zero exit (1)" 

服务可能运行在管理或工作节点上,默认的管理节点可以像工作节点一样运行任务

该命令也显示服务期望的状态 DESIRED STATE,和实际的状态 CURRENT STATE

6、在 swarm 集群中动态伸缩服务实例数

一旦你在 swarm 集群中创建一个服务后,你就可以使用命令来改变服务的实例个数。在服务中运行的容器称为 “任务”。

在管理节点 cnkanon-1 中执行如下指令将 dev-portainer 的实例个数变为 3 个:

[root@cnkanon-1 ~]# docker service scale dev-portainer=3
dev-portainer scaled to 3
overall progress: 3 out of 3 tasks 
1/3: running   [==================================================>] 
2/3: running   [==================================================>] 
3/3: running   [==================================================>] 
verify: Service converged 

scale S E R V I C E N A M E / {SERVICE_NAME}/SERVICENAME/{SERVICE_ID} = n:伸缩服务的实例为指定个数

在管理节点 cnkanon-1 上查看服务 dev-portainer 的运行情况及实例个数:

# 查看服务运行情况
[root@cnkanon-1 ~]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                        PORTS
3k2ptlq025am        dev-portainer       replicated          3/3                 portainer/portainer:latest   *:9000->9000/tcp

# 查看服务运行的实例个数
[root@cnkanon-1 ~]# docker service ps dev-portainer 
ID            NAME             IMAGE                       NODE       DESIRED STATE  CURRENT STATE                ERROR         PORTS
rugy9x8je284  dev-portainer.1  portainer/portainer:latest  cnkanon-1  Running        Running about a minute ago                      
1a5hyn0g23c8  dev-portainer.2  portainer/portainer:latest  cnkanon-3  Running        Running 4 minutes ago                           
tjgi9ptunfg8  dev-portainer.3  portainer/portainer:latest  cnkanon-2  Running        Running 4 minutes ago                            

可以看出,dev-portainer 服务运行情况中,REPLICAS=3 表示服务运行实例已扩展为 3 个

dev-portainer 服务的运行节点 NODE 有 cnkanon-1、cnkanon-2、cnkanon-3,共 3 个节点

现在分别登录工作节点 cnkanon-2、cnkanon-3 查看服务 dev-portainer 的运行情况:

# 工作节点 cnkanon-2
[root@cnkanon-2 ~]# docker ps
CONTAINER ID        IMAGE                        COMMAND             CREATED             STATUS              PORTS               NAMES
a91f1c529425        portainer/portainer:latest   "/portainer"        3 minutes ago       Up 3 minutes        9000/tcp            dev-portainer.3.va0p1mllzqnte3cghnbp19mk6

# 工作节点 cnkanon-3
[root@cnkanon-3 ~]# docker ps
CONTAINER ID        IMAGE                        COMMAND             CREATED             STATUS              PORTS               NAMES
e69063554d71        portainer/portainer:latest   "/portainer"        3 minutes ago       Up 3 minutes        9000/tcp            dev-portainer.2.ene51pt4kpqtq7czpduqrmn9w

可以看到,dev-portainer.3 运行在工作节点 cnkanon-2 上,dev-portainer.2 运行在工作节点 cnkanon-3 上。

在管理节点 cnkanon-1 中尝试将 dev-portainer 的实例个数变为 2 个,会发现并不会动态删除第 3 个节点上的容器,只是停止第 3 个容器:

# 在管理节点 cnkanon-1 上将 dev-portainer 的运行实例缩放到2个节点
[root@cnkanon-1 ~]# docker service scale dev-portainer=2
dev-portainer scaled to 2
overall progress: 2 out of 2 tasks 
1/2: running   [==================================================>] 
2/2: running   [==================================================>] 
verify: Service converged 

# 在管理节点 cnkanon-1 上查看 dev-portainer 运行情况
[root@cnkanon-1 ~]# docker service ps dev-portainer 
ID            NAME             IMAGE                       NODE       DESIRED STATE  CURRENT STATE              ERROR         PORTS
rugy9x8je284  dev-portainer.1  portainer/portainer:latest  cnkanon-1  Running        Running about a minute ago                      
1a5hyn0g23c8  dev-portainer.2  portainer/portainer:latest  cnkanon-3  Running        Running 4 minutes ago                           
tjgi9ptunfg8  dev-portainer.3  portainer/portainer:latest  cnkanon-2  Shutdown       Failed 3 minutes ago       "task: non-zero exit (1)"

# 登录工作节点 cnkanon-2 查看 dev-portainer 已不在运行
[root@cnkanon-2 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAME

7、从 swarm 集群中删除服务

在管理节点 cnkanon-1 中删除 dev-portainer:

[root@cnkanon-1 ~]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                        PORTS
3k2ptlq025am        dev-portainer       replicated          2/2                 portainer/portainer:latest   *:9000->9000/tcp
[root@cnkanon-1 ~]# docker service rm dev-portainer 
dev-portainer
[root@cnkanon-1 ~]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
[root@cnkanon-1 ~]# docker service ps dev-portainer 
no such service: dev-portainer
[root@cnkanon-1 ~]# docker service inspect dev-portainer
[]
Status: Error: no such service: dev-portainer, Code: 1

尽管服务不存在了,任务容器还需要几秒钟来清理,你可以在工作节点 cnkanon-2、cnkanon-3 上 docker ps 查看任务什么时候被移除。

8、更新、回滚服务

swarm 集群有一项非常重要的功能:对服务进行滚动更新、滚动回滚以及对服务资源配置进行更新。

(1)更新服务资源配置

(2)滚动更新服务

在 swarm 集群中可以对服务的版本进行升级,此例中以 nginx:1.16.0 版本为例,先基于 nginx:1.16.0 创建服务,设置 replicas=3,创建 3 个实例运行来运行,再将服务升级到 nginx:1.17 版本:

# 先下载 nginx:1.16.0 镜像
[root@cnkanon-1 ~]# docker pull nginx:1.16.0
# 创建服务,并指定实例数为3
[root@cnkanon-1 ~]# docker service create --replicas=3 --name=dev-nginx --publish=80:80 nginx:1.16.0

# 查看服务版本为 nginx:1.16.0
[root@cnkanon-1 ~]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                          PORTS
uyqnphtca0lx        dev-nginx           replicated          3/3                 nginx:1.16.0                   *:80->80/tcp  

现在将 nginx:1.16.0 版本升级到 nginx:1.17.0 版本:

# 更新版本到 nginx:1.17.0
[root@cnkanon-1 ~]# docker service update --image nginx:1.17 dev-nginx
dev-nginx
overall progress: 3 out of 3 tasks 
1/3: running   [==================================================>] 
2/3: running   [==================================================>] 
3/3: running   [==================================================>] 
verify: Service converged

# 查看服务版本为 nginx:1.17.0
[root@cnkanon-1 ~]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                        PORTS
uyqnphtca0lx        dev-nginx           replicated          3/3                 nginx:1.17                   *:80->80/tcp

# 查看服务运行情况,版本为 nginx:1.17.0
[root@cnkanon-1 ~]# docker service ps dev-nginx 
ID             NAME            IMAGE         NODE         DESIRED STATE       CURRENT STATE                 ERROR               PORTS
3zstw4g8a3vg   dev-nginx.1     nginx:1.17    cnkanon-2    Running             Running about a minute ago                        
hug1u1seuzwg   \_ dev-nginx.1  nginx:1.16.0  cnkanon-2    Shutdown            Shutdown 2 minutes ago                            
9av4gh54tk3o   dev-nginx.2     nginx:1.17    cnkanon-3    Running             Running 54 seconds ago                            
63ajbftz8dp3   \_ dev-nginx.2  nginx:1.16.0  cnkanon-3    Shutdown            Shutdown about a minute ago                       
spzalsgvt7w8   dev-nginx.3     nginx:1.17    cnkanon-1    Running             Running about a minute ago                        
y3wyuqq06ldy   \_ dev-nginx.3  nginx:1.16.0  cnkanon-1    Shutdown            Shutdown about a minute ago       

调度器 scheduler 依照以下步骤来滚动更新:

  • 停止第一个任务
  • 对停止的任务进行更新
  • 对更新的任务进行启动
  • 如果更新的任务返回 RUNNING,等待特定间隔后启动下一个任务
  • 如果在任何更新的时间,任务返回了 FAILED,则停止更新。

可以看出执行更新指令后,并未将 nginx:1.16.0 版本删除,而是停止了并且新创建了 nginx:1.17 版本的服务

同时可以指定相应参数来制定滚动更新策略:

  • –update-delay:配置更新服务的时间间隔,可以指定时间 T 为秒是 Ts,分是 Tm,或时是 Th,所以 10m30s 就是 10 分 30 秒的延迟
  • 默认的调度器 scheduler 一次更新一个任务,使用参数 --update-parallelism 来配置调度器同时更新的最大任务数量
  • 默认的当一个更新任务返回 RUNNING 状态后,调度器才调度另一个更新任务,直到所有任务都更新了。如果更新过程中任何任务返回了 FAILED,调度器就会停止更新。可以给命令 docker service create or docker service update 配置配置 --update-failure-action,来设置这个行为。

(3)回滚更新服务

将上述更新到 nginx:1.17.0 版本的服务回滚到 nginx:1.16.0 版本,其滚动回滚的原理和滚动更新类似,并不会删除 nginx:1.17.0 服务,只是停止,也不会重启之前的 nginx:1.16.0 版本的服务,而是直接再创建一个 nginx:1.16.0 版本的服务:

# 执行回滚
[root@cnkanon-1 ~]# docker service update --rollback dev-nginx
dev-nginx
rollback: manually requested rollback 
overall progress: rolling back update: 3 out of 3 tasks 
1/3: running   [>                                                  ] 
2/3: running   [>                                                  ] 
3/3: running   [>                                                  ] 
verify: Service converged 

# 查看服务运行情况,running状态的版本为 nginx:1.16.0,停止状态的版本为 nginx:1.16.0、nginx:1.17.0
[root@cnkanon-1 ~]# docker service ps dev-nginx
ID            NAME                IMAGE          NODE        DESIRED STATE       CURRENT STATE                 ERROR               PORTS
0jlkh0ci9r42  dev-nginx.1         nginx:1.16.0   cnkanon-2   Running             Running about a minute ago                        
3zstw4g8a3vg  \_ dev-nginx.1      nginx:1.17     cnkanon-2   Shutdown            Shutdown about a minute ago                       
hug1u1seuzwg  \_ dev-nginx.1      nginx:1.16.0   cnkanon-2   Shutdown            Shutdown 13 minutes ago                           
54sciwitz0he  dev-nginx.2         nginx:1.16.0   cnkanon-3   Running             Running about a minute ago                        
9av4gh54tk3o  \_ dev-nginx.2      nginx:1.17     cnkanon-3   Shutdown            Shutdown about a minute ago                       
63ajbftz8dp3  \_ dev-nginx.2      nginx:1.16.0   cnkanon-3   Shutdown            Shutdown 12 minutes ago                           
spzalsgvt7w8  dev-nginx.3         nginx:1.17     cnkanon-1   Shutdown            Shutdown about a minute ago                       
y3wyuqq06ldy  \_ dev-nginx.3      nginx:1.16.0   cnkanon-1   Shutdown            Shutdown 13 minutes ago  

9、从 swarm 集群中下线一个节点

  • 前面的教程中管理节点会把任务分配给 ACTIVE 的节点,所有 ACTIVE 的节点都能接到任务
  • 有时候,例如特定的维护时间,我们就需要从集群中下线一个节点。下线节点使节点不会接受新任务,管理节点会停止该节点上的任务,分配到别的 ACTIVE 的节点上。

注意:下线一个节点不移除节点中的独立容器,如 docker run,docker-compose up、docker api 启动的容器都不会删除。节点的状态仅影响集群服务的负载是否分到该节点。

# swarm 集群中3个节点都牌 ACTIVE 状态
[root@cnkanon-1 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
82a19cjqf5gvorp2p5jxwhnn6 *   cnkanon-1           Ready               Active              Leader              18.09.6
a9durycfoospewwyf7gvyoo35     cnkanon-2           Ready               Active                                  18.09.6
s879hzzvfqc9l2ixmj130ved4     cnkanon-3           Ready               Active                                  18.09.6

# swarm 集群中有一个服务 nginx:1.16.0 在2个节点运行
[root@cnkanon-1 ~]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                        PORTS
uyqnphtca0lx        dev-nginx           replicated          2/2                 nginx:1.16.0                 *:80->80/tcp

# nginx:1.16.0 服务分别运行在节点 cnkanon-2、cnkanon-3 上
[root@cnkanon-1 ~]# docker service ps dev-nginx
ID            NAME                IMAGE          NODE        DESIRED STATE       CURRENT STATE                 ERROR               PORTS
0jlkh0ci9r42  dev-nginx.1         nginx:1.16.0   cnkanon-2   Running             Running about a minute ago                        
3zstw4g8a3vg  \_ dev-nginx.1      nginx:1.17     cnkanon-2   Shutdown            Shutdown about a minute ago                       
hug1u1seuzwg  \_ dev-nginx.1      nginx:1.16.0   cnkanon-2   Shutdown            Shutdown 13 minutes ago                           
54sciwitz0he  dev-nginx.2         nginx:1.16.0   cnkanon-3   Running             Running about a minute ago                        
9av4gh54tk3o  \_ dev-nginx.2      nginx:1.17     cnkanon-3   Shutdown            Shutdown about a minute ago                       
63ajbftz8dp3  \_ dev-nginx.2      nginx:1.16.0   cnkanon-3   Shutdown            Shutdown 12 minutes ago                           
spzalsgvt7w8  dev-nginx.3         nginx:1.17     cnkanon-1   Shutdown            Shutdown about a minute ago                       
y3wyuqq06ldy  \_ dev-nginx.3      nginx:1.16.0   cnkanon-1   Shutdown            Shutdown 13 minutes ago  

将节点 cnkanon-3 下线:

# 更新节点 cnkanon-3 的状态为 DRAIN
[root@cnkanon-1 ~]# docker node update --availability drain cnkanon-3
cnkanon-3

# swarm 集群中节点 cnkanon-3 状态已变为 DRAIN
[root@cnkanon-1 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
82a19cjqf5gvorp2p5jxwhnn6 *   cnkanon-1           Ready               Active              Leader              18.09.6
a9durycfoospewwyf7gvyoo35     cnkanon-2           Ready               Active                                  18.09.6
s879hzzvfqc9l2ixmj130ved4     cnkanon-3           Ready               Drain                                   18.09.6

# 服务 nginx:1.16.0 依旧在2个节点运行,但已经从 cnkanon-3 切换到了 cnkanon-1
[root@cnkanon-1 ~]# docker service ps dev-nginx
ID            NAME             IMAGE          NODE          DESIRED STATE       CURRENT STATE                 ERROR               PORTS
0jlkh0ci9r42  dev-nginx.1      nginx:1.16.0   cnkanon-2     Running             Running 6 hours ago                               
3zstw4g8a3vg  \_ dev-nginx.1   nginx:1.17     cnkanon-2     Shutdown            Shutdown 6 hours ago                              
hug1u1seuzwg  \_ dev-nginx.1   nginx:1.16.0   cnkanon-2     Shutdown            Shutdown 6 hours ago                              
9esjmlrua9hv  dev-nginx.2      nginx:1.16.0   cnkanon-1     Running             Running about a minute ago                        
54sciwitz0he  \_ dev-nginx.2   nginx:1.16.0   cnkanon-3     Shutdown            Shutdown about a minute ago                       
9av4gh54tk3o  \_ dev-nginx.2   nginx:1.17     cnkanon-3     Shutdown            Shutdown 6 hours ago                              
63ajbftz8dp3  \_ dev-nginx.2   nginx:1.16.0   cnkanon-3     Shutdown            Shutdown 6 hours ago                              
spzalsgvt7w8  dev-nginx.3      nginx:1.17     cnkanon-1     Shutdown            Shutdown 6 hours ago                              
y3wyuqq06ldy  \_ dev-nginx.3   nginx:1.16.0   cnkanon-1     Shutdown            Shutdown 6 hours ago 
  • 当节点重新 active 的时候,在以下情况下它会重新接受任务:
  • 当一个服务缩容扩容时
  • 在滚动更新的时候
  • 当另一个节点 Drain 下线的时候
  • 当一个任务在另一个 active 节点上运行失败的时候

10、swarm 集群中的路由网络

  • docker 的 swarm 模式使服务暴露给外部端口更加方便。所有的节点都在一个路由网络里。这个路由网络使得集群内的所有节点都能在开放的端口上接受请求。即使节点上没有任务运行,这个服务的端口也暴露的。路由网络路由所有的请求到暴露端口的节点上。
  • 前提是需要暴露以下端口来使节点间能通信
    • 7946/tcp、7946/udp 用于容器间网络发现
    • 4789/udp 用于容器进入网络
  • 你也必须开放节点之间的公开端口,和任何外部资源端口,例如一个外部的负载均衡
  • 你也可以使特定服务绕过路由网络

(1)创建服务时暴露端口

  • 使用 --publish 来在创建一个服务的时候暴露端口。target 指明容器内暴露的端口。published 指明绑定到路由网络上的端口。如果不写 published,就会为每个服务绑定一个随机的高数字端口。你需要检查任务才能确定端口
docker service create --name=dev-nginx --publish=published=8080,target=80 --replicas=1 nginx:1.16.0

注意旧版的语法是冒号分开的 published:target,例如 -p 8080:80。新语法更易读且灵活。

当你在任何节点访问 8080 端口时,路由网络将把请求分发到一个 active 的容器中。在各个节点,8080 端口可能并没有绑定,但是路由网络知道如何路由流量,并防止任何端口冲突。

路由网络监听各个节点的 IP 上的 published port 。从外面看,这些端口是各个节点暴露的。对于别的 IP 地址,只在该主机内可以访问。

在这里插入图片描述

(2)对已存在服务暴露端口

  • 也可以用以下命令给一个已经存在的服务暴露端口
docker service update --publish-add published=8080,target=80 dev-nginx

# 查看暴露端口情况
docker service inspect --format="{{json .Endpoint.Spec.Ports}}" dev-nginx
[{"Protocol":"tcp","TargetPort":80,"PublishedPort":8080,"PublishMode":"ingress"}]

(3)仅暴露一个 tcp/udp 端口

  • 默认你暴露的端口都是 tcp 的。如果你使用长语法(Docker 1.13 and higher),设置 protocol 为 tcp 或 udp 即可暴露相应协议的端口
# 仅暴露 tcp 端口
# 长语法
docker service create --name=dev-nginx dns-cache --publish=published=8080,target=80 dns-cache
# 短语法
docker service create --name=dev-nginx dns-cache -p 53:53 dns-cache

# 暴露 tcp和udp 端口
# 长语法
docker service create --name=dev-nginx dns-cache --publish=published=8080,target=80 --publish=published=6379,target=6379,protocol=udp dns-cache
# 短语法
docker service create --name=dev-nginx dns-cache -p 53:53 -p 53:53/udp dns-cache

# 仅暴露 udp 端口
# 长语法
docker service create --name=dev-nginx dns-cache --publish=published=8080,target=80,protocol=udp dns-cache
#短语法
docker service create --name=dev-nginx dns-cache -p 53:53/udp dns-cache

(4)绕过路由网络

  • 你可以绕过路由网络,直接和一个节点上的端口通信,来访问服务。这叫做 Host 模式:

如果该节点上没有服务运行,服务也没有监听端口,则可能无法通信。

你不能在一个节点上运行多个服务实例他们绑定同一个静态 target 端口。或者你让 docker 分配随机高数字端口(通过空配置 target),或者确保该节点上只运行一个服务实例(通过配置全局服务 global service 而不是副本服务,或者使用配置限制)。

  • 为了绕过路由网络,必须使用长格式–publish,设置模式 mode 为 host 模式。如果你忽略了 mode 设置或者设置为内网 ingress,则路由网络将启动。下面的命令创建了全局应用使用 host 模式绕过路由网络:
docker service create --name=dev-nginx dns-cache --publish=published=8080,target=80,protocol=udp,mode=host --mode global dns-cache

(5)配置外部负载均衡

可以为 swarm 集群配置外部的负载均衡,或者结合路由网络使用或者完全不使用

  • 使用路由网络

使用一个外部的 HAProxy 来负载均衡,服务是 8080 端口上的 nginx 服务

在这里插入图片描述

上图中负载均衡和集群节点之间的 8080 端口必须是开放的。swarm 集群节点在一个外部不可访问的内网中,节点可以与 HAProxy 通信。

可以配置负载均衡分流请求到不同的集群节点,即使节点上没有服务运行

当请求 HAProxy 的 80 端口的时候,它会转发请求到后端节点。swarm 的路由网络会路由到相应的服务节点。这样无论任何原因 swarm 的调度器调度服务到不同节点,都不需要重新配置负载均衡。

可以配置任何类型的负载均衡来分流请求。

  • 不使用路由网络

如果不使用路由网络,配置 --endpoint-mode 的值为 dnsrr,而不是 vip。在本例子中没有一个固定的虚拟 IP。Docker 为服务做了 DNS 注册,这样一个服务的 DNS 查询会返回一系列 IP 地址。客户端就可以直接连接其中一个节点。你负责提供这一系列的 IP 地址,开放端口给你的负载均衡器。参考 Configure service discovery.

Swarm 和 Kubernetes(K8s)的主要区别在于它们的复杂性、可伸缩性、自动伸缩、负载均衡、滚动更新回滚、数据共享、日志记录和监控能力。12

  • 安装和部署:Swarm 的安装过程相对简单,但集群功能不如 K8s 强大;K8s 的安装过程较为复杂,但一旦安装完成,其集群功能非常强大。

  • 图形用户界面:K8s 提供了图形用户界面,而 Swarm 则没有。

  • 可伸缩性:Swarm 在可伸缩性方面比 K8s 快 5 倍。

  • 自动伸缩:K8s 支持自动伸缩,而 Swarm 则不支持。

  • 负载均衡:K8s 在不同 Pods 中的不同容器之间平衡负载流量,需要手动干预;Swarm 可以自动平衡集群中容器之间的流量。

  • 滚动更新回滚:K8s 支持滚动更新和回滚,而 Swarm 可以部署滚动更新,但不能自动回滚。

  • 数据共享:K8s 可以共享存储卷,但只能与同一 Pod 中的其他集装箱共享;Swarm 可以与任何其他容器共享存储卷。

  • 日志记录和监控:K8s 内置了日志和监控工具,而 Swarm 则需要使用第三方工具进行日志记录和监控。

总的来说,Swarm 更适合小规模容器集群的管理,因为它更加简单易用;而 K8s 则更适合大规模高可用性容器集群的管理,虽然其安装和部署过程相对复杂,但提供了更强大的功能和灵活性。选择使用哪种工具取决于具体的需求和场景。

 

posted @ 2024-07-01 14:06  CharyGao  阅读(47)  评论(0编辑  收藏  举报