管理Swarm服务网络

此页面描述了Swarm服务的网络配置。

Swarm 和流量类型

Docker Swarm 会生成两种不同类型的流量:

  • 控制和管理平面流量:这包括 Swarm 管理消息,例如加入或离开 Swarm 的请求。此流量始终加密。

  • 应用数据平面流量:这包括容器流量以及来自外部客户端的进出流量。

关键网络概念

以下三个网络概念对Swarm服务至关重要:

  • 覆盖网络负责管理参与集群的 Docker 守护进程之间的通信。您可以像为独立容器创建用户定义的网络一样,创建覆盖网络。此外,还可以将服务附加到一个或多个现有的覆盖网络上,以实现服务间的通信。覆盖网络是使用 overlay 网络驱动程序的 Docker 网络。

  • The ingress network is a special overlay network that facilitates load balancing among a service's nodes. When any swarm node receives a request on a published port, it hands that request off to a module called IPVS. IPVS keeps track of all the IP addresses participating in that service, selects one of them, and routes the request to it, over the ingress network.

    ingress 网络在初始化或加入 swarm 时会自动创建。大多数用户无需自定义其配置,但 Docker 允许您这样做。

  • The docker_gwbridge 是一个网桥网络,用于将覆盖网络(包括 ingress 网络)连接到各个 Docker 守护进程的物理网络。默认情况下,每个运行服务的容器都连接到其本地 Docker 守护进程主机的 docker_gwbridge 网络。

    docker_gwbridge 网络在初始化或加入 Swarm 时会自动创建。大多数用户无需自定义其配置,但 Docker 允许您这样做。

提示

另请参阅 网络概述 以获取有关 Swarm 网络的更多详细信息。

防火墙注意事项

参与 Swarm 的 Docker 守护进程需要通过以下端口进行相互通信:

  • 端口 7946 TCP/UDP 用于容器网络发现。
  • Port 4789 UDP (configurable) for the overlay network (including ingress) data path.

在设置 Swarm 中的网络时,应格外小心。请查阅 教程 以获取概述。

覆盖网络

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

  • 一个名为 ingress 的覆盖网络,用于处理与 Swarm 服务相关的控制流量和数据流量。当您创建 Swarm 服务且未将其连接到用户定义的覆盖网络时,它将默认连接到 ingress 网络。
  • 一个名为 docker_gwbridge 的桥接网络,用于将单个 Docker 守护进程连接到参与集群的其他守护进程。

创建覆盖网络

要创建覆盖网络,在使用 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 网络中看到的 localhostglobal 范围。此范围表示只有参与 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 加密。该加密会带来不可忽视的性能损耗,因此您应在生产环境使用前测试此选项。

注意

您必须 自定义自动创建的 Ingress 以启用加密。默认情况下,所有 Ingress 流量均未加密,因为加密是网络层选项。

将服务附加到覆盖网络

要将服务附加到现有的覆盖网络,请向--network传递docker service create标志,或向docker service update传递--network-add标志。

$ 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>。您可以从任何已加入且处于 running 状态的Swarm节点上运行这些命令。

配置服务发现

服务发现是 Docker 用于将来自您服务外部客户端的请求路由到单个 swarm 节点的机制,而客户端无需知道参与服务的节点数量及其 IP 地址或端口。对于连接到同一网络上的服务之间使用的端口,您无需将其发布到客户端。例如,如果您有一个 使用 MySQL 服务存储数据的 WordPress 服务, 并且它们连接到同一个 overlay 网络,您无需将 MySQL 端口发布给客户端,只需发布 WordPress 的 HTTP 端口。

服务发现可以通过两种不同的方式工作:在第3层和第4层使用嵌入式DNS和虚拟IP(VIP)进行基于连接的内部负载均衡,或在第7层使用DNS轮询(DNSRR)进行外部和定制的基于请求的负载均衡。您可以按服务进行配置。

  • 默认情况下,当你将服务附加到网络并且该服务发布一个或多个端口时,Docker 会为该服务分配一个虚拟 IP(VIP),这是客户端访问服务的“前端”。Docker 会维护一份服务中所有工作节点的列表,并在客户端与其中一个节点之间路由请求。来自客户端的每个请求可能会被路由到不同的节点。

  • 如果你将服务配置为使用DNS轮询(DNSRR)服务发现, 则没有单个虚拟IP。相反,Docker为服务设置DNS条目, 使得对服务名称的DNS查询返回IP地址列表, 客户端直接连接到这些地址中的一个。

    DNS 轮询在你想要使用自己的负载均衡器(如 HAProxy)时很有用。要将服务配置为使用 DNSRR,在创建新服务或更新现有服务时使用标志--endpoint-mode dnsrr

自定义入口网络

大多数用户无需配置ingress网络,但 Docker 允许您进行配置。如果自动选择的子网与您网络上已存在的子网发生冲突,或者您需要自定义其他低级网络设置(如 MTU),或者您想要启用加密,这将非常有用。

自定义 ingress 网络涉及删除并重新创建它。这通常在您在 swarm 中创建任何服务之前完成。如果您有发布端口的现有服务,则需要在删除 ingress 网络之前先删除这些服务。

在不存在 ingress 网络的时间段内,未发布端口的现有服务仍可正常运行,但不会进行负载均衡。这会影响发布端口的服务,例如发布端口 80 的 WordPress 服务。

  1. 检查使用 ingressdocker network inspect 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]
    
  3. 使用--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 之外的名称,但你只能有一个。尝试创建第二个会失败。

  4. 重启在第一步中停止的服务。

自定义 docker_gwbridge

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

您需要在操作系统上安装 brctl 应用程序才能删除现有的桥接器。软件包名称为 bridge-utils

  1. 停止 Docker。

  2. 使用 brctl show docker_gwbridge 命令检查是否存在名为 docker_gwbridge 的桥接设备。如果存在,请使用 brctl delbr docker_gwbridge 删除它。

  3. 启动 Docker。不要加入或初始化 swarm。

  4. 创建或重新创建具有自定义设置的 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
    
  5. 初始化或加入集群。

为控制流量和数据流量使用独立的接口

默认情况下,所有 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 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。

了解更多