docker swarm编排工具

Swarm介绍

Swarm 是 Docker 公司在 2014 年 12 月初发布的一套较为简单的工具,用来管理 Docker 集群,它将一群 Docker 宿主机变成一个单一的,虚拟的主机。Swarm 使用标准的 Docker API接口作为其前端访问入口,换言之,各种形式的 Docker Client(docker client in go, docker_py,docker 等)均可以直接与 Swarm 通信。Swarm 几乎全部用 Go 语言来完成开发。
Swarm deamon 只是一个调度器(Scheduler)加路由器(router),Swarm 自己不运行容器,它只是接受 docker 客户端发送过来的请求,调度适合的节点来运行容器,这意味着,即使Swarm 由于某些原因挂掉了,集群中的节点也会照常运行,当 Swarm 重新恢复运行之后,它会收集重建集群信息。下面是 Swarm 的结构图:
swarm架构图

环境准备

  1. 三台服务器或者虚拟机
  • server01, server02, server03
  1. 安装了docker

搭建集群

初始化一个manager节点

docker提供了init命令用于初始化一个集群, 从输出信息中可以得到对应的work节点的token

n-tech-admin@server01:~$ docker swarm init 
Swarm initialized: current node (wpx3o9mcpuq79ujpumykjkgt7) is now a manager.

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

    docker swarm join --token SWMTKN-1-44a0imbc65z7o9fbfj89mxs4xfu7w3pmtfo7s50mt3ues809mr-0xhunq3plzdyhyhebswxuuds8 192.168.10.45:2377

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

在其他服务器输入命令

在上一步的输出中, 已经包含了其他节点加入该集群的命令.只需要输入即可.

n-tech-admin@server02:~$ docker swarm join --token SWMTKN-1-44a0imbc65z7o9fbfj89mxs4xfu7w3pmtfo7s50mt3ues809mr-0xhunq3plzdyhyhebswxuuds8 192.168.10.45:2377
This node joined a swarm as a worker.

n-tech-admin@server03:~$ docker swarm join --token SWMTKN-1-44a0imbc65z7o9fbfj89mxs4xfu7w3pmtfo7s50mt3ues809mr-0xhunq3plzdyhyhebswxuuds8 192.168.10.45:2377
This node joined a swarm as a worker.

查看docker network

创建集群之后, 我们可以看到network增加了docker_gwbridgeingress两个网络.
swarm的ingress连接的是ingress网络, 该网络需要通过docker_gwbridge网桥, 借助于docker daemon网桥跟主机进行连接.

n-tech-admin@server01:~$ docker network ls
NETWORK ID          NAME                         DRIVER              SCOPE
cdb39c520f0b        bridge                       bridge              local
fd5e65ece1c7        docker_gwbridge              bridge              local
eb06b54c7e76        host                         host                local
tbsdc0m2p1le        ingress                      overlay             swarm
f4e8f15f758b        none                         null                local

高可用

docker默认支持高可用, 通过选举将work节点挑选为manager节点. 只需要配置所有节点为manager节点即可.
首先可以通过docker node ls查看所有的节点信息.可以看到默认情况下MANAGER STATUS只有server01是一个Leader节点. 其他节点都是普通节点.

n-tech-admin@server01:~$ docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
wpx3o9mcpuq79ujpumykjkgt7 *   server01            Ready               Active              Leader              18.09.3
1bz3t5imxc9evv4poh9o3o65l     server02            Ready               Active                                  18.09.0
nuwhcuajlf71q4x23syi7tx06     server03            Ready               Active                                  18.02.0-ce

通过在manager节点执行 docker node promote 服务器名称, 可以将其他节点提升为manager节点.
可以看到执行之后, 另外两个work节点的MANAGER STATUS也变成了Reachable

n-tech-admin@server01:~$ docker node promote server02
Node server02 promoted to a manager in the swarm.
n-tech-admin@server01:~$ docker node promote server03
Node server03 promoted to a manager in the swarm.
n-tech-admin@server01:~$ docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
wpx3o9mcpuq79ujpumykjkgt7 *   server01            Ready               Active              Leader              18.09.3
1bz3t5imxc9evv4poh9o3o65l     server02            Ready               Active              Reachable           18.09.0
nuwhcuajlf71q4x23syi7tx06     server03            Ready               Active              Reachable           18.02.0-ce

