Docker Swarm

0.Docker Swarm是什么?

单机的Docker资源是有限的,不能方便地进行横向扩展,也难以实现容器的故障恢复,容器中运行的服务做到无中断地更新也比较困难。这一系列的问题下,Docker Swarm这样的容器编排工具就应运而生了。

Docker Swarm是Docker内置的一个容器编排工具,但它不是唯一的容器编排工具。常见的还有Kubernetes,不过Kubernetes比较复杂,上手难度大、学习成本高、开发运维人员的技术要求也相应提高。

所以,中小企业使用Docker Swarm更为合适。

Docker Swarm也是一个Docker的集群,这也符合计算机领域的常规思路:单机无法实现的事情就通过集群来完成。既然是集群,就涉及到集群的架构。Docker Swarm集群中的节点分为manager节点和worker节点,manager节点负责控制集群的配置、服务(task)的运行、查看集群状态等工作,而worker节点只能用来运行服务,也就是容器。

image

1.准备Docker Swarm环境

1.1 初始化Docker Swarm

在172.18.20.53执行初始化命令

$ docker swarm init
Swarm initialized: current node (j6cm8ajrkzpmy0whc9pk5cvu5) is now a manager.

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

    docker swarm join --token SWMTKN-1-4lgkwzzstiqq7u0owwd0cz5lnw8ao6qk62v2siq0usda4o5dph-aw8x1sik3nrrfzg262el2msb6 172.18.20.53:2377

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

初始化完成后,当前节点为manager节点,并且会提示如何将新的节点加入此Docker Swarm集群,其中需要通过--token参数指定token,否则无法成功加入。

如果没有及时加入新的节点,并记住上面的token也没有关系,可以使用以下命令分别查看添加manager和worker节点的token。

$ docker swarm join-token --help

Usage:  docker swarm join-token [OPTIONS] (worker|manager)

Manage join tokens

Options:
  -q, --quiet    Only display token
      --rotate   Rotate join token
$ docker swarm join-token worker
To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-4lgkwzzstiqq7u0owwd0cz5lnw8ao6qk62v2siq0usda4o5dph-aw8x1sik3nrrfzg262el2msb6 172.18.20.53:2377

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

    docker swarm join --token SWMTKN-1-4lgkwzzstiqq7u0owwd0cz5lnw8ao6qk62v2siq0usda4o5dph-as56uu7na38f7uox1py8a4par 172.18.20.53:2377

从以上内容可以看出,Docker Swarm中添加manager和worker节点的命令是一致的,只是不同的token决定了加入的节点是manager节点还是worker节点。

1.2 添加新节点到Docker Swarm中

在172.18.20.54执行以下命令,加入manager节点

$ docker swarm join --token SWMTKN-1-4lgkwzzstiqq7u0owwd0cz5lnw8ao6qk62v2siq0usda4o5dph-as56uu7na38f7uox1py8a4par 172.18.20.53:2377
This node joined a swarm as a manager.

在172.18.20.55执行以下命令,加入worker节点

$ docker swarm join --token SWMTKN-1-4lgkwzzstiqq7u0owwd0cz5lnw8ao6qk62v2siq0usda4o5dph-aw8x1sik3nrrfzg262el2msb6 172.18.20.53:2377
This node joined a swarm as a worker.

1.3 查看集群中的节点

$ docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
j6cm8ajrkzpmy0whc9pk5cvu5 *   172.18.20.53        Ready               Active              Leader              19.03.8
e1u5wv4x4tfpe9j6kfd1byau6     172.18.20.54        Ready               Active              Reachable           19.03.8
b5w8u1dprgqk6g5hwgvf21rm4     172.18.20.55        Ready               Active                                  19.03.8

查看节点只能在manager节点下进行,在worker节点下会有如下错误提示

$ docker node ls
Error response from daemon: This node is not a swarm manager. Worker nodes can't be used to view or modify cluster state. Please run this command on a manager node or promote the current node to a manager.

2.Docker Swarm与Overlay Network

首先使用一个whoami的镜像来进行试验

docker pull stefanscherer/whoami

其项目地址为 https://github.com/StefanScherer/whoami

项目主页中可以看到其默认的web服务端口号为8080.

$ docker service create --name whoami -p 9090:8080 stefanscherer/whoami
9va4qq1p05go0q0pr4rppntdd
overall progress: 1 out of 1 tasks
1/1: running   [==================================================>]
verify: Service converged
$ docker service ps whoami
ID                  NAME                IMAGE                         NODE                DESIRED STATE       CURRENT STATE           ERROR               PORTS
qdbs2557cu79        whoami.1            stefanscherer/whoami:latest   172.18.20.55        Running             Running 2 minutes ago

使用在Docker Swarm中运行一个service,从结果可以看到这个容器被分配到172.18.20.55这个节点运行。

接着使用curl来验证whoami的输出结果

$ curl http://172.18.20.55:9090
I'm 3ce32f72a750 running on linux/amd64

IP: 127.0.0.1
IP: 10.0.0.8
IP: 172.19.0.3
ENV: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ENV: HOSTNAME=3ce32f72a750
ENV: HOME=/
GET / HTTP/1.1
Host: 172.18.20.55:9090
User-Agent: curl/7.54.0
Accept: */*

这个结果是预料之中的,容器在该节点运行,那么该节点作为宿主机,其9090端口与容器的8080端口映射,外部能够访问,这是理所当然的。

然后继续使用curl请求其它两个节点的9090端口的时候,“意外”发生了

$ curl http://172.18.20.53:9090
I'm 3ce32f72a750 running on linux/amd64

IP: 127.0.0.1
IP: 10.0.0.8
IP: 172.19.0.3
ENV: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ENV: HOSTNAME=3ce32f72a750
ENV: HOME=/
GET / HTTP/1.1
Host: 172.18.20.53:9090
User-Agent: curl/7.54.0
Accept: */*

