Docker覆盖网络(overlay network)驱动程序的原理和用法详解

覆盖网络驱动程序在多个Docker后台程序主机之间创建分布式网络。该网络位于(覆盖)特定主机的网络之上,允许连接到它的容器(包括swarm服务容器)安全地进行通信。 Docker透明地把每个数据包从Docker后台程序主机处理并路由到目标容器。

当您初始化swarm或将Docker主机加入现有swarm时,会在该Docker主机上创建两个新网络:

  • 称为ingress的覆盖网络,用于处理与swarm服务相关的控制和数据通信。创建swarm服务并且不将其连接到用户定义的覆盖网络时,默认情况下它会连接到ingress网络。
  • 一个名为docker_gwbridge的桥接网络,它将各个Docker后台程序连接到参与swarm的其他后台程序。

您可以使用docker network create创建用户定义的覆盖网络,与创建用户定义的桥接网络方法相同。服务或容器一次可以连接到多个网络。服务或容器只能通过它们各自连接的网络进行通信。

虽然swarm服务和独立容器都可以连接到覆盖网络,但默认行为和配置问题是不同的。因此,本主题的其余部分分为适用于所有覆盖网络的操作,适用于swarm服务网络的操作以及适用于独立容器使用的覆盖网络的操作。

所有覆盖网络的操作

创建覆盖网络

先决条件

  • 使用覆盖网络的Docker后台程序的防火墙规则。

您需要打开以下端口,这些端口用于在覆盖网络上与每个参与的Docker主机的通信:

  • 用于集群管理通信的TCP端口2377

  • TCP和UDP端口7946用于节点之间的通信

  • UDP端口4789用于覆盖网络通信

  • 在创建覆盖网络之前,您需要使用docker swarm init将Docker后台程序初始化为swarm管理器,或者使用docker swarm join将其连接到现有的swarm。 它们都会创建默认的ingress覆盖网络,默认情况下由swarm服务使用。 即使您从未计划使用swarm服务,也需要执行此操作。 之后,您可以创建其他用户定义的覆盖网络。

要创建用于swarm服务的覆盖网络,请使用如下命令:

$ docker network create -d overlay my-overlay

要创建可由swarm服务或独立容器用于与在其他Docker后台程序上运行的其他独立容器通信的覆盖网络,请添加--attachable标记:

$ docker network create -d overlay --attachable my-attachable-overlay

您可以指定IP地址范围,子网,网关和其他选项。 有关详细信息,请参阅docker network create --help

加密覆盖网络上的通信

默认情况下,使用GCM模式下的AES算法加密所有swarm服务管理通信。 swarm中的管理器节点每隔12小时轮换用于加密数据的密钥。

要加密应用程序数据,请在创建覆盖网络时添加--opt encrypted。 这样可以在vxlan级别启用IPSEC加密。 此加密会产生不可忽视的性能损失,因此您应该在生产中使用它之前测试此选项。

启用覆盖加密后,Docker会在所有节点之间创建IPSEC隧道,在这些节点上为连接到覆盖网络的服务安排任务。 这些隧道还在GCM模式下使用AES算法,管理器节点每12小时自动轮换密钥。

不要将Windows节点连接到加密的覆盖网络。

Windows不支持覆盖网络加密。 如果Windows节点尝试连接到加密的覆盖网络,则不会检测到错误,但节点无法通信。

SWARM模式覆盖网络和独立容器

您可以将覆盖网络功能--opt encrypted --attachable一起使用,并将非托管容器附加到该网络:

$ docker network create --opt encrypted --driver overlay --attachable my-attachable-multi-host-network

自定义默认ingress网络

大多数用户从不需要配置ingress网络,但Docker 17.05及更高版本允许您这样做。 如果自动选择的子网与网络上已存在的子网冲突,或者您需要自定义其他低级网络设置(如MTU),则此功能非常有用。

自定义ingress网络涉及删除和重新创建它。 这通常在您在swarm中创建任何服务之前完成。 如果您那你已经有服务发布了端口,则需要先删除这些服务,然后才能删除ingress网络。

在没有ingress网络的时候,没有发布端口的服务继续运行但没有负载均衡功能。 这会影响发布端口的服务,例如发布在80端口的WordPress服务。

  1. 使用docker network inspect ingress检查ingress网络,并删除任何容器与其连接的服务。 这些是发布端口的服务,例如发布在80端口的WordPress服务。如果未停止所有此类服务,则下一步将失败。

  2. 删除现有的ingress网络:

$ docker network rm ingress

WARNING! Before removing the routing-mesh network, make sure all the nodes
in your swarm run the same docker engine version. Otherwise, removal may not
be effective and functionality of newly created ingress networks will be
impaired.
Are you sure you want to continue? [y/N]
  1. 使用--ingress标记以及要设置的自定义选项创建一个新的覆盖网络。 本示例将MTU设置为1200,将子网设置为10.11.0.0/16,并将网关设置为10.11.0.2
