Docker Swarm 介绍
Swarm 在 Docker 1.12 版本之前属于一个独立的项目,在 Docker 1.12 版本发布之后,该项目合并到了 Docker 中,成为 Docker 的一个子命令。目前,Swarm 是 Docker 社区提供的唯一一个原生支持 Docker 集群管理的工具。它可以把多个 Docker 主机组成的系统转换为单一的虚拟 Docker 主机,使得容器可以组成跨主机的子网网络。
2016年核心团队发现中央服务的扩展被限制之后,Swarm 在内部被再次重新设计为Swarm2,使用了去中心化的集群设计,允许构造数千个节点的集群;随后又发布了SwarmKit(可以作为任规模的分布式服务的编排工具包),将其合并到了Docker Engine,Docker Swarm在设计上遵从了可插拔的设计思想,安装集群只需要启动几个docker就可以完成
Docker三剑客:Docker Swarm、 Docker Machine、 Docker Compose(它们可以无缝的集成)
Docker Machine:预配机器,可以是虚拟机器也可以是物理机器,并可以在若干纯物理机器上运行Docker容器 (Docker Engine和Docker Machine介绍)
Docker Compose:用户可以快速定义Dockerfile,通过简单但是强大的YAML语法描述行为,并且只需要把这些文件“组合”起来就可以启动应用程序(Docker-Compose简介安装使用)
Docker Swarm:强大的集群工具,让用户以为自己管理的是单个巨大的Docker宿主机,而这个宿主机是由很多Docker宿主机组成的
前提
两台网络互通的宿主机
安装1.12或更高版本的docker
管理节点的IP地址
开启宿主机之间的端口(TCP端口2377集群管理端口)
概念
swarm:是一组docker引擎的集群
node:是单个docker引擎的实例,可以在一个物理机上也可以在多个
application:是应用
manager node:部署应用的时候会有一个manager node节点
Worker nodes:对应的就是Worker nodes
service:然后service是一堆被workder执行的任务
replicated services:是负载均衡节点
global services:则是全局的,在所有节点上都会执行的一个服务
task:一个task就是一个docker的容器,是Swarm的工作单元
创建Docker Swarm集群
1、使用docker machine ssh连接到想要成为manager node的那台docker宿主机上。
$ docker-machine ssh manager1
2、执行下面的命令,创建一个swarm集群。
docker swarm init --advertise-addr <MANAGER-IP>
例如:
# docker swarm init --advertise-addr 43.241.208.252 Swarm initialized: current node (xmv5n6bi8jtzux88a9ly03dx6) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-4ebqztfvn45rpmol5gy8stxh9om7otzzeib3pyvemtpc49zf0t-18tzrg41wdfctkp2ejeai9nxl 43.241.208.252:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
我这里是在美团公有云的一台云主机上创建的,使用的是公网IP,因为我准备将阿里云上一台云主机添加为swarm node。所以用的是公网IP,通常生产环境都是用内网IP
添加一个worker到swarm集群,执行以下命令,注意是在worker上执行命令而不是manager
docker swarm join --token SWMTKN-1-4ebqztfvn45rpmol5gy8stxh9om7otzzeib3pyvemtpc49zf0t-18tzrg41wdfctkp2ejeai9nxl 43.241.208.252:2377
如果哪天忘记这个命令了,可以在manager上执行下面的命令,查看
$ 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到swarm集群,执行以下命令,并按照提示操作,注意是在worker上执行命令而不是manager
docker swarm join-token manager
我这里把美团云上同一内网的另外一台云主机添加为worker,虽然我前面创建集群是用的公网IP,但是manager监听地址为0.0.0.0:2377,所以用内网IP也没问题
# docker swarm join --token SWMTKN-1-4ebqztfvn45rpmol5gy8stxh9om7otzzeib3pyvemtpc49zf0t-18tzrg41wdfctkp2ejeai9nxl 172.16.2.14:2377 This node joined a swarm as a worker.
将阿里云主机添加为worker
# docker swarm join --token SWMTKN-1-4ebqztfvn45rpmol5gy8stxh9om7otzzeib3pyvemtpc49zf0t-18tzrg41wdfctkp2ejeai9nxl 43.241.208.252:2377 This node joined a swarm as a worker.
注意:在操作之前,一定要保证节点之间,以下端口能互通
TCP port 2377 for cluster management communications
TCP and UDP port 7946 for communication among nodes
UDP port 4789 for overlay network traffic
manager和worker之前角色转换
manager降级为worker
docker node demote node_name
worker升级为manager
docker node update --role manager node_name 或者 docker node promote node_name
注意命令要在manager上执行
docker node ls:查看swarm集群节点信息,在manager节点上执行该命令

