使用覆盖网络进行网络连接
本系列教程涉及 Swarm 服务的网络配置。 关于独立容器的网络配置,请参阅 独立容器的网络配置。如果您需要 进一步了解 Docker 网络的总体情况,请参阅 概述。
本页面包含以下教程。您可以在 Linux、Windows 或 Mac 上运行每个教程,但对于最后一个教程,您需要在其他地方运行第二个 Docker 主机。
使用默认覆盖网络 演示了如何使用 Docker 在初始化或加入集群时自动为您设置的默认覆盖网络。该网络并不是生产系统的最佳选择。
使用用户定义的覆盖网络 展示了 如何创建和使用您自己的自定义覆盖网络,以连接服务。 这对于在生产环境中运行的服务是推荐的。
为独立容器使用覆盖网络 展示了如何使用覆盖网络在不同Docker守护进程上的独立容器之间进行通信。
前提条件
这些要求您至少有一个单节点集群,这意味着您已经启动了 Docker 并在主机上运行了 docker swarm init。您也可以在多节点集群上运行这些示例。
使用默认覆盖网络
在此示例中,您启动一个 alpine 服务,并从单个服务容器的角度检查网络的特征。
本教程不涉及操作系统特定的覆盖网络实现细节,而是重点介绍从服务角度来看覆盖网络的功能。
前提条件
本教程需要三台可以相互通信的物理或虚拟 Docker 主机。本教程假设这三台主机运行在同一网络上,且不涉及防火墙。
这些主机将被称为 manager、worker-1 和 worker-2。manager 主机将同时作为管理节点和工作节点,这意味着它既可以运行服务任务,也可以管理集群。worker-1 和 worker-2 将仅作为工作节点,
如果您手头没有三台主机,一个简单的解决方案是在云提供商(如 Amazon EC2)上设置三台 Ubuntu 主机,所有主机位于同一网络,并允许该网络上的所有主机之间进行所有通信(使用 EC2 安全组等机制),然后按照Ubuntu 上安装 Docker Engine - Community 的说明进行操作。
演练
创建 Swarm
在本过程结束时,所有三个 Docker 主机将加入 swarm,并使用名为 ingress 的覆盖网络相互连接。
在
manager上初始化 swarm。如果主机只有一个网络接口,--advertise-addr标志是可选的。$ docker swarm init --advertise-addr=<IP-ADDRESS-OF-MANAGER>请记下打印出的文本,因为其中包含用于将
worker-1和worker-2加入到群集的令牌。将令牌存储在密码管理器中是一个好主意。在
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上,列出所有节点。此命令只能从管理节点执行。$ 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的 bridge 网络。此处仅显示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 管理节点和工作节点之间流动。如果您创建 swarm 服务且未指定网络,它们将连接到 ingress 网络。建议为每个应用程序或需要协同工作的应用程序组使用独立的 overlay 网络。在接下来的步骤中,您将创建两个 overlay 网络并将服务分别连接到它们。
创建服务
在
manager上,创建一个名为nginx-net的新覆盖网络:$ docker network create -d overlay nginx-net您不需要在其他节点上创建覆盖网络,因为当其中一个节点开始运行需要该网络的服务任务时,它将自动创建。
在
manager上,创建一个连接到nginx-net的 5 副本 Nginx 服务。 该服务将端口 80 发布到外部。服务的所有任务容器可以在不打开任何端口的情况下相互通信。注意
服务只能在管理节点上创建。
$ docker service create \ --name my-nginx \ --publish target=80,published=80 \ --replicas=5 \ --network nginx-net \ nginxingress的默认发布模式,当您没有为--publish标志指定mode时使用,意味着如果您浏览到manager、worker-1或worker-2上的端口 80,您将连接到 5 个服务任务之一的端口 80,即使您浏览到的节点上当前没有运行任何任务。如果您想使用host模式发布端口,可以将mode=host添加到--publish输出中。但是,在这种情况下,您还应该使用--mode global而不是--replicas=5,因为只有一个服务任务可以在给定节点上绑定给定端口。运行
docker service ls以监控服务启动的进度,这可能需要几秒钟。检查
nginx-net网络在manager、worker-1和worker-2上的情况。 请记住,您不需要在worker-1和worker-2上手动创建它,因为 Docker 已经为您创建了。输出结果会很长,但请注意Containers和Peers部分。Containers列出了从该主机连接到覆盖网络的所有服务任务(或独立容器)。从
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运行相同的命令,并注意到所有服务任务容器都连接到它。注意
尽管覆盖网络会根据需要在 swarm 工作节点上自动创建,但它们不会自动移除。
清理服务和网络。从
manager开始,运行以下命令。管理器将指示工作节点自动删除网络。$ docker service rm my-nginx $ docker network rm nginx-net nginx-net-2
使用用户定义的覆盖网络
前提条件
本教程假设 Swarm 已经设置完成,并且你位于管理节点上。
演练
创建用户定义的覆盖网络。
$ docker network create -d overlay my-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并验证my-nginx服务任务已连接到它,方法是查看Containers部分。删除服务和网络。
$ docker service rm my-nginx $ docker network rm my-overlay
为独立容器使用覆盖网络
此示例演示了 DNS 容器发现——具体来说,如何使用覆盖网络在不同 Docker 守护进程上的独立容器之间进行通信。步骤如下:
- 在
host1上,将节点初始化为一个 swarm(管理节点)。 - 在
host2上,将节点加入 swarm (worker)。 - 在
host1上,创建一个可附加的覆盖网络 (test-net)。 - 在
host1上,运行一个交互式的 alpine 容器 (alpine1),位于test-net。 - 在
host2上,运行一个交互式且分离的, alpine 容器 (alpine2),位于test-net上。 - 在
host1上,从alpine1的会话中,pingalpine2。
前提条件
对于此测试,您需要两台能够相互通信的不同Docker主机。每台主机必须在两台Docker主机之间开放以下端口:
- TCP 端口 2377
- TCP 和 UDP 端口 7946
- UDP 端口 4789
一种简单的方法是设置两台虚拟机(可以是本地或AWS等云提供商上的),每台都安装并运行Docker。如果您使用AWS或类似的云计算平台,最简单的配置是使用一个安全组,打开两台主机之间的所有入站端口以及来自您客户端IP地址的SSH端口。
此示例将我们群集中的两个节点称为 host1 和 host2。
此示例也使用 Linux 主机,但相同的命令在 Windows 上也适用。
Walk-through
设置集群。
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.如果节点无法加入集群,
docker swarm join命令会超时。要解决此问题,请在host2上运行docker swarm leave --force,检查您的网络和防火墙设置,然后重试。在
host1上,创建一个名为test-net的可附加覆盖网络:$ docker network create --driver=overlay --attachable test-net uqsof8phj3ak0rq9k86zta6ht注意返回的 NETWORK ID -- 当你从
host2连接到它时,你将再次看到它。在
host1上,启动一个交互式 (-it) 容器 (alpine1),该容器连接到test-net:$ 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上,启动一个分离的 (-d) 和交互式的 (-it) 容器 (alpine2),该容器连接到test-net:$ 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这两个容器通过连接两个主机的覆盖网络进行通信。如果您在
host2上运行另一个 非分离 的 alpine 容器, 您可以从host2pingalpine1(这里我们添加了 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 alpine2a. 在
host1上,删除alpine1和test-net:$ docker container rm alpine1 $ docker network rm test-net