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

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

  • 7946用于容器网络发现的端口TCP / UDP。
  • 4789容器入口网络的端口UDP。

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

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

发布一个端口服务

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

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

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

<PUBLISHED-PORT>是集群提供服务的端口。如果您省略它,则将绑定一个随机的高编号端口。该<CONTAINER-PORT>是其中容器侦听的端口。此参数是必需的。

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

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

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

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

docker swarm network调试 docker swarm网络模式_swarm

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

$ 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端口。如果您使用更长的语法(推荐用于Docker 1.13及更高版本),请将protocol属性设置为tcpudp

仅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

绕过路由网格

您可以绕过路由网格,以便在访问给定节点上的绑定端口时,始终可以访问在该节点上运行的服务的实例。这称为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

配置外部负载均衡器

您可以为集群服务配置外部负载均衡器,既可以与路由网格结合使用,也可以完全不使用路由网格。

使用路由网格

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

docker swarm network调试 docker swarm网络模式_docker_02

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

您可以配置负载平衡器以平衡集群中每个节点之间的请求,即使该节点上未计划任何任务也是如此。例如,您可能在以下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负载平衡器时,它将请求转发到集群中的节点。集群路由网格将请求路由到活动任务。如果出于某种原因,群集调度程序将任务分派到不同的节点,则无需重新配置负载均衡器。

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

不使用路由网格

要使用没有路由网格的外部负载均衡器,请设置--endpoint-mode 为dnsrr而不是默认值vip。在这种情况下,没有单个虚拟IP。取而代之的是,Docker为服务设置DNS条目,以便对服务名称的DNS查询返回IP地址列表,并且客户端直接连接到其中之一。您负责向负载均衡器提供IP地址和端口的列表。请参阅 配置服务发现