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节点上执行该命令

image.png


使用--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 attributematchesexample
node.idNode IDnode.id==2ivku8v2gvtg4
node.hostnameNode hostnamenode.hostname!=node-2
node.roleNode rolenode.role==manager
node.labelsuser defined node labelsnode.labels.security==high
engine.labelsDocker Engine's labelsengine.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

   

image.png  



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、查看版本

image.png


查看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 命令查看节点信息

image.png



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