Docker Swarm 说明及基础教程

Docker Swarm 简介

Swarm 在 Docker 1.12 版本之前属于一个独立的项目,在 Docker 1.12 版本发布之后,该项目合并到了 Docker 中,成为 Docker 的一个子命令。目前,Swarm 是 Docker 社区提供的唯一一个原生支持 Docker 集群管理的工具。它可以把多个 Docker 主机组成的系统转换为单一的虚拟 Docker 主机,使得容器可以组成跨主机的子网网络。

Docker Swarm 是一个为 IT 运维团队提供集群和调度能力的编排工具。用户可以把集群中所有 Docker Engine 整合进一个「虚拟 Engine」的资源池,通过执行命令与单一的主 Swarm 进行沟通,而不必分别和每个 Docker Engine 沟通。在灵活的调度策略下,IT 团队可以更好地管理可用的主机资源,保证应用容器的高效运行。

Docker Swarm 内部构造

节点(nodes)

Docker Swarm 中有两种节点,ManagerWorker。如下图所示。

管理节点(Manager)

管理节点主要处理集群管理任务:

  • 维护节点状态
  • 调度服务
  • 提供集群服务HTTP API 接口

在容错性方面,提供了多管理节点容错能力,官方建议使用奇数管理节点,从而实现故障恢复不停机。

多个管理节点时,只有一个管理节点可以成为 leader,选举通过raft 协议实现.

  • 三个管理节点集群最多可以容忍同时一个节点故障
  • 五个管理节点集群最多可以容忍同时两个节点故障
  • N个管理节点集群最多可以容忍同时*(N-1)/2个节点故障
  • 官方建议集群管理节点最多7个

工作节点(Worker)

工作节点也就是具体执行任务的节点,管理节点默认也是工作节点,管理节点将服务(service)下发到工作节点。

默认情况下服务根据情况自动分发到工作节点,当然可以通过标签的形式将服务固定运行在指定工作节点(可以为多个)上。

角色更换

如果你已经搭建好集群,因为某些原因,需要将工作节点转换为管理节点。通过docker node promote 实现。

服务(Services)

任务、服务、容器

在Docker Swarm中,部署应用通过服务的形式进行部署,管理节点通过将服务拆分为一项或者多项任务,通过工作节点进行任务的执行,而任务又通过创建并运行容器实现具体执行。

一个任务只能调用一个容器(容器可理解为任务的实例),当容器处于活动状态时,调度程序将设置对应任务为运行状态,反之亦然。

在部署服务时,可以对服务进行一些选项配置:

  • 服务对外提供的端口映射
  • 服务使用其他服务的覆盖网络(服务间网络打通)
  • CPU 与 内存的限制
  • 滚动更新策略
  • 服务运行的副本数量

例如如果需要部署一个拥有三个副本的nginx 服务,具体分布如下图所示:

任务(Task)与调度(scheduling)

Docker Swarm 内部逻辑主要通过调度器(scheduler) 与协调器(orchestrator) 完成。

任务是Swarm集群内调度的基本单元。当你创建或者更新服务之后,协调器读取服务所需要的状态(如:你创建一个需要运行三个实例的nginx服务),然后通过调度任务实现服务所需的状态。当任务失败时,协调器(orchestrator)将会删除任务及其容器,然后根据服务的条件创建新的任务来进行替换。

下图为创建服务到最终执行示意图:

service-lifecycle

复制服务(Replicated)与全局服务(global)

服务的部署可以有两种类型: 复制服务、全局服务。

  • replicated services (复制服务) 按照一定规则在各个工作节点上运行指定个数的任务。
  • global services (全局服务)每个工作节点上运行一个任务。

下图所示:(黄色为复制服务、灰色为全局服务)

调度策略

服务创建之后,管理节点会根据指定的策略来计算合适运行容器的节点.

  • Random 随机选择节点,常用于调试
  • Spread (默认策略) 选择运行容器最少的节点运行新容器,从而实现集群容器的均衡
  • Binpack 尽可能把容器运行在一个节点上,避免容器碎片化,把成块的大空间留给需要大空间的容器运行

网络(network)

Docker Swarm 节点间通讯由docker 的网络组件支持。

