使用 overlay 网络进行联网
本系列教程讲解 swarm 服务的网络。有关独立容器的网络连接,请参阅 使用独立容器进行联网。如果您需要详细了解 Docker 网络,请参阅概览。
本页包含以下教程。您可以在 Linux、Windows 或 Mac 上运行它们中的每一个,但最后一个教程需要另一台正在运行的 Docker 主机。
使用默认的 overlay 网络 演示了如何在初始化或加入 swarm 时使用 Docker 自动为您设置的默认 overlay 网络。此网络不是生产系统的最佳选择。
使用用户定义的 overlay 网络 演示了如何创建和使用您自己的自定义 overlay 网络来连接服务。这对于在生产环境中运行的服务是推荐的做法。
为独立容器使用 overlay 网络 演示了如何使用 overlay 网络在不同 Docker 守护进程上的独立容器之间进行通信。
前提条件
这些教程要求您至少拥有一个单节点 swarm,这意味着您已经在主机上启动了 Docker 并运行了 docker swarm init
命令。您也可以在多节点 swarm 上运行这些示例。
使用默认的 overlay 网络
在此示例中,您将启动一个 alpine
服务,并从单个服务容器的角度检查网络的特性。
本教程不涉及 overlay 网络如何实现的特定于操作系统的细节,而是侧重于从服务的角度来看 overlay 如何工作。
前提条件
本教程需要三台物理或虚拟 Docker 主机,它们之间都可以相互通信。本教程假设这三台主机在同一网络上运行,且没有涉及防火墙。
这些主机将被称为 manager
、worker-1
和 worker-2
。manager
主机将兼作 manager 和 worker,这意味着它可以运行服务任务并管理 swarm。worker-1
和 worker-2
将仅作为 worker 运行,
如果您手边没有三台主机,一个简单的解决方案是在 Amazon EC2 等云提供商上设置三台 Ubuntu 主机,所有主机都在同一网络上,并且允许该网络上的所有主机之间进行所有通信(使用 EC2 安全组等机制),然后按照 在 Ubuntu 上安装 Docker Engine - Community 的说明进行操作。
演练
创建 swarm
在此步骤结束时,所有三台 Docker 主机都将加入 swarm,并将使用名为 ingress
的 overlay 网络连接在一起。
在
manager
主机上,初始化 swarm。如果主机只有一个网络接口,--advertise-addr
标志是可选的。$ docker swarm init --advertise-addr=<IP-ADDRESS-OF-MANAGER>
记下打印出的文本,因为它包含用于将
worker-1
和worker-2
加入 swarm 的令牌。建议将令牌存储在密码管理器中。在
worker-1
主机上,加入 swarm。如果主机只有一个网络接口,--advertise-addr
标志是可选的。$ docker swarm join --token <TOKEN> \ --advertise-addr <IP-ADDRESS-OF-WORKER-1> \ <IP-ADDRESS-OF-MANAGER>:2377
在
worker-2
主机上,加入 swarm。如果主机只有一个网络接口,--advertise-addr
标志是可选的。$ docker swarm join --token <TOKEN> \ --advertise-addr <IP-ADDRESS-OF-WORKER-2> \ <IP-ADDRESS-OF-MANAGER>:2377
在
manager
主机上,列出所有节点。此命令只能从 manager 执行。$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS d68ace5iraw6whp7llvgjpu48 * ip-172-31-34-146 Ready Active Leader nvp5rwavvb8lhdggo8fcf7plg ip-172-31-35-151 Ready Active ouvx2l7qfcxisoyms8mtkgahw ip-172-31-36-89 Ready Active
您也可以使用
--filter
标志按角色过滤$ docker node ls --filter role=manager ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS d68ace5iraw6whp7llvgjpu48 * ip-172-31-34-146 Ready Active Leader $ docker node ls --filter role=worker ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS nvp5rwavvb8lhdggo8fcf7plg ip-172-31-35-151 Ready Active ouvx2l7qfcxisoyms8mtkgahw ip-172-31-36-89 Ready Active
在
manager
、worker-1
和worker-2
主机上列出 Docker 网络,注意每个主机现在都有一个名为ingress
的 overlay 网络和一个名为docker_gwbridge
的桥接网络。此处仅显示manager
主机上的列表$ docker network ls NETWORK ID NAME DRIVER SCOPE 495c570066be bridge bridge local 961c6cae9945 docker_gwbridge bridge local ff35ceda3643 host host local trtnl4tqnc3n ingress overlay swarm c8357deec9cb none null local
docker_gwbridge
将 ingress
网络连接到 Docker 主机的网络接口,以便流量可以在 swarm manager 和 worker 之间流动。如果您创建 swarm 服务时未指定网络,它们将连接到 ingress
网络。建议为每个应用程序或协同工作的应用程序组使用单独的 overlay 网络。在下一个步骤中,您将创建两个 overlay 网络并将服务连接到其中每一个。
创建服务
在
manager
主机上,创建一个名为nginx-net
的新 overlay 网络$ docker network create -d overlay nginx-net
您无需在其他节点上创建此 overlay 网络,因为当其中一个节点开始运行需要它的服务任务时,它将自动创建。
在
manager
主机上,创建一个连接到nginx-net
的 5 副本 Nginx 服务。该服务将把端口 80 发布到外部世界。所有服务任务容器都可以相互通信,无需打开任何端口。注意
服务只能在 manager 主机上创建。
$ docker service create \ --name my-nginx \ --publish target=80,published=80 \ --replicas=5 \ --network nginx-net \ nginx
默认的
ingress
发布模式(在您未为--publish
标志指定模式时使用)意味着如果您浏览到manager
、worker-1
或worker-2
主机上的端口 80,您将被连接到其中一个 5 个服务任务的端口 80,即使您浏览的节点当前没有运行任何任务。如果您想使用host
模式发布端口,您可以将mode=host
添加到--publish
输出。但是,在这种情况下,您也应该使用--mode global
而不是--replicas=5
,因为一个给定节点上的给定端口只能由一个服务任务绑定。运行
docker service ls
命令来监控服务启动进度,这可能需要几秒钟。在
manager
、worker-1
和worker-2
主机上检查nginx-net
网络。请记住,您无需在worker-1
和worker-2
上手动创建它,因为 Docker 已经为您创建了。输出会很长,但请注意Containers
和Peers
部分。Containers
列出了从该主机连接到 overlay 网络的所有服务任务(或独立容器)。从
manager
主机上,使用docker service inspect my-nginx
命令检查服务,并注意服务使用的端口和端点信息。创建一个新网络
nginx-net-2
,然后更新服务以使用此网络代替nginx-net
$ docker network create -d overlay nginx-net-2
$ docker service update \ --network-add nginx-net-2 \ --network-rm nginx-net \ my-nginx
运行
docker service ls
命令验证服务已更新且所有任务已重新部署。运行docker network inspect nginx-net
命令验证没有容器连接到它。对nginx-net-2
运行相同的命令,并注意所有服务任务容器都已连接到它。注意
即使 overlay 网络会在 swarm worker 节点上按需自动创建,它们也不会自动移除。
清理服务和网络。从
manager
主机上,运行以下命令。manager 将指示 worker 自动移除网络。$ docker service rm my-nginx $ docker network rm nginx-net nginx-net-2
使用用户定义的 overlay 网络
前提条件
本教程假设 swarm 已设置好,并且您位于 manager 主机上。
演练
创建用户定义的 overlay 网络。
$ docker network create -d overlay my-overlay
使用 overlay 网络启动服务,并将端口 80 发布到 Docker 主机上的端口 8080。
$ docker service create \ --name my-nginx \ --network my-overlay \ --replicas 1 \ --publish published=8080,target=80 \ nginx:latest
运行
docker network inspect my-overlay
命令并查看Containers
部分,验证my-nginx
服务任务已连接到它。移除服务和网络。
$ docker service rm my-nginx $ docker network rm my-overlay
为独立容器使用 overlay 网络
此示例演示了 DNS 容器发现 -- 特别是如何使用 overlay 网络在不同 Docker 守护进程上的独立容器之间进行通信。步骤如下:
- 在
host1
上,将节点初始化为 swarm (manager)。 - 在
host2
上,将节点加入 swarm (worker)。 - 在
host1
上,创建一个可附加的 overlay 网络 (test-net
)。 - 在
host1
上,在test-net
上运行一个交互式 alpine 容器 (alpine1
)。 - 在
host2
上,在test-net
上运行一个交互式 (-it
) 且分离 (-d
) 的 alpine 容器 (alpine2
)。 - 在
host1
上,在alpine1
的会话中,pingalpine2
。
前提条件
此测试需要两台可以相互通信的不同 Docker 主机。每台主机必须在两台 Docker 主机之间打开以下端口:
- TCP 端口 2377
- TCP 和 UDP 端口 7946
- UDP 端口 4789
一种简单的设置方法是准备两台虚拟机(本地或在 AWS 等云提供商上),每台都安装并运行 Docker。如果您使用 AWS 或类似的云计算平台,最简单的配置是使用一个安全组,该安全组在两台主机之间以及从您客户端 IP 地址到 SSH 端口打开所有入站端口。
此示例将 swarm 中的两个节点称为 host1
和 host2
。此示例也使用 Linux 主机,但相同的命令在 Windows 上也适用。
演练
设置 swarm。
a. 在
host1
上,初始化 swarm(如果出现提示,请使用--advertise-addr
指定用于与 swarm 中其他主机通信的接口的 IP 地址,例如 AWS 上的私有 IP 地址)$ docker swarm init Swarm initialized: current node (vz1mm9am11qcmo979tlrlox42) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-5g90q48weqrtqryq4kj6ow0e8xm9wmv9o6vgqc5j320ymybd5c-8ex8j0bc40s6hgvy5ui5gl4gy 172.31.47.252:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
b. 在
host2
上,按照上述说明加入 swarm$ docker swarm join --token <your_token> <your_ip_address>:2377 This node joined a swarm as a worker.
如果节点未能加入 swarm,
docker swarm join
命令将超时。要解决此问题,请在host2
上运行docker swarm leave --force
,验证您的网络和防火墙设置,然后再次尝试。在
host1
上,创建一个名为test-net
的可附加 overlay 网络$ docker network create --driver=overlay --attachable test-net uqsof8phj3ak0rq9k86zta6ht
注意返回的 NETWORK ID -- 当您从
host2
连接到它时,您会再次看到它。在
host1
上,启动一个连接到test-net
的交互式 (-it
) 容器 (alpine1
)$ docker run -it --name alpine1 --network test-net alpine / #
在
host2
上,列出可用的网络 -- 注意test-net
尚不存在$ docker network ls NETWORK ID NAME DRIVER SCOPE ec299350b504 bridge bridge local 66e77d0d0e9a docker_gwbridge bridge local 9f6ae26ccb82 host host local omvdxqrda80z ingress overlay swarm b65c952a4b2b none null local
在
host2
上,启动一个连接到test-net
的分离 (-d
) 且交互式 (-it
) 容器 (alpine2
)$ docker run -dit --name alpine2 --network test-net alpine fb635f5ece59563e7b8b99556f816d24e6949a5f6a5b1fbd92ca244db17a4342
注意
自动 DNS 容器发现仅适用于唯一的容器名称。
在
host2
上,验证test-net
已创建(并且与host1
上的test-net
具有相同的 NETWORK ID)$ docker network ls NETWORK ID NAME DRIVER SCOPE ... uqsof8phj3ak test-net overlay swarm
在
host1
上,在alpine1
的交互式终端中 pingalpine2
/ # ping -c 2 alpine2 PING alpine2 (10.0.0.5): 56 data bytes 64 bytes from 10.0.0.5: seq=0 ttl=64 time=0.600 ms 64 bytes from 10.0.0.5: seq=1 ttl=64 time=0.555 ms --- alpine2 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.555/0.577/0.600 ms
这两个容器通过连接两台主机的 overlay 网络进行通信。如果您在
host2
上运行另一个未分离的 alpine 容器,您可以从host2
pingalpine1
(这里我们添加 remove 选项 以自动清理容器)$ docker run -it --rm --name alpine3 --network test-net alpine / # ping -c 2 alpine1 / # exit
在
host1
上,关闭alpine1
会话(这也将停止容器)/ # exit
清理容器和网络
您必须在每台主机上独立停止和移除容器,因为 Docker 守护进程独立运行且这些是独立容器。您只需要在
host1
上移除网络,因为当您在host2
上停止alpine2
时,test-net
就会消失。a. 在
host2
上,停止alpine2
,检查test-net
是否已移除,然后移除alpine2
$ docker container stop alpine2 $ docker network ls $ docker container rm alpine2
a. 在
host1
上,移除alpine1
和test-net
$ docker container rm alpine1 $ docker network rm test-net