使用--filter 过滤
# docker node ls --filter role=manager ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION xmv5n6bi8jtzux88a9ly03dx6 * OPS01-LINTEST02 Ready Active Leader 18.05.0-ce
# docker node ls --filter role=worker ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION p7s36i9wzczvkld8xxjvjj19u test2 Ready Active 18.05.0-ce
docker info,查看 Swarm集群信息
Swarm: active NodeID: xmv5n6bi8jtzux88a9ly03dx6 Is Manager: true ClusterID: nwjap3nned83wyf9zt2nrcd0i Managers: 1 Nodes: 3 Orchestration: Task History Retention Limit: 5
在swarm集群中部署服务
# docker service create --replicas 1 --name helloworld alpine ping docker.com s3yyv341lp5ldgpxe91bkqgpz overall progress: 1 out of 1 tasks 1/1: running [==================================================>] verify: Service converged
docker service create命令创建一个 service.--name标签命名service为helloBoy.--replicas标签来详细声明1个运行实体.参数alpine ping docker.com定义执行pingg docker.com作为alpine容器的服务
--constraint: 约束,指定将创建服务的task分发到满足条件的节点上,
例如:
| node attribute | matches | example |
|---|---|---|
| node.id | Node ID | node.id==2ivku8v2gvtg4 |
| node.hostname | Node hostname | node.hostname!=node-2 |
| node.role | Node role | node.role==manager |
| node.labels | user defined node labels | node.labels.security==high |
| engine.labels | Docker Engine's labels | engine.labels.operatingsystem==ubuntu 14.04 |
例如:
docker service create --replicas 3 --name my-redis --contraint 'node.role==worker' redis
官方文档:https://docs.docker.com/engine/reference/commandline/service_create/#set-service-mode---mode
docker service ls:查看正在运行的服务
# docker service ls ID NAME MODE REPLICAS IMAGE PORTS s3yyv341lp5l helloworld replicated 1/1 alpine:latest
查看服务的详细信息
docker service inspect --pretty SERVICE_NAME
例如:
# docker service inspect --pretty helloworld ID: s3yyv341lp5ldgpxe91bkqgpz Name: helloworld 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: alpine:latest@sha256:e1871801d30885a610511c867de0d6baca7ed4e6a2573d506bbec7fd3b03873f Args: ping docker.com Resources: Endpoint Mode: vip
如果希望以json格式查看,去掉--pretty参数
[
{
"ID": "s3yyv341lp5ldgpxe91bkqgpz",
"Version": {
"Index": 21
},
"CreatedAt": "2018-06-29T07:27:04.344971763Z",
"UpdatedAt": "2018-06-29T07:27:04.344971763Z",
"Spec": {
"Name": "helloworld",
"Labels": {},
"TaskTemplate": {
"ContainerSpec": {
"Image": "alpine:latest@sha256:e1871801d30885a610511c867de0d6baca7ed4e6a2573d506bbec7fd3b03873f",
"Args": [
"ping",
"docker.com"
],
"StopGracePeriod": 10000000000,
"DNSConfig": {},
"Isolation": "default"
},
"Resources": {
"Limits": {},
"Reservations": {}
},
"RestartPolicy": {
"Condition": "any",
"Delay": 5000000000,
"MaxAttempts": 0
},
"Placement": {
"Platforms": [
{
"Architecture": "amd64",
"OS": "linux"
},
{
"OS": "linux"
},
{
"Architecture": "arm64",
"OS": "linux"
},
{
"Architecture": "386",
"OS": "linux"
},
{
"Architecture": "ppc64le",
"OS": "linux"
},
{
"Architecture": "s390x",
"OS": "linux"
}
]
},
"ForceUpdate": 0,
"Runtime": "container"
},
"Mode": {
"Replicated": {
"Replicas": 1
}
},
"UpdateConfig": {
"Parallelism": 1,
"FailureAction": "pause",
"Monitor": 5000000000,
"MaxFailureRatio": 0,
"Order": "stop-first"
},
"RollbackConfig": {
"Parallelism": 1,
"FailureAction": "pause",
"Monitor": 5000000000,
"MaxFailureRatio": 0,
"Order": "stop-first"
},
"EndpointSpec": {
"Mode": "vip"
}
},
"Endpoint": {
"Spec": {}
}
}
]查看服务在哪个node上运行,执行
docker service ps <SERVICE-ID>
[root@OPS01-LINTEST02 ~]# docker service ps helloworld ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS ilf2yn2rwk5u helloworld.1 alpine:latest OPS01-LINTEST02 Running Running 25 minutes ago
Swarm集群中大规模部署服务
$ docker service scale <SERVICE-ID>=<NUMBER-OF-TASKS>
例如:
# docker service scale helloworld=5 helloworld scaled to 5 overall progress: 5 out of 5 tasks 1/5: running [==================================================>] 2/5: running [==================================================>] 3/5: running [==================================================>] 4/5: running [==================================================>] 5/5: running [==================================================>] verify: Service converged
查看这些服务部署在哪些node上
[root@OPS01-LINTEST02 ~]# docker service ps helloworld ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS ilf2yn2rwk5u helloworld.1 alpine:latest OPS01-LINTEST02 Running Running 32 minutes ago j334o76219na helloworld.2 alpine:latest aliyun-ecs Running Running about a minute ago q619x5t6u0wf helloworld.3 alpine:latest aliyun-ecs Running Running about a minute ago 6qskbu6gl4lv helloworld.4 alpine:latest OPS01-LINTEST02 Running Running about a minute ago e9umbgu80g6g helloworld.5 alpine:latest test2 Running Running about a minute ago
可以看到,之前部署了一个helloworld 服务,现在又部署了4个服务。
删除Swarm集群中的service
docker service rm helloworld
[root@OPS01-LINTEST02 ~]# docker service rm helloworld helloworld [root@OPS01-LINTEST02 ~]# docker service ls ID NAME MODE REPLICAS IMAGE PORTS [root@OPS01-LINTEST02 ~]# docker service ps helloworld no such service: helloworld
滚动更新service
如果你部署了一个基于Redis3.0.6容器镜像的服务,现在需要将Redis版本更新为3.0.7。可以使用docker service update命令,更新redis版本
例如:
1、部署基于Redis3.0.6版本的redis服务
# docker service create \ > --replicas 3 \ > --name redis \ > --update-delay 10s \ > redis:3.0.6 nx4vkpmpbkmf08c2mtyz97emd
2、查看redis 服务信息
# docker service ls ID NAME MODE REPLICAS IMAGE PORTS nx4vkpmpbkmf redis replicated 3/3 redis:3.0.6
3、更新redis版本
docker service update --image redis:3.0.7 redis
默认的更新策略如下:
Stop the first task.
Schedule update for the stopped task.
Start the container for the updated task.
If the update to a task returns
RUNNING, wait for the specified delay period then start the next task.If, at any time during the update, a task returns
FAILED, pause the update
4、查看版本

