如何使用 Docker 1.12 swarm mode 部署 Consul

12

我有一个由3个服务器组成的Consul集群。我还有一个由大约6个工作节点和3个主节点(主节点与Consul服务器在同一台硬件上,但设置为availability == drain,以防止它们接受工作)的Docker Swarm。

通常我使用consul-template来读取Consul K/V。我无法想出如何明智地推出Consul Agent服务。如果我使用全局服务,则会在每个节点上获得一个代理程序,但是服务器群集会抱怨,因为所有客户端代理程序都似乎具有相同的IP地址。

复制的服务似乎是正确的方法,但我认为我需要发布客户端端口8301,这似乎会与我的服务器群集(正在运行Swarm主节点和Consul服务器(不在Docker下))发生冲突。

请指点一般方向-请注意,这是1.12群集模式,因此与早期版本非常不同。

4个回答

6

虽然令人困惑,但Docker“Swarm Mode”实际上与仍称为Docker Swarm的内容不同。在Swarm Mode中,您不需要Consul。每个主机上的docker守护进程充当键值存储并执行服务发现。它可以完成“旧”Docker Swarm中所需的Consul的所有工作。

只需小心查找特定于“swarm mode”的文档/信息。实际上,我希望他们使用了不同的名称。


真的吗?你是在说我可以让Consul-Template读取我的应用程序值吗?我知道在实现Swarm功能时不需要它,但我们将其用于更多功能。 - MarkH
通常情况下,consul-template 用于更新 nginx 或 haproxy 的配置。它基本上是在服务器列表中添加或删除 IP 地址以进行负载均衡。但在 Swarm 模式下这是不必要的,你可以让 Docker 来做负载均衡。最好使用 nginx(例如)来处理 SSL、gzip 和安全等问题,但其配置文件只需使用 DNS 名称“myservice”作为上游服务器即可。如果你已经创建了一个名为“myservice”的 Docker 服务,Docker 将对正确的容器进行负载均衡。 - Bernard
我们使用consul-template来为一大堆遗留应用程序填充文件 - 我很难看到这可以通过仅使用swarm实现。我理解swarm现在实现了许多以前依赖第三方工具的服务发现和负载平衡。但作为一个通用的K/V存储,我就是看不到如何使用它。 - MarkH
@MarkH 我明白你的意思。简而言之,我认为在Docker 1.12中不可能实现。 Docker 1.13可能会添加所需的更改。更长的故事: 新的Swarm Mode使用内部kv存储(基于etcd),但仅供其自己使用。此外,没有办法监听有关启动/停止容器/服务的事件。这是计划在Docker 1.13中实现的功能 https://github.com/docker/docker/issues/23827。 Registrator需要此功能来更新Consul。如果您现在确实需要某些内容,则可以使用Docker Remote API进行轮询,但这就像编写自己的Registrator。 - Bernard
我正在使用Consul作为自己的微服务的键值存储,这与主机名完全无关。Traefik也在使用它。 - holms
我正在使用Consul作为自己的微服务的键值存储,这与主机名完全无关。Traefik也在使用它。 - holms

6
经过长时间的思考和多次失败后,我们终于找到了适合我们的解决方案。问题的一部分是在撰写本文时,Docker 1.12还比较新生,引入了许多需要理解的概念才能使其有意义。在我们的情况下,我们之前使用的早期版Swarm阻碍了我们的前进思路,而没有帮助。
我们利用以下解决方案来部署我们的Swarm中的consul K/V服务:
创建名为“consul”的叠加网络。这样可以为我们的服务创建一个地址空间。 docker network create --driver overlay --subnet 10.10.10.0/24 consul 将consul服务器集群部署到新的覆盖层中。我们有三个主机被用作管理节点,并且我们希望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),将其映射到三个新实例。
接下来,我们部署了代理服务: 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 端口不危险吗? - joonas.fi
发布端口给谁?我们整个网络实际上是一个DMZ。只有在同一VLAN上的设备才能访问这些服务,因此风险是最小的。我很好奇你会用什么其他方法 - 我们总是开放的,欢迎任何可以改进我们部署的方式。 - MarkH
1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - joonas.fi
不确定原因,但只是一个警告 - 创建服务导致3个Docker Swarm管理节点中的2个崩溃,并且无法恢复,出现了有关Docker服务守护程序的错误:Error starting daemon: layer does not exist - Brandon

3
在我的博客中,我探讨了与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

我正在使用全局模式(global mode)在 3 节点集群中,因此您可以将其替换为副本并设置约束条件。


最初我们使用的是与此相同的retry-join集合。然而,使用VIP似乎更加简洁。一旦集群建立,负载均衡器就不再参与,因为gossip协议将传播单个集群成员的IP地址而不是VIP。当我们进行研究时,我希望我们能找到您的博客... - MarkH
@MarkH,我也是!我们花了好几天时间才想出来的。: )。不过关于VIP的那个很有趣,我们可能需要做更多的研究来了解它们是如何工作的。 - Jared Mackey
1
发布代理端口不危险吗?您不希望Consul API可以被互联网访问。我猜您可以通过防火墙规则来阻止互联网访问,但这似乎有悖于Docker的网络模型(私有端口与公开端口)。 - joonas.fi
是的,这样做可能很危险,但我们在防火墙后面。我不确定如何在不发布它们的情况下访问它们。 - Jared Mackey
请提供Compose版本 :)?那些IP是什么,我无法将设置绑定到任何IP,它应该是动态的。 - holms

3
对于像我这样喜欢从docker-compose.yml文件运行服务的人,我成功地使用“docker stack deploy”将Consul作为Docker服务运行。以下是链接:https://github.com/thechane/consul/blob/master/docker-compose.yml
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 实例。因此,如果您打算扩展您的 Swarm 节点计数,建议从种子入口点中删除超时命令及其选项。


我发现引导集群所需的种子,在所有运行时种子停止并且不再需要。Consul文档中有一处提到,只有一个节点可以使用引导选项。 关于标签检查,请参阅-https://docs.docker.com/engine/reference/commandline/node_update/#examples - thechane
我仍然不清楚你的标签是如何工作的。在compose文件中,您有以下放置约束条件: constraints: - "engine.labels.access == temp" - "engine.labels.access != consul" 这些约束条件似乎是互斥的('temp'永远不能等于'consul')。因此我的问题是。 - MarkH
标签可以按照您的意愿进行设置,这只是一个想象中的示例,其中我将一些节点标记为temp,一些标记为consul,还有一些标记为两者都有。我希望服务被安排在任何具有temp标签的节点上,只要它没有consul标签即可。 - thechane
在compose文件中,{{ GetInterfaceIP ... }}是什么东西? - James Mills
1
这是一个文档不良的Consul特性。 https://godoc.org/github.com/hashicorp/go-sockaddr/template https://github.com/hashicorp/consul/issues/2217 - thechane
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接