创建服务

我们在 manager创建一个linux服务, 提供一个shell命令让他运行.
通过执行 service ls命令, 可以看到刚才运行服务已经成功了.

还可以通过 service inspect 服务名 查看服务的详细信息
通过 service logs 服务名 查看服务的详细日志

n-tech-admin@server01:~$ docker service create --name test01 alpine ping baidu.com
ruzuc9hqpyv6dpe6qk8jmlc12
overall progress: 1 out of 1 tasks 
1/1: running   [==================================================>] 
verify: Service converged


n-tech-admin@server01:~$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
ruzuc9hqpyv6        test01              replicated          1/1                 alpine:latest       

接下来, 我们继续通过swarm创建一个nginx服务, 执行上面相同的命令, 创建完成后, 通过ls命令查看服务.

n-tech-admin@server01:~$ docker service create --name nginx nginx
n6svunal14gc78uffbzn5rl76
overall progress: 1 out of 1 tasks 
1/1: running   [==================================================>] 
verify: Service converged

n-tech-admin@server01:~$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
n6svunal14gc        nginx               replicated          1/1                 nginx:latest        
ruzuc9hqpyv6        test01              replicated          1/1                 alpine:latest       

修改服务

我们发现, nginx没有对外端口, 我们可以通过 update 命令将nginx对外暴露一个端口
然后我们通过浏览器访问 server01, server02, server03三个服务器, 发现都能够得到正确的响应, 这是因为docker通过虚拟IP的方式帮我们访问到最终提供服务的nginx容器.

n-tech-admin@server01:~$ docker service update --publish-add 9967:80 nginx 
nginx
overall progress: 1 out of 1 tasks 
1/1: running   [==================================================>] 
verify: Service converged

服务扩展

docker为我们提供了 scale 命令, 可以对服务进行扩容, 我们通过 service scale nginx=3, 将nginx容器扩容到三个, 然后通过ls命令可以看到 REPLICAS 已经变成了3/3.

n-tech-admin@server01:~$ docker service scale nginx=3
nginx scaled to 3
overall progress: 3 out of 3 tasks 
1/3: running   [==================================================>] 
2/3: running   [==================================================>] 
3/3: running   [==================================================>] 
verify: Service converged 

n-tech-admin@server01:~$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
n6svunal14gc        nginx               replicated          3/3                 nginx:latest        *:9967->80/tcp
ruzuc9hqpyv6        test01              replicated          1/1                 alpine:latest       

服务间应用连通性

通过上面, 我们创建了 test01 服务和 nginx 服务, 然后我们通过 exec -it 登录到 alpine 的 test01 服务, 通过 ping nginx 发现不能连通, 说明默认模式下创建的服务, 不具备服务之间的连通性.

那么, 既然问题提出了, 下面就来说一下怎么解决.

首先, 我们创建一个 network, driver使用 overlay, 名字叫做 local-overlay. 如下

n-tech-admin@server01:~$ docker network create -d overlay local-overlay
7lg34csui03vtcwie57pshodd

n-tech-admin@server01:~$ docker network ls
NETWORK ID          NAME                         DRIVER              SCOPE
cdb39c520f0b        bridge                       bridge              local
fd5e65ece1c7        docker_gwbridge              bridge              local
501f1e83da67        harbor_harbor                bridge              local
eb06b54c7e76        host                         host                local
tbsdc0m2p1le        ingress                      overlay             swarm
7lg34csui03v        local-overlay                overlay             swarm
f4e8f15f758b        none                         null                local
82d08c922135        syncd                        bridge              local
6b2cd023f92f        syncd-docker_syncd-network   bridge              local

然后我们删除上面创建的两个服务.

n-tech-admin@server01:~$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
n6svunal14gc        nginx               replicated          3/3                 nginx:latest        *:9967->80/tcp
ruzuc9hqpyv6        test01              replicated          1/1                 alpine:latest       
n-tech-admin@server01:~$ docker service rm nginx test01 
nginx
test01
n-tech-admin@server01:~$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS

接下来, 我们再次创建两个服务, 不过这次, 我们需要给服务指定网络使用 local-overlay

n-tech-admin@server01:~$ docker service create --name nginx --network local-overlay -p 9967:80 nginx
9mtl0x99t67nxhllfh0ly2m43
overall progress: 1 out of 1 tasks 
1/1: running   [==================================================>] 
verify: Service converged 

n-tech-admin@server01:~$ docker service create --name test02 --network local-overlay alpine ping baidu.com
7fnhnrzrxu9ih9hpu4ysnfijw
overall progress: 1 out of 1 tasks 
1/1: running   [==================================================>] 
verify: Service converged 

然后我们进入 test02 服务 的 alpine, 执行上面执行失败的 pingwget, 我们发现, 所有的操作都已经能够正确执行了, 这是因为docker的vip为我们做了处理.

n-tech-admin@server02:~$ docker exec -it aa sh
/ # ping nginx
PING nginx (10.0.0.2): 56 data bytes
64 bytes from 10.0.0.2: seq=0 ttl=64 time=0.105 ms
64 bytes from 10.0.0.2: seq=1 ttl=64 time=0.100 ms
64 bytes from 10.0.0.2: seq=2 ttl=64 time=0.070 ms
^C
--- nginx ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.070/0.091/0.105 ms
/ # wget nginx
Connecting to nginx (10.0.0.2:80)
index.html           100% |********************************************************************************************************************************************************************************|   612  0:00:00 ETA
/ # 

剔除集群中服务器

如果想要移除集群中某一个服务器, 首先需要判断它是否是一台管理节点, 如果是管理节点, 首先需要将其降级为普通节点, 然后再执行删除命令

降级
docker node demote 节点的id

删除
docker node rm 节点的id

stack

docker 为集群部署的一系列操作提供了 stack 子命令, 方便一次操作.
首先我们需要准备一个 yml 文件, 里面包含了对服务的配置, 就和 compose 文件一样, 不过比 compose文件多了一些对服务资源的限制.
我在这里提供一个文件. external: true表示该网络已存在的意思.

version: "3.4"
services:
  alpine:
    image: alpine
    command:
      - "ping"
      - "www.bing.com"
    networks:
      - local-overlay
    deploy:
      endpoint_mode: dnsrr
      replicas: 2
      restart_policy:
        condition: on-faliure
      resources:
        limits:
          cpus: "0.1"
          memory: "50M"
    depends_on:
      - nginx
  nginx:
    image: nginx
    networks:
      - local-overlay
    ports:
      - 9967:80

networks:
  local-overlay:
    external: true

通过 stack deploy命令对服务进行部署. 通过 stack service 服务名 查看服务详情, 通过 stack ls 查看有多少个服务.

n-tech-admin@server01:~/yzt_test_folder$ docker stack deploy -c service.yml test
Creating service test_alpine
Creating service test_nginx

n-tech-admin@server01:~/yzt_test_folder$ docker stack ls
NAME                SERVICES            ORCHESTRATOR
test                2                   Swarm

n-tech-admin@server01:~/yzt_test_folder$ docker stack services test 
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
3vqmi2loytn6        test_alpine         replicated          2/2                 alpine:latest       
wp7qiu0nbfol        test_nginx          replicated          1/1                 nginx:latest        *:9967->80/tcp

n-tech-admin@server01:~/yzt_test_folder$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
3vqmi2loytn6        test_alpine         replicated          2/2                 alpine:latest       
wp7qiu0nbfol        test_nginx          replicated          1/1                 nginx:latest        *:9967->80/tcp

网络模式

docker 集群模式下默认使用 vip 模式, 可以显示的指定使用 dnsrr模式. 如在 stack 下, 可以在 deploy 子节点指定 endpoint_mode: dnsrr 来修改网络模式.

vip: vip模式中每个服务都有一个固定的ip
dnsrr: dnsrr模式是没有固定ip的, 通过dns服务解析

查看服务的模式可以通过 docker service inspect 服务名, 然后找到 EndpointSpec节点即可查看.

总结

通篇说了很多, 总结下来也就那么几个命令.

docker swarm
docker network
docker service
docker node 
docker stack