查看redis服务运行信息,可以看到3.0.6版本的redis已经shutdown了
[root@OPS01-LINTEST02 ~]# docker service ps redis ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS ha449wxgle7h redis.1 redis:3.0.7 test2 Running Running 2 minutes ago rnsvj7yfxh07 \_ redis.1 redis:3.0.6 test2 Shutdown Shutdown 3 minutes ago i6o3owwi7y2w redis.2 redis:3.0.7 aliyun-ecs Running Running 2 minutes ago toj148zo39l2 \_ redis.2 redis:3.0.6 aliyun-ecs Shutdown Shutdown 2 minutes ago j4nvdkhh873e redis.3 redis:3.0.7 OPS01-LINTEST02 Running Running 3 minutes ago 7jp6fgmmxcld \_ redis.3 redis:3.0.6 OPS01-LINTEST02 Shutdown Shutdown 3 minutes ago
将某个node从Swarm集群中排除
命令:
docker node update --availability drain NODE_NAME
默认情况下,Swarm集群中的所有node状态都是active状态
[root@OPS01-LINTEST02 ~]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION xmv5n6bi8jtzux88a9ly03dx6 * OPS01-LINTEST02 Ready Active Leader 18.05.0-ce tfmk3rjzw513w0lt8xrqhd94h aliyun-ecs Ready Active 18.05.0-ce p7s36i9wzczvkld8xxjvjj19u test2 Ready Active 18.05.0-ce
处于active状态的几点,可以接收manager节点下发的任务,但有时候某个docker宿主机需要维护,不能接收新的任务,
我们需要将该节点设置为Drain状态,这意味着该节点不再从swarm管理器接收新任务,manager节点将停止该节点上运行的任务,并在具有ACTIVE可用性的节点上启动副本任务。
例如:
1、我们删除之前启动的redis服务,重新部署具有三个副本的redis服务
# docker service create --replicas 3 --name redis --update-delay 10s redis:3.0.6 # docker service ps redis ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS k8i108uomuls redis.1 redis:3.0.6 test2 Running Running 24 seconds ago ia4zd35lh9up redis.2 redis:3.0.6 aliyun-ecs Running Running 24 seconds ago rlw2cysxe9av redis.3 redis:3.0.6 OPS01-LINTEST02 Running Running 24 seconds ago
2、将test2节点设置为drain状态
[root@OPS01-LINTEST02 ~]# docker node update --availability drain test2 test2 [root@OPS01-LINTEST02 ~]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION xmv5n6bi8jtzux88a9ly03dx6 * OPS01-LINTEST02 Ready Active Leader 18.05.0-ce tfmk3rjzw513w0lt8xrqhd94h aliyun-ecs Ready Active 18.05.0-ce p7s36i9wzczvkld8xxjvjj19u test2 Ready Drain 18.05.0-ce
3、查看redis服务状态
[root@OPS01-LINTEST02 ~]# docker service ps redis ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS pai2qdtk4z2k redis.1 redis:3.0.6 OPS01-LINTEST02 Running Running 31 seconds ago k8i108uomuls \_ redis.1 redis:3.0.6 test2 Shutdown Shutdown 32 seconds ago ia4zd35lh9up redis.2 redis:3.0.6 aliyun-ecs Running Running 9 minutes ago rlw2cysxe9av redis.3 redis:3.0.6 OPS01-LINTEST02 Running Running 9 minutes ago
可以看到test2节点上的redis服务shutdown了,而OPS01-LINTEST02节点(manager节点)上,又启动了一个redis服务
4、恢复test2节点状态为active状态
[root@OPS01-LINTEST02 ~]# docker node update --availability active test2 test2 [root@OPS01-LINTEST02 ~]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION xmv5n6bi8jtzux88a9ly03dx6 * OPS01-LINTEST02 Ready Active Leader 18.05.0-ce tfmk3rjzw513w0lt8xrqhd94h aliyun-ecs Ready Active 18.05.0-ce p7s36i9wzczvkld8xxjvjj19u test2 Ready Active 18.05.0-ce
5、用docker node inspect 命令查看节点信息

Swarm mode路由网格
$ docker service create \ --name <SERVICE-NAME> \ --publish published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \ <IMAGE>
published是docker宿主机上的端口,target是容器中的端口
参考文档:https://docs.docker.com/network/
https://www.jianshu.com/p/401b811be854
















