【问题标题】:How to deploy consul using Docker 1.12 swarm mode如何使用 Docker 1.12 swarm mode 部署 consul
【发布时间】:2016-08-24 20:13:09
【问题描述】:

我有一个由 3 台服务器组成的领事集群。我还有大约 6 名工人和 3 名主人的 docker 群(主人与领事服务器在同一硬件上,但设置为可用性 == 排水以防止他们接受工作)。

我一般使用 consul-template 来阅读 consul K/V。我一生都无法弄清楚如何明智地推出领事代理服务。如果我使用全局服务,那么每个节点都有一个代理,但服务器集群会抱怨,因为客户端代理似乎都具有相同的 IP 地址。

复制服务似乎是要走的路,但我相信我需要发布客户端端口 8301,这似乎会导致与我的服务器集群发生冲突(它同时运行 swarm master 和 consul 服务器(不在 docker 下) .

我希望大家能朝着正确的方向总体引导 - 请记住,这是 1.12 集群模式,因此与早期版本有很大不同。

【问题讨论】:

    标签: docker docker-swarm


    【解决方案1】:

    这很令人困惑,但 Docker 的“Swarm Mode”确实是一种不同于仍然称为 Docker Swarm 的动物。在 Swarm 模式下,您不需要 Consul。每个主机上的 docker 守护进程充当键值存储并进行服务发现。它为“旧” Docker Swarm 中需要 Consul 做所有事情。

    请注意仅查找特定于“群模式”的文档/信息。我希望他们实际上使用了不同的名称。

    【讨论】:

    • 真的吗?你是说我可以以某种方式指向 consul-template 来读取我的应用程序值吗?我知道我不需要它来实现 swarm 功能,但我们用它来做更多的事情
    • 通常 consul-template 用于更新 nginx 或 haproxy 的配置。它基本上在服务器列表中添加或删除 IP 地址以进行负载平衡。这在 Swarm 模式中是不需要的。你让 docker 做负载平衡。最好让 nginx(例如)在您的服务前面处理 SSL、gzip、安全性之类的事情,但它的配置文件可以简单地使用 dns 名称“myservice”作为上游服务器。如果你创建了一个名为“myservice”的 docker 服务,docker 会为合适的容器做负载均衡。
    • 我们使用 consull-template 为一大堆遗留应用程序填充文件 - 我正在努力了解如何仅使用 swarm 来实现这一点。我了解 swarm 现在是如何实现过去依赖第三方工具的大部分服务发现和负载平衡的。但是作为一个通用的K/V store,我就是不知道怎么用。
    • @MarkH 我明白你的意思。总的来说,我认为 Docker 1.12 不可能。 Docker 1.13 可能会添加所需的更改。更长的故事:新的 Swarm 模式使用内部 kv 存储(基于 etcd),但仅供自己使用。此外,无法监听有关容器/服务启动/停止的事件。这是 Docker 1.13 的一个功能,尽管github.com/docker/docker/issues/23827。 Registrator 需要这个来更新 Consul。如果你现在真的需要一些东西,你可以使用 Docker Remote API 进行轮询,但这就像编写你自己的 Registrator。
    • 我使用 consul 作为我自己的微服务的键值对存储,这与主机名完全无关。 traefik 也在使用它。
    【解决方案2】:

    经过深思熟虑和许多死胡同,我们终于想出了一个适合我们的解决方案。部分问题在于,在撰写本文时,Docker 1.12 还有些幼稚,并且引入了许多必须理解的概念才能使一切变得有意义。在我们的案例中,我们之前使用 1.12 之前的 Swarm 变体的经验阻碍了我们的前瞻性思考,而不是帮助了我们。

    我们用来为我们的 swarm 部署 consul K/V 服务的解决方案如下

    1. 创建一个名为“consul”的覆盖网络。这为我们的服务在其中运行创建了一个地址空间。

      docker network create --driver overlay --subnet 10.10.10.0/24 consul

    2. 将领事服务器集群部署到新的覆盖中。我们将三台主机用作管理器节点,我们希望 consul 服务器容器在该集群上运行,而不是在应用服务器上运行,因此使用了“约束”标志

      docker service create -e 'CONSUL_LOCAL_CONFIG={"leave_on_terminate": true}' --name consulserver --network consul --constraint 'node.role == manager' --replicas 3 consul agent server -bootstrap-expect=3 -bind=0.0.0.0 -retry-join="10.10.10.2" -data-dir=/tmp

      这里的关键是 swarm 将在映射到三个新实例的 consul 网络开始时分配一个新的 VIP (10.10.10.2)。

    3. 接下来我们部署了一个代理服务

      docker service create \ -e 'CONSUL_BIND_INTERFACE=eth0' \ -e 'CONSUL_LOCAL_CONFIG={"leave_on_terminate": true, "retry_join":["10.10.10.2"]}' \ --publish "8500:8500" \ --replicas 1 \ --network consul \ --name consulagent \ --constraint 'node.role != manager' \ consul agent -data-dir=/tmp -client 0.0.0.0

    指定 consulserver 服务的 VIP。 (Consul 不会解析加入的名称 - 其他容器可能会做得更好,允许指定服务名称“consulserver”而不是 VIP)

    完成后,任何其他服务都可以通过加入 consul 网络并解析名称“consulagent”来访问 consulagent。 consulagent 服务可以根据需要进行扩展(或部署为全局服务)。 发布端口 8500 使服务在 swarm 边缘可用,如果您不需要使其可用于非 swarm 服务,则可以将其丢弃。

    【讨论】:

    • 与@electrometro 的回答相同的问题:发布 Consul API 端口不危险吗?
    • 向谁发布端口?我们的整个网络实际上是一个 DMZ。只有同一 VLAN 上的设备才能访问这些服务中的任何一项,因此风险很小。我很好奇你会怎么做 - 我们总是乐于改进我们的部署。
    • 在 Docker Swarm 模式之前,我将 Consul API 绑定到桥接接口 IP,因此 API 可以从集群内部访问,但不能从外部访问。这是唯一的选择,因为建议 Consul 在主机网络名称空间上运行。我不确定我的解决方案是否明智,但这正是我来这里研究的原因,试图找到更好的方法.. :)
    • 不确定原因,但只是一个警告 - 创建服务导致 3 个 docker swarm 管理器节点中的 2 个崩溃,并且在 docker 服务守护进程上出现错误并无法恢复:Error starting daemon: layer does not exist
    【解决方案3】:

    在我的blog 中,我探索了与 MarkH 的答案类似的方法,但关键区别在于,我不是指向新服务器的 VIP,而是指向加入网络的前三个节点。这可能是有益的,因为 VIP 存在指向自身的问题,而不是在该 VIP 上的所有节点之间进行负载平衡。根据我的经验,最好以这种方式创建服务。

    docker service create \
      --network=consul \
      --name=consul \
      -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' \ 
      -e CONSUL_BIND_INTERFACE='eth0' \
      --mode global \
      -p 8500:8500 \ 
      consul agent -server -ui -client=0.0.0.0 \
      -bootstrap-expect 3 \
      -retry-join 172.20.0.3 \
      -retry-join 172.20.0.4 \
      -retry-join 172.20.0.5 \
      -retry-interval 5s
    

    我在 3 节点集群中使用全局模式,因此您可以将其换成副本并设置约束。

    【讨论】:

    • 最初我们使用与此相同的重试加入集。然而,使用 VIP 似乎更干净。一旦集群建立起来,负载均衡器就不会参与进来,因为 gossip 协议将传播单个集群成员的 IP 而不是 VIP。我希望我们在研究时找到您的博客...
    • @MarkH,我也是!我们花了几天时间想出这个。 :)。不过 VIP 非常有趣,我们可能需要对它们的工作原理进行更多研究。
    • 发布代理的端口不危险吗?您不希望互联网可以访问 Consul API。我想您可以通过防火墙规则阻止互联网,但我想这有点破坏 Docker 的网络模型(私有与发布的端口)
    • 是的,这很危险,但我们在防火墙后面。我不确定如何在不发布它们的情况下访问它们。
    • 请撰写版本:)?那里的IP是什么,我不能对任何IP进行严格的设置,它应该是动态的
    【解决方案4】:

    对于像我这样喜欢从 docker-compose.yml 文件运行我们的服务的人,我设法“docker stack deploy”

    https://github.com/thechane/consul/blob/master/docker-compose.yml

    ... 将 Consul 作为 Docker 服务运行。

    --- 编辑,糟糕的形式只能用链接回答,所以这里是:

    version: '3.1'
    #customise this with options from
    #https://www.consul.io/docs/agent/options.html
    
    services:
    
    seed:
      hostname: seed
      image: consul:0.8.0
      deploy:
        restart_policy:
          condition: none  #we do not want this to be restarted on timeout (see entrypoint options below)
        replicas: 1
        placement:
          constraints:
            - "engine.labels.access == temp"
            - "engine.labels.access != consul"
      environment:
        - "CONSUL_LOCAL_CONFIG={\"disable_update_check\": true}"
        - "CONSUL_BIND_INTERFACE=eth0"
      entrypoint:
        - timeout     #this seed fires up the cluster after which it is no longer needed
        - -sTERM      #this is the same signal as docker would send on a scale down / stop
        - -t300       #terminate after 5 mins
        - consul
        - agent
        - -server
        - -bootstrap-expect=5
        - -data-dir=/tmp/consuldata
        - -bind={{ GetInterfaceIP "eth0" }}
      networks:
        - "consul"
    
    cluster:
      image: consul:0.8.0
      depends_on:
        - "seed"
      deploy:
        mode: global                                      ##this will deploy to all nodes that
        placement:
          constraints:
            - "engine.labels.access == consul"            ##have the consul label
            - "engine.labels.access != temp"
      environment:
        - "CONSUL_LOCAL_CONFIG={\"disable_update_check\": true}"
        - "CONSUL_BIND_INTERFACE=eth0"
        - "CONSUL_HTTP_ADDR=0.0.0.0"
      entrypoint:
        - consul
        - agent
        - -server
        - -data-dir=/tmp/consuldata
        - -bind={{ GetInterfaceIP "eth0" }}
        - -client=0.0.0.0
        - -retry-join=seed:8301
        - -ui                                              ##assuming you want the UI on
      networks:
        - "consul"
      ports:
        - "8500:8500"
        - "8600:8600"
    
    networks:
      consul:
        driver: overlay
    

    另外注意,我后来发现没有种子就不能添加更多的consul实例。因此,如果您打算扩大集群节点数,我会从种子入口点删除 timeout 命令及其选项。

    【讨论】:

    • 我已经有一段时间没有重新审视这个部署了——它一直在做它的工作......但是,您的解决方案非常酷。您能解释一下我不清楚的几个方面吗 1. 您能否提供对控制部署的 engine.labels.access 的参考 - 我在任何地方都找不到它,唯一的模糊参考。我有 Docker UCP(我们不使用) 2. 什么是“种子”的工作 - 为什么不直接启动集群?
    • 我发现引导集群所必需的种子,一旦它全部运行,种子就会停止并且不再需要。在 Consul 文档的某处,它说只有一个节点可以使用引导选项。对于标签检查 - docs.docker.com/engine/reference/commandline/node_update/…
    • 我仍然不清楚您的标签是如何工作的。在撰写文件中,您有如下放置约束constraints: - "engine.labels.access == temp" - "engine.labels.access != consul" 这些约束似乎是互斥的('temp' 可以 never 等于 'consul')。因此我的问题。
    • 标签可以随心所欲地设置,这只是一个虚构的例子,我有一些节点标记为 temp,一些节点标记为 consul,一些节点标记为两者。我希望将服务安排到具有临时标签的任何节点上,只要它也没有领事标签。
    猜你喜欢
    • 1970-01-01
    • 2017-01-18
    • 1970-01-01
    • 2017-09-26
    • 1970-01-01
    • 2016-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多