使用 Docker Stack 部署多服务集群

使用 Docker Stack 部署多服务集群

 

前言


单机模式下,我们可以使用 Docker Compose 来编排多个服务,而在 上一篇文章 中介绍的 Docker Swarm 只能实现对单个服务的简单部署。于是就引出了本文的主角 Docker Stack ,通过 Docker Stack 我们只需对已有的 docker-compose.yml 配置文件稍加改造就可以完成 Docker 集群环境下的多服务编排。

 

正文


  • 首先创建一个 docker-compose.yml 文件,使用 Docker Compose v3 语法

    内容比较简单,一个有四个实例的 nginx 服务,两个只部署在 manager 节点上的单实例监控工具服务:portainer 和 visualizer

version: "3"

services:
  nginx:
    image: nginx:alpine
    ports:
      - 80:80
    deploy:
      mode: replicated
      replicas: 4

  visualizer:
    image: dockersamples/visualizer
    ports:
      - "9001:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      replicas: 1
      placement:
        constraints: [node.role == manager]

  portainer:
    image: portainer/portainer
    ports:
      - "9000:9000"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      replicas: 1
      placement:
        constraints: [node.role == manager]
  • 部署服务
$ docker stack deploy -c docker-compose.yml stack-demo
  • 部署成功之后查看详情
$ docker stack services stack-demo 
ID                  NAME                    MODE                REPLICAS            IMAGE                             PORTS
4yb35ywqvo49        stack-demo_portainer    replicated          1/1                 portainer/portainer:latest        *:9000->9000/tcp
mzd2volqug28        stack-demo_nginx        replicated          4/4                 nginx:alpine                      *:80->80/tcp
r0zlzpp3wujg        stack-demo_visualizer   replicated          1/1                 dockersamples/visualizer:latest   *:9001->8080/tcp
  • 在浏览器中访问监控工具,对应端口如下:
portainer  ——→ ip:9000
visualizer ——→ ip:9001

注意:如果有多个 manager 节点,portainer 和 visualizer 可能分别部署在两台机器上,所以ip可能会不一样。

  • 修改 docker-compose.yml 文件后重新部署即可完成对修改内容的更新
$ docker stack deploy -c docker-compose.yml stack-demo

 

关于负载均衡


