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 中有两种节点,Manager 与 Worker。如下图所示。
管理节点(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)将会删除任务及其容器,然后根据服务的条件创建新的任务来进行替换。
下图为创建服务到最终执行示意图:
复制服务(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