使用 Swarm 模式路由网格
Docker Engine Swarm 模式使得为服务发布端口以使其可供 Swarm 外部资源访问变得容易。所有节点都参与一个 ingress 路由网格。路由网格使得 Swarm 中的每个节点都可以接受通过发布端口对 Swarm 中运行的任何服务进行的连接,即使该节点上没有运行任务。路由网格将所有传入的请求路由到可用节点上发布端口的活跃容器。
要在 Swarm 中使用 ingress 网络,您需要在启用 Swarm 模式之前在 Swarm 节点之间打开以下端口
- 端口
7946
TCP/UDP 用于容器网络发现。 - 端口
4789
UDP(可配置)用于容器 ingress 网络。
在设置 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 和 UDP 端口时,如果省略协议指定符,则该端口将作为 TCP 端口发布。如果您使用更长的语法(推荐),请将 protocol
键设置为 tcp
或 udp
。
仅 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 节点上(无论该节点是否运行指定服务)的已发布端口时,您会被透明地重定向到正在运行该服务的 worker 节点。实际上,Docker 为您的 Swarm 服务充当了负载均衡器。
您可以绕过路由网格,这样当您访问给定节点上绑定的端口时,您始终访问的是在该节点上运行的服务实例。这被称为 host
模式。需要记住一些事项。
如果您访问未运行服务任务的节点,则服务不会在该端口上监听。可能没有任何程序在监听,或者一个完全不同的应用程序在监听。
如果您希望在每个节点上运行多个服务任务(例如,您有 5 个节点但运行 10 个副本),则无法指定静态目标端口。您可以允许 Docker 分配一个随机的高编号端口(通过省略
published
),或者通过使用全局服务而不是复制服务,或者通过使用放置约束来确保在给定节点上只运行一个服务实例。
要绕过路由网格,您必须使用长格式的 --publish
服务语法并将 mode
设置为 host
。如果您省略 mode
键或将其设置为 ingress
,则使用路由网格。以下命令创建了一个使用 host
模式并绕过路由网格的全局服务。
$ docker service create --name dns-cache \
--publish published=53,target=53,protocol=udp,mode=host \
--mode global \
dns-cache
配置外部负载均衡器
您可以为 Swarm 服务配置外部负载均衡器,可以与路由网格结合使用,也可以完全不使用路由网格。
使用路由网格
您可以配置外部负载均衡器将请求路由到 Swarm 服务。例如,您可以配置 HAProxy 来均衡路由到发布在端口 8080 上的 nginx 服务的请求。


在这种情况下,负载均衡器和 Swarm 中的节点之间必须打开端口 8080。Swarm 节点可以位于代理服务器可访问但不公开可访问的私有网络上。
您可以配置负载均衡器来均衡 Swarm 中每个节点之间的请求,即使该节点上没有调度任务。例如,您可以在 /etc/haproxy/haproxy.cfg
中进行以下 HAProxy 配置
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 调度程序将任务分派到不同的节点,您无需重新配置负载均衡器。
您可以配置任何类型的负载均衡器来将请求路由到 Swarm 节点。要了解有关 HAProxy 的更多信息,请参阅 HAProxy 文档。
不使用路由网格
要在不使用路由网格的情况下使用外部负载均衡器,请将 --endpoint-mode
设置为 dnsrr
,而不是默认值 vip
。在这种情况下,没有单个虚拟 IP。相反,Docker 会为服务设置 DNS 条目,以便对服务名称进行 DNS 查询返回一个 IP 地址列表,并且客户端直接连接到其中一个地址。
您不能同时使用 --endpoint-mode dnsrr
和 --publish mode=ingress
。您必须在服务前面运行自己的负载均衡器。对 Docker 主机上的服务名称进行 DNS 查询会返回运行该服务的节点 IP 地址列表。配置您的负载均衡器以使用此列表并在节点之间平衡流量。请参阅配置服务发现。