评论区有小伙伴提到,容器间通过服务名 ( 比如文中的 nginx ) 通讯时,对应的 IP 却和容器的实际 IP 对不上。出现这个情况是因为负载均衡( 对外表现为一个服务,内部为多个服务 )。下面是我做的试验,希望能帮助大家理解。

  1. 按上面的配置启动集群 ( 由两台服务器构成 )

  2. 在 manager 节点服务器中看下运行的服务

    $ docker ps
    CONTAINER ID IMAGE NAMES
    9b96f07bbb91 dockersamples/visualizer:latest stack-demo_visualizer.1.p5hy7gsc50vbm0wkxm1c17rl6
    942dd34d024e nginx:alpine stack-demo_nginx.4.tp6u05jmg9iuookqc9i9e11kz
    706ae42e0089 nginx:alpine stack-demo_nginx.2.vnlmlky5m5qy7l8qxq6k5nllk
    6dba55dd7d63 portainer/portainer:latest stack-demo_portainer.1.yv76gf0i7gou2awen44kshm1j
    
  3. 在这台服务器上启动了两个 nginx 容器实例,随便进一个实例看下 IP

    $ docker exec -it stack-demo_nginx.2.vnlmlky5m5qy7l8qxq6k5nllk ifconfig
    eth0 Link encap:Ethernet HWaddr 02:42:0A:FF:00:3E
    inet addr:10.255.0.62 Bcast:10.255.255.255 Mask:255.255.0.0
    eth1 Link encap:Ethernet HWaddr 02:42:0A:00:06:07
    inet addr:10.0.6.7 Bcast:10.0.6.255 Mask:255.255.255.0
    eth2 Link encap:Ethernet HWaddr 02:42:AC:13:00:04
    inet addr:172.19.0.4 Bcast:172.19.255.255 Mask:255.255.0.0
    lo Link encap:Local Loopback
    inet addr:127.0.0.1 Mask:255.0.0.0
    

    发现容器中绑了3个网卡 eth0 、eth1 、eth2 ,我猜想分别对应 整个 Swarm 集群的局域网当前 Stack 集群的局域网 、当前主机下 Compose 服务的局域网 三个网络。

  4. 查看当前主机下的 docker 网络

    $ docker network ls
    NETWORK ID NAME DRIVER SCOPE
    bd4fa8219483 bridge bridge local
    e51735fef0d6 docker_gwbridge bridge local
    26360437865a host host local
    yvupj4ex3odl ingress overlay swarm
    f0a0190c3b1f none null local
    oft930l7jpdn stack-demo_default overlay swarm
    
  5. 上一步看到有两个 swarm 的网络,进去看下具体信息

    $ docker network inspect ingress
    "IPAM": {
        "Config": [
            {
                "Subnet": "10.255.0.0/16",
                "Gateway": "10.255.0.1"
            }
        ]
    },
    "Containers": {
        "6dba55dd7d63f7166e2e0ee3afed8e427089b7140d62f39a835d3145a058b868": {
            "Name": "stack-demo_portainer.1.yv76gf0i7gou2awen44kshm1j",
            "IPv4Address": "10.255.0.59/16",
        },
        "706ae42e00890444087aa6d51ccb966b76b5ad4c985b48fdf5215c192bcf0836": {
            "Name": "stack-demo_nginx.2.vnlmlky5m5qy7l8qxq6k5nllk",
            "IPv4Address": "10.255.0.62/16",
        },
        "942dd34d024e218aad4e5034e1194a2cfa1d9be81a839ec86403cf237d41368b": {
            "Name": "stack-demo_nginx.4.tp6u05jmg9iuookqc9i9e11kz",
            "IPv4Address": "10.255.0.64/16",
        },
        "9b96f07bbb91a570bb8d26945996d77151c5633c0a6057361ab4474b393da364": {
            "Name": "stack-demo_visualizer.1.p5hy7gsc50vbm0wkxm1c17rl6",
            "IPv4Address": "10.255.0.66/16",
        },
        "ingress-sbox": {
            "Name": "ingress-endpoint",
            "IPv4Address": "10.255.0.2/16",
        }
    }
    

    内容太多就省略其他无关内容了,从上面的信息已经可以证明第三步的猜想了 ( ingress 对应 Swarm 集群 , stack-demo_default 对应 Stack 集群 ) ,要进一步确认可以再看下另一台服务器上的网络。

  6. 通过容器 nginx.4 使用服务名的方式 ping 一下 nginx

    $ docker exec -it stack-demo_nginx.4.tp6u05jmg9iuookqc9i9e11kz ping nginx
    PING nginx (10.0.6.5): 56 data bytes
    64 bytes from 10.0.6.5: seq=0 ttl=64 time=0.121 ms
    

    发现 IP 是 10.0.6.5 ,属于 stack-demo_default 网络,但是在两台服务器的 docker网络详情里面都找不到这个实例。

  7. 在容器 nginx.4 中安装 curl 然后再访问 nginx 看下效果

    $ docker exec -it stack-demo_nginx.4.tp6u05jmg9iuookqc9i9e11kz sh -c 'echo -e "https://mirrors.ustc.edu.cn/alpine/latest-stable/main\nhttps://mirrors.ustc.edu.cn/alpine/latest-stable/community" > /etc/apk/repositories && apk --update add curl'
    $ docker exec -it stack-demo_nginx.4.tp6u05jmg9iuookqc9i9e11kz curl nginx
    

    可以看到访问成功,再多调用几次。

  8. 打印 nginx 容器的日志 ( 可以多开几个终端打印日志,再访问 nginx 看下实时日志的效果,这样更直观 )

    $ docker logs stack-demo_nginx.2.vnlmlky5m5qy7l8qxq6k5nllk && echo "---分界线---" && docker logs stack-demo_nginx.4.tp6u05jmg9iuookqc9i9e11kz
    10.0.6.4 - - [06/Dec/2018:10:15:18 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.60.0" "-"
    ---分界线---
    10.0.6.4 - - [06/Dec/2018:10:13:16 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.60.0" "-"
    10.0.6.4 - - [06/Dec/2018:10:15:19 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.60.0" "-"
    

    可以看到明显的负载均衡的效果,请求都来自 10.0.6.4,它就是 stack-demo_default 网络中一个名为 lb- 开头的实例,它就是这个负载均衡的入口。

    "lb-stack-demo_default": {
     "Name": "stack-demo_default-endpoint",
     "IPv4Address": "10.0.6.4/24",
    }
    
  9. 再去另一台服务器看下 nginx 的日志

    发现并没有访问记录,说明这个负载均衡仅限于 当前服务器 、相同服务 的 多个实例,不会跨服务器负载均衡。

  10. 在另一台服务器上再重复 7 & 8 两个步骤

    发现另一台服务器上不存在名为 lb- 开头的实例,而负载均衡的入口是其中一个普通的 nginx 实例。

总结下:

整个请求的调用流程应该就是:通过服务名 nginx 访问 -- 指向 --> stack 集群网关 ( 10.0.6.5 ) -- 转发 --> stack 集群中,位于当前服务器的负载均衡实例 ( 10.0.6.4 ) -- 分发 --> 最终的应用 。

 

相关命令


命令 描述
docker stack deploy 部署新的堆栈或更新现有堆栈
docker stack ls 列出现有堆栈
docker stack ps 列出堆栈中的任务
docker stack rm 删除一个或多个堆栈
docker stack services 列出堆栈中的服务

 

参考文章


  • Docker 三剑客之 Docker Swarm

 

转载来源:https://www.jianshu.com/p/1db6f0150fdb

你可能感兴趣的:(Docker,docker)