Docker 网络有如下模式:

  • bridge(桥接模式) 默认的网络模式,一般在多个容器间通讯使用该模式
  • host(主机模式) Docker使用的网络实际上和宿主机一样,在容器内看到的网卡ip是宿主机上的ip
  • overlay(叠加网络) 开箱即用地创建了一个支持多主机网络的叠加网络,它结合使用了本地Linux桥接器和VXLAN,以叠加物理网络基础结构上的容器到容器通信。
  • macvlan 将容器直接联通到物理网络或VLAN中,相当于虚拟机中的桥接模式
  • none 这种模式下不会配置任何网络,与世隔绝
  • Network plugins 第三方网络插件,通常不使用

桥接模式(bridge)

Docker默认使用的网络模式(Linux安装的Docker情况下),当启动容器时,默认情况如下图所示:

 

当用户自定义桥接网络时,如下图所示:

docker network create -d bridge --subnet 10.0.0.0/24 my_bridge

主机模式(host)

当使用主机模式时,容器与主机共用网络地址,如下图所示:

叠加网络(overlay)

主要应用于Docker Swarm中,处理集群中多主机中容器间通讯。其核心原理如下图所示:

叠加网络内部结构如下图所示:

外部访问

由于叠加网络相当于自建了一套独立的网络,无法直接访问。该模式下提供两种端口发布模式。

  • host mode 主机模式 端口发布仅在运行特定服务任务的主机上公开端口。
  • ingress mode 入口模式 适用于具有多个副本且要求这些副本之间进行负载平衡的服务。

下图为两种模式示意图:

MACVLAN

该模式类似于虚拟机中的桥接模式,使容器实现如独立主机一样进行网络注册,如下图所示:

None

本模式实现容器与其他容器和主机的完全隔离,该容器只包含一个回环网络且没有其他任何接口。

存储

Docker 本身不提供单机卷挂载以外的存储服务,集群情况下,需要三方解决方案支持。

传统方案
  • NAS
  • SAN
存储服务
  • Trident from NetApp
  • HPE Nimble
  • Nutanix DVP
  • Pure Storage
  • vSphere Storage
  • DataCore SDS
  • NexentaEdge
  • BlockBridge

Docker Swarm 实践

通过以下活动了解Swarm:

  • 初始化集群
  • 向集群添加节点
  • 部署应用服务到集群
  • 管理集群服务

Docker Swarm基础要求:

  • Docker 版本大于1.12
  • 主机间端口开放(TCP:2377 UDP: 4789 TCP/UDP:7946)

默认每台主机已经安装好docker.

初始化集群

背景

示例中使用如下主机。

序号 主机名称 ip地址
1 manager1 192.168.99.100
2 worker1 192.168.99.101
3 Worker2 192.168.99.102

初始化

通过如下命令进行Docker Swarm集群初始化操作。

docker swarm init --advertise-addr <MANAGER-IP>
  • –advertise-addr 只用于主机多网络情况,如果你本机单网卡,可此忽略参数。

在主节点(管理节点)进行集群创建,执行如下命令:

$ docker swarm init --advertise-addr 192.168.99.100
Swarm initialized: current node (dxn1zf6l61qsb1josjja83ngz) is now a manager.

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

    docker swarm join \
    --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
    192.168.99.100:2377

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

查看节点

在管理节点执行如下命令查看节点状态:

$ docker node ls

ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
dxn1zf6l61qsb1josjja83ngz *  manager1  Ready   Active        Leader

集群添加节点

根据上述得到添加工作节点(worker)的命令,则在工作节点上执行:

$ docker swarm join \
  --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
  192.168.99.100:2377

This node joined a swarm as a worker.

获取加入节点命令

获取加入worker节点的命令,只需在管理节点执行:

$ docker swarm join-token worker
To add a worker to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
    192.168.99.100:2377

获取加入manager节点的命令,只需在管理节点执行:

$ docker swarm join-token manager
To add a manager to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-73ylv430dj8d2d9y9c6rqs9e3 \
    192.168.99.100:2377

节点查看

当所有工作节点执行JOIN命令之后,在管理节点查看节点状态:

$ docker node ls
ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
03g1y59jwfg7cf99w4lt0f662    worker2   Ready   Active
9j68exjopxe7wfl6yuxml7a7j    worker1   Ready   Active
dxn1zf6l61qsb1josjja83ngz *  manager1  Ready   Active        Leader

到此,一个单管理节点,3个工作节点集群搭建完成。

部署应用服务到集群