$ curl http://172.18.20.54:9090
I'm 3ce32f72a750 running on linux/amd64

IP: 127.0.0.1
IP: 10.0.0.8
IP: 172.19.0.3
ENV: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ENV: HOSTNAME=3ce32f72a750
ENV: HOME=/
GET / HTTP/1.1
Host: 172.18.20.54:9090
User-Agent: curl/7.54.0
Accept: */*

其它两个节点的9090端口居然也能访问?

使用docker inspectdocker service inspect命令可以看出,whoami这个容器使用的是ingress网络(也就是overlay网络)

Docker Swarm默认使用的就是overlay网络。

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
684be8ae630e        bridge              bridge              local
061dd53e57b9        docker_gwbridge     bridge              local
4cfc45bc4cc7        host                host                local
4pluvrq8bgsu        ingress             overlay             swarm
0ccda9e2745e        none                null                local

查看ingress的详细信息,可以看到Docker Swarm集群的三个节点都连接了ingress这个overlay网络。

$ docker network inspect ingress
[
    {
        "Name": "ingress",
        "Id": "4pluvrq8bgsu5tkhtbze5m43u",
        "Created": "2020-03-17T23:26:45.971433101+08:00",
        "Scope": "swarm",
        "Driver": "overlay",
        ...
        ...
        ...
        "Peers": [
            {
                "Name": "2254bda5c7e4",
                "IP": "172.18.20.53"
            },
            {
                "Name": "5164a5c8f987",
                "IP": "172.18.20.54"
            },
            {
                "Name": "7abbc0275f86",
                "IP": "172.18.20.55"
            }
        ]
    }
]

关于docker overlay network这里不作深入探究,它是基于LVS实现的,对网络原理有兴趣的可以自行拓展阅读。

3.Docker Swarm之负载均衡与弹性伸缩

docker service scale可以控制服务(容器)运行的的实例数。

将实例数增加到2

$ docker service scale whoami=2
whoami scaled to 2
overall progress: 2 out of 2 tasks
1/2: running   [==================================================>]
2/2: running   [==================================================>]
verify: Service converged

查看服务运行的节点

$ docker service ps whoami
ID                  NAME                IMAGE                         NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
qdbs2557cu79        whoami.1            stefanscherer/whoami:latest   172.18.20.55        Running             Running 36 minutes ago
opajqayjgryw        whoami.2            stefanscherer/whoami:latest   172.18.20.54        Running             Running 54 seconds ago

3.1 负载均衡

此时再通过curl请求whoami服务时,可以看到whoami的输出结果为2个whoami实例交替响应。

$ curl http://172.18.20.53:9090
I'm 23031bbc1772 running on linux/amd64

$ curl http://172.18.20.53:9090
I'm 3ce32f72a750 running on linux/amd64

$ curl http://172.18.20.53:9090
I'm 23031bbc1772 running on linux/amd64

$ curl http://172.18.20.53:9090
I'm 3ce32f72a750 running on linux/amd64

这样实际上也就实现了负载均衡效果。

3.2 弹性伸缩

将whoami实例数扩展到5个

$ docker service scale whoami=5
whoami 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
$ docker service ps whoami
ID                  NAME                IMAGE                         NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
qdbs2557cu79        whoami.1            stefanscherer/whoami:latest   172.18.20.55        Running             Running 44 minutes ago
opajqayjgryw        whoami.2            stefanscherer/whoami:latest   172.18.20.54        Running             Running 9 minutes ago
5krem5omr02v        whoami.3            stefanscherer/whoami:latest   172.18.20.53        Running             Running 50 seconds ago
yx77vjfmhc0j        whoami.4            stefanscherer/whoami:latest   172.18.20.53        Running             Running 50 seconds ago
xlsgmzyzodl1        whoami.5            stefanscherer/whoami:latest   172.18.20.55        Running             Running 15 seconds ago

将whoami实例数缩减到2个

$ docker service scale whoami=2
whoami scaled to 2
overall progress: 2 out of 2 tasks
1/2: running   [==================================================>]
2/2: running   [==================================================>]
verify: Service converged
$ docker service ps whoami
ID                  NAME                IMAGE                         NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
qdbs2557cu79        whoami.1            stefanscherer/whoami:latest   172.18.20.55        Running             Running 46 minutes ago
opajqayjgryw        whoami.2            stefanscherer/whoami:latest   172.18.20.54        Running             Running 11 minutes ago

停止全部的whoami实例

$ docker service scale whoami=0
whoami scaled to 0
overall progress: 0 out of 0 tasks
verify: Service converged
$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                         PORTS
9va4qq1p05go        whoami              replicated          0/0                 stefanscherer/whoami:latest   *:9090->8080/tcp
$ docker service ps whoami
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE       ERROR               PORTS

在Docker Swarm中实现扩容和所容,只需要一行命令就能完成,免去了传统方式准备操作系统和运行环境的痛苦。

4.Docker Stack

version: "3.8"

services:
  wordpress:
    image: wordpress
    ports:
      - "8080:80"
    networks:
      - overlay
    deploy:
      mode: replicated
      replicas: 2
      endpoint_mode: vip

  mysql:
    image: mysql
    volumes:
       - db-data:/var/lib/mysql/data
    networks:
       - overlay
    deploy:
      mode: replicated
      replicas: 2
      endpoint_mode: dnsrr

volumes:
  db-data:

networks:
  overlay:

https://docs.docker.com/compose/compose-file/#deploy

5.Service更新

docker service update --image <image> <service>

6.展望: CI & CD

Jenkins vs Gitlab CI