overlay
网络驱动在多个 Docker daemon 宿主机之间建立一个分布式网络。这张大网建立在特定的主机之上(也就是 overlay 的由来),它允许连接到它的容器(包括 swarm 编排下的容器)在启用加密后安全地进行通信。Docker 透明地处理每一个数据包的路由,使其往返于正确的 Docker daemon 宿主机和正确的目标容器之间。
当你初始化一个 Swarm 或将一个Docker主机加入到一个现有的Swarm时,在该Docker主机上会创建两个新的网络:
ingress
的 overlay 网络,它处理与 swarm 服务相关的控制和数据流量。当你创建一个 swarm 服务,并且没有把它连接到用户定义的 overlay 网络时,它默认连接到 ingress
网络。docker_gwbridge
的 bridge 网络,它将单个 Docker daemon 与 Swarm 里的其他daemon 连接起来。你可以使用 docker network create
来创建用户定义的 overlay
网络,就像你可以创建用户定义的 bridge
网络一样。服务或容器可以同时连接到一个以上的网络。服务或容器只能在它们各自所连接的网络中进行通信。
尽管你可以将 swarm 服务和独立容器都连接到覆盖网络上,但默认行为和配置关注点是不同的。由于这个原因,本主题的其余部分被分为适用于所有 overlay 网络的操作、适用于 swarm 服务网络的操作以及适用于独立容器使用的 overlay 网络的操作。
先决条件:
使用了 overlay 网络的 Docker daemon 的防火墙规则
你需要开放以下端口,以便于进行 overlay 网络的每个 Docker 主机通信 :
- TCP 端口 2377 ,集群管理通讯
- TCP 与 UDP 端口 7946 ,节点间通讯
- UDP 端口 4789,overlay 网络通讯
在创建 overlay 网络之前,你需要使用
docker swarm init
将你的 Docker daemon 初始化为集群管理器,或者使用docker swarm join
将其加入到现有的群集中。这两种方法中的任何一种都会创建默认的ingress
overlay 网络,该网络默认被 swarm 服务使用。即使你从未打算使用 swarm 服务,你也需要这样做。在此之后,你可以创建额外的用户定义的覆盖网络。
要创建一个用于 swarm 服务的 overlay 网络,使用如下命令:
$ docker network create -d overlay my-overlay
要创建一个可以被 swarm 服务或独立容器使用的 overlay 网络,以便与运行在其他 Docker daemon 上的其他独立容器进行通信,需要添加 --attachable
标志:
$ docker network create -d overlay --attachable my-attachable-overlay
你可以指定IP地址范围、子网、默认网关,以及其他的选项。详情请执行 docker network create --help
。
所有的 swarm 服务的管理流量默认都是加密的,在GCM模式下使用 AES 算法 。swarm 中的管理节点每12小时轮换一次用于加密数据的密钥。
同样的,要对应用数据进行加密,在创建 overlay 网络时添加 --opt encrypted
。这将在 vxlan 层面上启用 IPSEC 加密。这种加密会带来不可忽视的性能损失,所以你应该在生产中使用这个选项之前进行性能测试。
当你启用 overlay 的加密时,Docker 会在所有为连接到 overlay 网络的服务安排任务的节点之间创建 IPSEC 隧道(有点拗口,其实就是 overlay 节点间)。这些隧道也在 GCM 模式下使用 AES 算法,管理节点每12小时自动轮换一次密钥。
不要把 Windows 节点连接到加密的 overlay 网络里。
Windows 不支持 overlay 网络的加密。如果 Windows 节点加入了一个加密的 overlay 网络,不会检测到错误,但节点无法通讯。
Swarm 模式的 overlay 网络以及独立的容器
你可以用 --opt encrypted --attachable
两种方式使用 overlay 网络功能,并将未受管理的容器附加到该网络上:
$ docker network create --opt encrypted --driver overlay --attachable my-attachable-multi-host-network
大多数用户从来不需要配置 ingress
网络,但 Docker 允许你这样做。如果自动选择的子网与你的网络上已经存在的子网相冲突,或者你需要定制其他的底层网络设置,如 MTU 大小,这时就会很有用。
自定义ingress
网络的过程包括移除并重新创建它。这通常是在你在 swarm 中创建任何服务之前完成的。如果你有一些服务已经公开过端口(用 -p 或者 --publish),那在你删除 ingress
网络之前,这些服务需要被先被删除。
在没有ingress
网络时,没有公开端口的服务继续运行,但无负载均衡。但有公开端口的服务则会被影响,例如公开了80端口的WordPress服务。
使用 docker network inspect ingress
命令来查看ingress
网络,并删除所有有容器连接到它的服务。这些服务都是有公开端口的,比如公开了80端口的WordPress服务。如果所有这些服务都没有停止,那么下一步就会失败。
移除现有的 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]
用 --ingress
标志以及你想设置的自定义选项创建一个 overlay 网络。下面的例子把 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
之外的名字,但你只能创建一个。试图创建第二个网络会失败。
重启你在第一步停掉的服务们。
docker_gwbridge
是一个虚拟网桥,它将叠加网络(包括ingress
网络)连接到单个Docker daemon的物理网络。当你初始化 swarm 或将 Docker 主机加入 swarm 时,Docker 会自动创建它,但它并不是一个 Docker 设备。它处于 Docker 宿主机的内核中。如果你要配置它,就需要把对应的 Docker 宿主机加入到 swarm 之前,或者是先暂时把宿主机从 swarm 里面移除出去的时候进行。
停掉 Docker。
删除现有的 docker_gwbridge
设备.
$ sudo ip link set docker_gwbridge down
$ sudo ip link del dev docker_gwbridge
启动 Docker。 不要加入或者初始化 swarm。
使用 docker network create
命令,用你的自定义设置手动创建或重新创建 docker_gwbridge
网桥。下面的例子把子网设置为 10.11.0.0/16
。完整的可选配置请参考 Bridge driver options.
$ 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
初始化或者加入 swarm. 由于网桥已经存在,Docker 就不会用自动的配置来再次创建它。
连接到同一个 overlay 网络的 swarm 服务,能够有效地访问彼此所有的端口。但如果要一个端口能被外部访问,就要用在 docker service create
或 docker service update
指令里用 -p
或者--publish
标志把对应的端口公开出去。传统的冒号分隔的语法和新的逗号分隔的语法都是支持的。较长的语法是首选,因为它在某种程度上是自我描述(self-documenting)的。
标志值 | 描述 |
---|---|
-p 8080:80 或 -p published=8080,target=80 |
将服务上的TCP 80端口映射到路由网的8080端口。 |
-p 8080:80/udp 或 -p published=8080,target=80,protocol=udp |
将服务上的UDP 80端口映射到路由网的8080端口。 |
-p 8080:80/tcp -p 8080:80/udp 或 -p published=8080,target=80,protocol=tcp -p published=8080,target=80,protocol=udp |
将服务上的TCP 80端口映射到路由网的8080端口,同时将服务上的UDP 80端口映射到路由网的8080端口。 |
默认情况下,swarm 上公开了端口的服务(services)会使用到路由网。当你连接到一个在任意节点(无论此节点跑着有对应的服务)上的公开的端口时,你会被透明地重定向到在跑着此服务(service)的 worker 节点上去。实际上,Docker 充当了 swarm 服务的负载均衡器。在路由网上的服务是以虚拟IP(VIP)模式运行的。即使是能够在每个节点上运行的服务(通过 --mode global
标志)亦如此。使用路由网的时候,不能保证哪个Docker节点为客户端请求提供服务。
要绕过路由网,你可以用 DNS轮询 (DNS Round Robin,DNSRR) 模式 启动服务,方法是把 --endpoint-mode
标志设置为 dnsrr
。你必须在你的服务跑起来之前启动你自己的负载均衡器。在Docker 宿主机上对服务名称的DNS查询会返回运行该服务的节点的IP地址列表(swarm 安排好的)。配置你的负载均衡器,消耗掉这个列表并在节点之间平衡流量。
默认情况下,有关于 swarm 管理的流量跟你的应用之间的流量都在同一个网络,即使 swarm 的控制流量是加密的。你可以配置 Docker 用分开的网络接口来管理两种不同的流量。当你初始化或者加入一个 swarm 的时候,分开指定 --advertise-addr
和 --datapath-addr
。每个加入 swarm 的节点都需要这么做。
创建 ingress
网络时没有 --attachable
标志,这意味着只有 swarm 服务可以使用它,独立容器则不行。你可以把独立容器连接到一个用 --attachable
标志创建的用户定义 overlay 网络。这给了跑在不同 Docker daemon 上的独立容器互通的能力,而不用在各自的 Docker daemon 宿主机去设置路由。
标志值 | 描述 |
---|---|
-p 8080:80 |
将容器上的TCP 80端口映射到 overlay 的8080端口。 |
-p 8080:80/udp |
将容器上的UDP 80端口映射到 overlay 的8080端口。 |
-p 8080:80/sctp |
将容器上的SCTP 80端口映射到 overlay 的8080端口。 |
-p 8080:80/tcp -p 8080:80/udp |
将容器上的TCP 80端口映射到 overlay 的8080端口。同时将容器上的UDP 80端口映射到 overlay 的8080端口。 |
在大多数的情况下,你应该连接一个服务名。它是由服务后端的所有容器("tasks")进行负载平衡和处理的。要获得服务所有的后端 tasks,请对 tasks.
进行DNS查询。