集群搭建完成之后,则可以部署服务到集群之中.

  • 管理相关操作只能在管理节点执行。

执行以下命令部署第一个应用服务:

$ docker service create --replicas 1 --name helloworld alpine ping baidu.com

9uk4639qpg7npwf3fn2aasksr
  • docker service create 创建服务
  • —name 指定服务名称
  • —replicas 副本实例个数

查看服务

服务在创建之后,通过如下命令进行查看:

$ docker service ls

ID            NAME        SCALE  IMAGE   COMMAND
9uk4639qpg7n  helloworld  1/1    alpine  ping baidu.com

管理集群服务

在整个的过程中,可以通过以下过程对集群中服务进行管理。

  • 查看服务
  • 服务伸缩
  • 删除服务
  • 滚动更新策略
  • 排除节点
  • 网络

查看服务

当服务创建之后,通过以下命令查看服务的详细信息。

$ docker service inspect --pretty helloworld

ID:		9uk4639qpg7npwf3fn2aasksr
Name:		helloworld
Service Mode:	REPLICATED
 Replicas:		1
Placement:
UpdateConfig:
 Parallelism:	1
ContainerSpec:
 Image:		alpine
 Args:	ping baidu.com
Resources:
Endpoint Mode:  vip

通过以下命令查看服务在哪些节点运行。

$ docker service ps helloworld

NAME                                    IMAGE   NODE     DESIRED STATE  CURRENT STATE           ERROR               PORTS
helloworld.1.8p1vev3fq5zm0mi8g0as41w35  alpine  worker2  Running        Running 3 minutes

根据上面的结果可以知道具体的任务运行在worker2,则可以在worker2上通过docker ps查看相关容器的具体信息。

服务伸缩

服务部署之后,可以通过docker service scale <SERVICE-ID>=<NUMBER-OF-TASKS>命令进行服务伸缩。

例如将helloworld执行5个副本:

$ docker service scale helloworld=5

helloworld scaled to 5

然后在通过docker service ps查看具体任务列表。

$ docker service ps helloworld

NAME                                    IMAGE   NODE      DESIRED STATE  CURRENT STATE
helloworld.1.8p1vev3fq5zm0mi8g0as41w35  alpine  worker2   Running        Running 7 minutes
helloworld.2.c7a7tcdq5s0uk3qr88mf8xco6  alpine  worker1   Running        Running 24 seconds
helloworld.3.6crl09vdcalvtfehfh69ogfb1  alpine  worker1   Running        Running 24 seconds
helloworld.4.auky6trawmdlcne8ad8phb0f1  alpine  manager1  Running        Running 24 seconds
helloworld.5.ba19kca06l18zujfwxyc5lkyn  alpine  worker2   Running        Running 24 seconds

删除服务

通过docker service rm可以将服务删除。由于集群模式,具体任务的删除可能有一定延迟。

$ docker service rm helloworld

helloworld

删除之后,通过docker service inspect <SERVICE-ID>检查是否已经正确删除。

$ docker service inspect helloworld
[]
Error: no such service: helloworld

滚动更新策略

很多场景需要定期更新相关的应用,滚动更新则足矣胜任该工作。

$ docker service create \
  --replicas 3 \
  --name redis \
  --update-delay 10s \
  redis:3.0.6

0u6a4s31ybk7yw2wyvtikmu50

–update-delay 配置两次更新服务任务或一组任务之间的时间延迟。

查看redis服务详细信息。

$ docker service inspect --pretty redis

ID:             0u6a4s31ybk7yw2wyvtikmu50
Name:           redis
Service Mode:   Replicated
 Replicas:      3
Placement:
 Strategy:	    Spread
UpdateConfig:
 Parallelism:   1
 Delay:         10s
ContainerSpec:
 Image:         redis:3.0.6
Resources:
Endpoint Mode:  vip

执行如下命令更新服务。

$ docker service update --image redis:3.0.7 redis
redis

调度程序会按如下步骤进行滚动更新:

  • 停止第一个任务
  • 更新已停止的任务
  • 启动已更新任务的容器
  • 如果更新任务的状态返回为:RUNNING ,则等待指定的延迟时间后继续执行下一个任务更新
  • 如果在更新过程中,任意任务返回FAILED状态,则暂停更新

执行更新之后,通过以下命令检查服务状态信息。

$ docker service inspect --pretty redis