$ docker network create   --driver overlay   --ingress   --subnet=10.11.0.0/16   --gateway=10.11.0.2   --opt com.docker.network.driver.mtu=1200   my-ingress

**注意:**您可以使用除ingress之外的其他名称来命名您的ingress网络,但只能有一个。 尝试创建第二个将失败。

  1. 重新启动您在第一步中停止的服务。

自定义docker_gwbridge接口

docker_gwbridge是一个虚拟网桥,用于将覆盖网络(包括入口网络)连接到个人的Docker后台程序的物理网络。 当您初始化swarm或将Docker主机加入swarm时,Docker会自动创建它,但它不是Docker的设备。 它存在于Docker主机的内核中。 如果需要自定义其设置,则必须在将Docker主机加入群集之前或从群集中暂时删除主机之后进行。

  1. 停止Docker。
  2. 删除已存在的docker_gwbridge接口。
$ sudo ip link set docker_gwbridge down

$ sudo ip link del dev docker_gwbridge
  1. 启动Docker。 不要加入或初始化swarm。
  2. 使用docker network create命令和自定义设置手动创建或重新创建docker_gwbridge网桥。 本示例使用子网10.11.0.0/16。 有关可自定义选项的完整列表,请参阅网桥驱动程序选项
$ docker network create   --subnet 10.11.0.0/16   --opt com.docker.network.bridge.name=docker_gwbridge   --opt com.docker.network.bridge.enable_icc=false   --opt com.docker.network.bridge.enable_ip_masquerade=true   docker_gwbridge
  1. 初始化或加入swarm。 由于该网桥已经存在,因此Docker不会使用自动设置来创建它。

swarm服务的操作

在覆盖网络上发布端口

连接到同一覆盖网络的swarm服务高效地将所有端口彼此公开。 为了使端口可以在服务外部访问,必须使用docker service createdocker service update上的-p--publish标记发布该端口。 支持旧的冒号分隔的语法和较新的逗号分隔的值语法。首选较长的语法,因为它自身有文档的作用。 | 标记值 | 描述 | | :---- | :---- | | -p 8080:80 or -p published=8080,target=80 | 将服务上的TCP端口80映射到路由网格上的端口8080。 | | -p 8080:80/udp or -p published=8080,target=80,protocol=udp | 将服务上的UDP端口80映射到路由网格上的端口8080。 | | -p 8080:80/tcp -p 8080:80/udp or -p published=8080,target=80,protocol=tcp -p published=8080,target=80,protocol=udp | 将服务上的TCP端口80映射到路由网格上的TCP端口8080,并将服务上的UDP端口80映射到路由网格上的UDP端口8080。 |

绕过路由网格以实现swarm服务

默认情况下,swarm服务使用路由网格发布端口。当您连接到任何swarm节点上的已发布端口时(无论它是否正在运行给定服务),您都将透明地重定向到正在运行该服务的工作节点。实际上,Docker充当了swarm服务的负载均衡器。使用路由网格的服务以虚拟IP(VIP)模式运行。甚至在每个节点上运行的服务(通过--mode全局标记)也使用路由网格。使用路由网格时,无法保证客户端请求具体哪个Docker节点的服务。

要绕过路由网格,可以通过将--endpoint-mode标记设置为dnsrr来使用DNS Round Robin(DNSRR)模式启动服务。您必须在服务之前运行自己的负载均衡。在Docker主机上对服务名称进行DNS查询会返回运行该服务的节点的IP地址列表。配置您的负载均衡使用此列表并平衡节点之间的流量。

控制和数据流量分开

默认情况下,但与群集管理有关的控制通信和进出您的应用程序的通信在同一网络上运行,尽管群集控制通信已加密。您可以将Docker配置为使用单独的网络接口来处理两种不同类型的流量。初始化或加入群集时,请分别指定--advertise-addr--datapath-addr。您必须对加入群集的每个节点执行此操作。

覆盖网络上独立容器的操作

将独立容器连接到覆盖网络

创建ingress网络时没有使用--attachable标记,这意味着只有swarm服务可以使用它,而独立容器不可以。 您可以将独立容器连接到使用--attachable标记创建的用户定义的覆盖网络。 这使运行在不同Docker后台程序上的独立容器能够进行通信,而无需在各个Docker后台程序主机上设置路由。

标记值 描述
-p 8080:80 将容器中的TCP端口80映射到覆盖网络上的端口8080。
-p 8080:80/udp 将容器中的UDP端口80映射到覆盖网络上的端口8080。
-p 8080:80/sctp 将容器中的SCTP端口80映射到覆盖网络上的端口8080。
-p 8080:80/tcp -p 8080:80/udp 将容器中的TCP端口80映射到覆盖网络上的端口8080,将容器中的UDP端口80映射到覆盖网络上的端口8080。

容器发现

在大多数情况下,您应该连接到服务名称,该名称是负载均衡的,并由支持该服务的所有容器(“任务”)处理。 要获取支持该服务的所有任务的列表,请对tasks.<service-name>进行DNS查找。

下一步