管理 swarm 服务网络
本页介绍 Swarm 服务的网络。
Swarm 和流量类型
Docker Swarm 生成两种不同类型的流量
控制和管理平面流量:这包括 Swarm 管理消息,例如加入或离开 Swarm 的请求。此流量始终加密。
应用程序数据平面流量:这包括容器流量和往返于外部客户端的流量。
关键网络概念
以下三个网络概念对 Swarm 服务非常重要
覆盖网络管理参与 Swarm 的 Docker 守护进程之间的通信。您可以创建覆盖网络,就像为独立容器创建用户定义网络一样。您还可以将服务附加到一个或多个现有的覆盖网络,以实现服务到服务的通信。覆盖网络是使用 `overlay` 网络驱动程序的 Docker 网络。
入口网络是一个特殊的覆盖网络,它有助于服务节点之间的负载均衡。当任何 Swarm 节点在已发布的端口上收到请求时,它会将该请求传递给一个名为 `IPVS` 的模块。`IPVS` 跟踪参与该服务的所有 IP 地址,选择其中一个,并通过 `ingress` 网络将请求路由到它。
当您初始化或加入 Swarm 时,`ingress` 网络会自动创建。大多数用户不需要自定义其配置,但 Docker 允许您这样做。
`docker_gwbridge` 是一个桥接网络,它将覆盖网络(包括 `ingress` 网络)连接到单个 Docker 守护进程的物理网络。默认情况下,服务运行的每个容器都连接到其本地 Docker 守护进程主机的 `docker_gwbridge` 网络。
当您初始化或加入 Swarm 时,`docker_gwbridge` 网络会自动创建。大多数用户不需要自定义其配置,但 Docker 允许您这样做。
提示另请参阅 网络概述 以获取有关 Swarm 网络的更多详细信息。
防火墙注意事项
参与 Swarm 的 Docker 守护进程需要能够通过以下端口进行通信
- 端口 `7946` TCP/UDP 用于容器网络发现。
- 端口 `4789` UDP(可配置)用于覆盖网络(包括入口)数据路径。
在 Swarm 中设置网络时,应特别小心。有关概述,请参阅教程。
覆盖网络
当您初始化一个 Swarm 或将一个 Docker 主机加入到现有 Swarm 时,该 Docker 主机上会创建两个新网络
- 一个名为 `ingress` 的覆盖网络,它处理与 Swarm 服务相关的控制和数据流量。当您创建一个 Swarm 服务并且没有将其连接到用户定义的覆盖网络时,它会默认连接到 `ingress` 网络。
- 一个名为 `docker_gwbridge` 的桥接网络,它将单个 Docker 守护进程连接到参与 Swarm 的其他守护进程。
创建覆盖网络
要创建覆盖网络,请在使用 `docker network create` 命令时指定 `overlay` 驱动程序
$ docker network create \
--driver overlay \
my-network
上述命令没有指定任何自定义选项,因此 Docker 会分配一个子网并使用默认选项。您可以使用 `docker network inspect` 查看有关网络的信息。
当没有容器连接到覆盖网络时,其配置并不是很令人兴奋
$ docker network inspect my-network
[
{
"Name": "my-network",
"Id": "fsf1dmx3i9q75an49z36jycxd",
"Created": "0001-01-01T00:00:00Z",
"Scope": "swarm",
"Driver": "overlay",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": []
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"Containers": null,
"Options": {
"com.docker.network.driver.overlay.vxlanid_list": "4097"
},
"Labels": null
}
]
在上面的输出中,请注意驱动程序是 `overlay`,作用域是 `swarm`,而不是您可能在其他类型的 Docker 网络中看到的 `local`、`host` 或 `global` 作用域。此作用域表示只有参与 Swarm 的主机才能访问此网络。
当服务首次连接到网络时,网络的子网和网关是动态配置的。以下示例显示了与上面相同的网络,但有三个 `redis` 服务的容器连接到它。
$ docker network inspect my-network
[
{
"Name": "my-network",
"Id": "fsf1dmx3i9q75an49z36jycxd",
"Created": "2017-05-31T18:35:58.877628262Z",
"Scope": "swarm",
"Driver": "overlay",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "10.0.0.0/24",
"Gateway": "10.0.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"Containers": {
"0e08442918814c2275c31321f877a47569ba3447498db10e25d234e47773756d": {
"Name": "my-redis.1.ka6oo5cfmxbe6mq8qat2djgyj",
"EndpointID": "950ce63a3ace13fe7ef40724afbdb297a50642b6d47f83a5ca8636d44039e1dd",
"MacAddress": "02:42:0a:00:00:03",
"IPv4Address": "10.0.0.3/24",
"IPv6Address": ""
},
"88d55505c2a02632c1e0e42930bcde7e2fa6e3cce074507908dc4b827016b833": {
"Name": "my-redis.2.s7vlybipal9xlmjfqnt6qwz5e",
"EndpointID": "dd822cb68bcd4ae172e29c321ced70b731b9994eee5a4ad1d807d9ae80ecc365",
"MacAddress": "02:42:0a:00:00:05",
"IPv4Address": "10.0.0.5/24",
"IPv6Address": ""
},
"9ed165407384f1276e5cfb0e065e7914adbf2658794fd861cfb9b991eddca754": {
"Name": "my-redis.3.hbz3uk3hi5gb61xhxol27hl7d",
"EndpointID": "f62c686a34c9f4d70a47b869576c37dffe5200732e1dd6609b488581634cf5d2",
"MacAddress": "02:42:0a:00:00:04",
"IPv4Address": "10.0.0.4/24",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.driver.overlay.vxlanid_list": "4097"
},
"Labels": {},
"Peers": [
{
"Name": "moby-e57c567e25e2",
"IP": "192.168.65.2"
}
]
}
]
自定义覆盖网络
在某些情况下,您可能不想使用覆盖网络的默认配置。有关可配置选项的完整列表,请运行命令 `docker network create --help`。以下是一些最常更改的选项。
配置子网和网关
默认情况下,当第一个服务连接到网络时,会自动配置网络的子网和网关。您可以在创建网络时使用 `--subnet` 和 `--gateway` 标志来配置这些。以下示例通过配置子网和网关扩展了前一个示例。
$ docker network create \
--driver overlay \
--subnet 10.0.9.0/24 \
--gateway 10.0.9.99 \
my-network
使用自定义默认地址池
要自定义 Swarm 网络的子网分配,您可以在 `swarm init` 期间选择性地配置它们。
例如,以下命令在初始化 Swarm 时使用
$ docker swarm init --default-addr-pool 10.20.0.0/16 --default-addr-pool-mask-length 26
每当用户创建一个网络,但未使用 `--subnet` 命令行选项时,该网络的子网将从池中下一个可用的子网顺序分配。如果指定的网络已分配,则该网络将不用于 Swarm。
如果需要不连续的地址空间,可以配置多个池。但是,不支持从特定池进行分配。网络子网将从 IP 池空间顺序分配,并且当子网从已删除的网络中释放时,它们将被重用。
可以配置默认掩码长度,并且对所有网络都相同。默认设置为 `/24`。要更改默认子网掩码长度,请使用 `--default-addr-pool-mask-length` 命令行选项。
注意默认地址池只能在 `swarm init` 时配置,并且在集群创建后无法更改。
覆盖网络大小限制
Docker 建议使用 `/24` 块创建覆盖网络。`/24` 覆盖网络块将网络限制为 256 个 IP 地址。
此建议解决了Swarm 模式的限制。如果您需要超过 256 个 IP 地址,请不要增加 IP 块大小。您可以使用带有外部负载均衡器的 `dnsrr` 端点模式,或使用多个较小的覆盖网络。有关不同端点模式的更多信息,请参阅配置服务发现。
配置应用程序数据加密
与 Swarm 相关的管理和控制平面数据始终是加密的。有关加密机制的更多详细信息,请参阅 Docker Swarm 模式覆盖网络安全模型。
Swarm 节点之间的应用程序数据默认不加密。要在给定的覆盖网络上加密此流量,请在 `docker network create` 上使用 `--opt encrypted` 标志。这将在 vxlan 级别启用 IPSEC 加密。此加密会带来不可忽视的性能损失,因此您应在生产中使用此选项之前进行测试。
注意您必须自定义自动创建的入口网络以启用加密。默认情况下,所有入口流量都是未加密的,因为加密是一个网络级别的选项。
将服务附加到覆盖网络
要将服务附加到现有覆盖网络,请将 `--network` 标志传递给 `docker service create`,或将 `--network-add` 标志传递给 `docker service update`。
$ docker service create \
--replicas 3 \
--name my-web \
--network my-network \
nginx
连接到覆盖网络的服务容器可以通过它相互通信。
要查看服务连接到哪些网络,请使用 `docker service ls` 查找服务名称,然后使用 `docker service ps <service-name>` 列出网络。或者,要查看哪些服务的容器连接到网络,请使用 `docker network inspect <network-name>`。您可以从任何已加入 Swarm 且处于 `running` 状态的 Swarm 节点运行这些命令。
配置服务发现
服务发现是 Docker 用于将来自服务外部客户端的请求路由到单个 Swarm 节点,而客户端无需知道参与服务的节点数量或其 IP 地址或端口的机制。您不需要发布在同一网络上服务之间使用的端口。例如,如果您有一个将数据存储在 MySQL 服务中的 WordPress 服务,并且它们连接到同一个覆盖网络,则无需向客户端发布 MySQL 端口,只需发布 WordPress HTTP 端口即可。
服务发现可以通过两种不同的方式工作:使用嵌入式 DNS 和虚拟 IP (VIP) 在第 3 层和第 4 层进行基于内部连接的负载均衡,或使用 DNS 轮询 (DNSRR) 在第 7 层进行基于外部和自定义请求的负载均衡。您可以为每个服务配置此项。
默认情况下,当您将服务附加到网络并且该服务发布一个或多个端口时,Docker 会为该服务分配一个虚拟 IP (VIP),这是客户端访问该服务的前端。Docker 会保留服务中所有工作节点的列表,并在客户端和一个节点之间路由请求。来自客户端的每个请求都可能被路由到不同的节点。
如果您将服务配置为使用 DNS 轮询 (DNSRR) 服务发现,则没有单个虚拟 IP。相反,Docker 会为服务设置 DNS 条目,以便对服务名称的 DNS 查询返回一个 IP 地址列表,客户端直接连接到其中一个。
当您想要使用自己的负载均衡器(例如 HAProxy)时,DNS 轮询非常有用。要将服务配置为使用 DNSRR,请在创建新服务或更新现有服务时使用 `--endpoint-mode dnsrr` 标志。
自定义入口网络
大多数用户永远不需要配置 `ingress` 网络,但 Docker 允许您这样做。如果自动选择的子网与网络上已存在的子网冲突,或者您需要自定义其他低级网络设置(如 MTU),或者您想启用加密,这可能会很有用。
自定义 `ingress` 网络涉及删除并重新创建它。这通常在您在 Swarm 中创建任何服务之前完成。如果您有发布端口的现有服务,则需要先删除这些服务,然后才能删除 `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` 标志创建一个新的覆盖网络,并附带您要设置的自定义选项。此示例将 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
`docker_gwbridge` 是一个虚拟网桥,它将覆盖网络(包括 `ingress` 网络)连接到单个 Docker 守护进程的物理网络。当您初始化一个 Swarm 或将一个 Docker 主机加入到 Swarm 时,Docker 会自动创建它,但它不是一个 Docker 设备。它存在于 Docker 主机的内核中。如果您需要自定义其设置,则必须在将 Docker 主机加入 Swarm 之前或暂时从 Swarm 中删除主机之后进行。
您需要在操作系统上安装 `brctl` 应用程序才能删除现有网桥。包名为 `bridge-utils`。
停止 Docker。
使用 `brctl show docker_gwbridge` 命令检查是否存在名为 `docker_gwbridge` 的网桥设备。如果存在,请使用 `brctl delbr docker_gwbridge` 删除它。
启动 Docker。不要加入或初始化 Swarm。
使用您的自定义设置创建或重新创建 `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初始化或加入 Swarm。
为控制和数据流量使用单独的接口
默认情况下,所有 Swarm 流量都通过同一个接口发送,包括用于维护 Swarm 本身的控制和管理流量以及往返于服务容器的数据流量。
您可以在初始化或加入 Swarm 时通过传递 `--data-path-addr` 标志来分离此流量。如果有多个接口,则必须明确指定 `--advertise-addr`,如果未指定,`--data-path-addr` 默认为 `--advertise-addr`。有关加入、离开和管理 Swarm 的流量通过 `--advertise-addr` 接口发送,服务容器之间的流量通过 `--data-path-addr` 接口发送。这些标志可以采用 IP 地址或网络设备名称,例如 `eth0`。
此示例使用单独的 `--data-path-addr` 初始化 Swarm。它假定您的 Docker 主机有两个不同的网络接口:10.0.0.1 应用于控制和管理流量,192.168.0.1 应用于与服务相关的流量。
$ docker swarm init --advertise-addr 10.0.0.1 --data-path-addr 192.168.0.1
此示例加入由主机 `192.168.99.100:2377` 管理的 Swarm,并将 `--advertise-addr` 标志设置为 `eth0`,将 `--data-path-addr` 标志设置为 `eth1`。
$ docker swarm join \
--token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2d7c \
--advertise-addr eth0 \
--data-path-addr eth1 \
192.168.99.100:2377
在覆盖网络上发布端口
连接到同一覆盖网络的 Swarm 服务有效地向彼此公开所有端口。要使端口在服务外部可访问,该端口必须使用 `docker service create` 或 `docker service update` 上的 `-p` 或 `--publish` 标志进行*发布*。支持旧的冒号分隔语法和新的逗号分隔值语法。首选较长的语法,因为它在某种程度上是自文档化的。
| 标志值 | 描述 |
|---|---|
| -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 映射到路由网格上的 TCP 端口 8080,并将服务上的 UDP 端口 80 映射到路由网格上的 UDP 端口 8080。 |