ID:             0u6a4s31ybk7yw2wyvtikmu50
Name:           redis
Service Mode:   Replicated
 Replicas:      3
Placement:
 Strategy:	    Spread
UpdateConfig:
 Parallelism:   1
 Delay:         10s
ContainerSpec:
 Image:         redis:3.0.7
Resources:
Endpoint Mode:  vip

如果更新失败,则返回以下信息:

$ docker service inspect --pretty redis

ID:             0u6a4s31ybk7yw2wyvtikmu50
Name:           redis
...snip...
Update status:
 State:      paused
 Started:    11 seconds ago
 Message:    update paused due to failure or early termination of task 9p7ith557h8ndf0ui9s0q951b
...snip...

排除故障以后,通过以下命令重新执行更新。

#docker service update <SERVICE-ID>
$ docker service update redis

检查任务更新情况,通过docker service ps <SERVICE-ID>查看。

$ docker service ps redis

NAME                                   IMAGE        NODE       DESIRED STATE  CURRENT STATE            ERROR
redis.1.dos1zffgeofhagnve8w864fco      redis:3.0.7  worker1    Running        Running 37 seconds
 \_ redis.1.88rdo6pa52ki8oqx6dogf04fh  redis:3.0.6  worker2    Shutdown       Shutdown 56 seconds ago
redis.2.9l3i4j85517skba5o7tn5m8g0      redis:3.0.7  worker2    Running        Running About a minute
 \_ redis.2.66k185wilg8ele7ntu8f6nj6i  redis:3.0.6  worker1    Shutdown       Shutdown 2 minutes ago
redis.3.egiuiqpzrdbxks3wxgn8qib1g      redis:3.0.7  worker1    Running        Running 48 seconds
 \_ redis.3.ctzktfddb2tepkr45qcmqln04  redis:3.0.6  mmanager1  Shutdown       Shutdown 2 minutes ago

排除节点

实际服务运行时,可以对节点进行排除进行维护。

本节以上节redis为例.节点分别为: manager1、worker1、worker2

排除节点

排除之前的任务运行情况如下:

$ docker service ps redis

NAME                               IMAGE        NODE     DESIRED STATE  CURRENT STATE
redis.1.7q92v0nr1hcgts2amcjyqg3pq  redis:3.0.6  manager1 Running        Running 26 seconds
redis.2.7h2l8h3q3wqy5f66hlv9ddmi6  redis:3.0.6  worker1  Running        Running 26 seconds
redis.3.9bg7cezvedmkgg6c8yzvbhwsd  redis:3.0.6  worker2  Running        Running 26 seconds

通过以下命令排除节点work1:

# docker node update --availability drain <NODE-ID>
$ docker node update --availability drain worker1

worker1

执行之后,通过以下命令检查状态:

$ docker node inspect --pretty worker1

ID:			38ciaotwjuritcdtn9npbnkuz
Hostname:		worker1
Status:
 State:			Ready
 Availability:		Drain
...snip...

确认已经为排除状态之后,查看任务状态:

$ docker service ps redis

NAME                                    IMAGE        NODE      DESIRED STATE  CURRENT STATE           ERROR
redis.1.7q92v0nr1hcgts2amcjyqg3pq       redis:3.0.6  manager1  Running        Running 4 minutes
redis.2.b4hovzed7id8irg1to42egue8       redis:3.0.6  worker2   Running        Running About a minute
 \_ redis.2.7h2l8h3q3wqy5f66hlv9ddmi6   redis:3.0.6  worker1   Shutdown       Shutdown 2 minutes ago
redis.3.9bg7cezvedmkgg6c8yzvbhwsd       redis:3.0.6  worker2   Running        Running 4 minutes

worker1 状态为Shutdown ,worker2 则启动了一个容器以维持任务实例数量。

激活节点

节点维护完成之后,节点可以重新激活。

通过以下命令完成:

$ docker node update --availability active worker1

worker1

检查其状态:

$ docker node inspect --pretty worker1

ID:			38ciaotwjuritcdtn9npbnkuz
Hostname:		worker1
Status:
 State:			Ready
 Availability:		Active
...snip...

当节点重新被激活,可以接收新任务:

  • 服务节点拓展期间
  • 执行滚动更新期间
  • 将另一个节点排除时
  • 激活节点的一个任务失败时

 

参照资料

https://docs.docker.com/engine/swarm/

https://success.docker.com/article/networking

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注