使用 Swarm 模式路由网格

Docker Engine Swarm 模式可以轻松发布服务端口,使它们可供 Swarm 外部的资源使用。所有节点都参与入口路由网格。路由网格使集群中的每个节点都可以接受集群中运行的任何服务的已发布端口上的连接,即使该节点上没有运行任何任务。路由网格将所有传入请求路由到可用节点上已发布端口的活动容器。

要在 Swarm 中使用入口网络,您需要在启用 Swarm 模式之前在 Swarm 节点之间打开以下端口:

  • 7946用于容器网络发现的 TCP/UDP端口。
  • 4789容器入口网络的端口UDP(可配置)。

在 Swarm 中建立网络时,应特别小心。请参阅教程 以获取概述。

您还必须打开 swarm 节点与需要访问该端口的任何外部资源(例如外部负载均衡器)之间的已发布端口。

您还可以 绕过给定服务的路由网格。

为服务发布端口

--publish创建服务时使用该标志来发布端口。target 用于指定容器内部的端口,published用于指定在路由网格上绑定的端口。如果您保留published 端口,则会为每个服务任务绑定一个随机的高编号端口。您需要检查任务以确定端口。

$ docker service create \
  --name <SERVICE-NAME> \
  --publish published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
  <IMAGE>

笔记

此语法的旧形式是用冒号分隔的字符串,其中发布的端口是第一个,目标端口是第二个,例如 -p 8080:80。新语法是首选,因为它更易于阅读并且具有更大的灵活性。

<PUBLISHED-PORT>是 Swarm 提供服务的端口。如果省略它,则会绑定随机的高编号端口。这<CONTAINER-PORT>是容器侦听的端口。此参数是必需的。

例如,以下命令将 nginx 容器中的端口 80 发布到 swarm 中任何节点的端口 8080:

$ docker service create \
  --name my-web \
  --publish published=8080,target=80 \
  --replicas 2 \
  nginx

当您访问任何节点上的 8080 端口时,Docker 会将您的请求路由到活动容器。在 swarm 节点本身上,端口 8080 实际上可能并未绑定,但路由网格知道如何路由流量并防止发生任何端口冲突。

路由网格在已发布的端口上侦听分配给该节点的任何 IP 地址。对于外部可路由 IP 地址,该端口可从主机外部使用。对于所有其他 IP 地址,只能从主机内部进行访问。

服务入口图片

您可以使用以下命令为现有服务发布端口:

$ docker service update \
  --publish-add published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
  <SERVICE>

您可以用来docker service inspect查看服务的已发布端口。例如:

$ docker service inspect --format="{{json .Endpoint.Spec.Ports}}" my-web

[{"Protocol":"tcp","TargetPort":80,"PublishedPort":8080}]

输出显示容器中的 <CONTAINER-PORT>(标记为)和节点侦听服务请求的(标记为)。TargetPort<PUBLISHED-PORT>PublishedPort

仅发布 TCP 或 UDP 端口

默认情况下,当您发布端口时,它是 TCP 端口。您可以专门发布 UDP 端口来代替 TCP 端口或除了 TCP 端口之外。当您同时发布 TCP 和 UDP 端口时,如果省略协议说明符,则该端口将发布为 TCP 端口。如果您使用较长的语法(推荐),请将键设置protocoltcpudp

仅 TCP

长语法:

$ docker service create --name dns-cache \
  --publish published=53,target=53 \
  dns-cache

简短语法:

$ docker service create --name dns-cache \
  -p 53:53 \
  dns-cache

TCP 和 UDP

长语法:

$ docker service create --name dns-cache \
  --publish published=53,target=53 \
  --publish published=53,target=53,protocol=udp \
  dns-cache

简短语法:

$ docker service create --name dns-cache \
  -p 53:53 \
  -p 53:53/udp \
  dns-cache

仅UDP

长语法:

$ docker service create --name dns-cache \
  --publish published=53,target=53,protocol=udp \
  dns-cache

简短语法:

$ docker service create --name dns-cache \
  -p 53:53/udp \
  dns-cache

绕过路由网格

默认情况下,发布端口的 Swarm 服务使用路由网格来发布端口。当您连接到任何 swarm 节点上的已发布端口(无论它是否正在运行给定服务)时,您都会被透明地重定向到正在运行该服务的工作线程。实际上,Docker 充当集群服务的负载均衡器。

您可以绕过路由网格,以便当您访问给定节点上的绑定端口时,您始终访问在该节点上运行的服务的实例。这称为host模式。有几件事需要记住。

  • 如果您访问未运行服务任务的节点,则该服务不会侦听该端口。有可能什么都没有在监听,或者有一个完全不同的应用程序正在监听。

  • 如果您希望在每个节点上运行多个服务任务(例如当您有 5 个节点但运行 10 个副本时),则无法指定静态目标端口。要么允许 Docker 分配一个随机的高编号端口(通过省略 published),要么通过使用全局服务而不是复制服务,或者使用放置约束来确保给定节点上只有一个服务实例运行。

要绕过路由网格,您必须使用长--publish服务并设置modehost。如果省略该mode键或将其设置为ingress,则使用路由网格。以下命令使用 host模式创建全局服务并绕过路由网格。

$ docker service create --name dns-cache \
  --publish published=53,target=53,protocol=udp,mode=host \
  --mode global \
  dns-cache

配置外部负载均衡器

您可以结合路由网格或根本不使用路由网格,为群服务配置外部负载均衡器。

使用路由网格

您可以配置外部负载均衡器以将请求路由到 swarm 服务。例如,您可以配置 HAProxy以平衡对发布到端口 8080 的 nginx 服务的请求。

带有外部负载均衡器镜像的入口

在这种情况下,负载均衡器和 swarm 中的节点之间的端口 8080 必须打开。群节点可以驻留在代理服务器可访问的专用网络上,但不可公开访问。

您可以配置负载均衡器来平衡 swarm 中每个节点之间的请求,即使该节点上没有计划任务也是如此。例如,您可以在 中具有以下 HAProxy 配置/etc/haproxy/haproxy.cfg

global
        log /dev/log    local0
        log /dev/log    local1 notice
...snip...

# Configure HAProxy to listen on port 80
frontend http_front
   bind *:80
   stats uri /haproxy?stats
   default_backend http_back

# Configure HAProxy to route requests to swarm nodes on port 8080
backend http_back
   balance roundrobin
   server node1 192.168.99.100:8080 check
   server node2 192.168.99.101:8080 check
   server node3 192.168.99.102:8080 check

当您在端口 80 上访问 HAProxy 负载均衡器时,它会将请求转发到 swarm 中的节点。群路由网格将请求路由到活动任务。如果出于任何原因 swarm 调度程序将任务分派到不同的节点,您无需重新配置负载均衡器。

您可以配置任何类型的负载均衡器以将请求路由到 Swarm 节点。要了解有关 HAProxy 的更多信息,请参阅 HAProxy 文档

没有路由网格

要在没有路由网格的情况下使用外部负载均衡器,请设置--endpoint-modednsrr而不是默认值vip。在这种情况下,不存在单个虚拟IP。相反,Docker 为服务设置 DNS 条目,以便对服务名称的 DNS 查询返回 IP 地址列表,并且客户端直接连接到其中之一。

您不能--endpoint-mode dnsrr与 一起使用--publish mode=ingress。您必须在服务前面运行自己的负载均衡器。对 Docker 主机上的服务名称进行 DNS 查询会返回运行该服务的节点的 IP 地址列表。配置负载均衡器以使用此列表并平衡节点之间的流量。请参阅 配置服务发现

了解更多