使用覆盖网络联网
本系列教程讨论了针对 Swarm 服务的网络。有关独立容器的网络,请参阅 独立容器的网络。如果您需要了解有关 Docker 网络的更多信息,请参阅 概述。
本页包含以下教程。您可以在 Linux、Windows 或 Mac 上运行每个教程,但对于最后一个教程,您需要另一个在其他位置运行的 Docker 主机。
使用默认覆盖网络 演示了如何使用 Docker 在您初始化或加入 Swarm 时自动为您设置的默认覆盖网络。此网络不是生产系统的最佳选择。
使用用户定义的覆盖网络 展示了如何创建和使用您自己的自定义覆盖网络来连接服务。建议在生产环境中运行的服务使用此方法。
将覆盖网络用于独立容器 展示了如何使用覆盖网络在不同 Docker 守护程序上的独立容器之间进行通信。
先决条件
这些教程要求您至少拥有单个节点 Swarm,这意味着您已启动 Docker 并在主机上运行了 docker swarm init
。您也可以在多节点 Swarm 上运行这些示例。
使用默认覆盖网络
在此示例中,您启动 alpine
服务并从各个服务容器的角度检查网络的特性。
本教程不会深入介绍有关覆盖网络实现方式的操作系统特定细节,而是重点介绍覆盖网络从服务角度的功能。
先决条件
本教程需要三个物理或虚拟 Docker 主机,这些主机可以彼此通信。本教程假设这三个主机在同一个网络上运行,并且没有涉及防火墙。
这些主机将分别称为 manager
、worker-1
和 worker-2
。manager
主机将同时充当管理器和工作节点,这意味着它可以同时运行服务任务和管理 Swarm。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
加入 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
上,列出所有节点。此命令只能从管理器执行。$ 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
的覆盖网络和一个名为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 管理器和工作节点。如果您创建 Swarm 服务并且没有指定网络,它们将连接到 ingress
网络。建议您为每个应用程序或将协同工作的应用程序组使用单独的覆盖网络。在下一个过程中,您将创建两个覆盖网络并将服务连接到每个网络。
创建服务
在
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 \ nginx
ingress
的默认发布模式(在您未为--publish
标志指定mode
时使用)意味着如果您浏览到manager
、worker-1
或worker-2
上的端口 80,您将连接到 5 个服务任务之一的端口 80,即使当前没有任务在您浏览到的节点上运行。如果您想使用host
模式发布端口,可以在--publish
输出中添加mode=host
。但是,在这种情况下,您还应该使用--mode global
而不是--replicas=5
,因为在给定节点上,只有一个服务任务可以绑定给定端口。运行
docker service ls
以监控服务启动的进度,这可能需要几秒钟。检查
manager
、worker-1
和worker-2
上的nginx-net
网络。请记住,您无需在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(工作节点)。 - 在
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 端口。
此示例将我们 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
的可附加覆盖网络$ 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 容器,则可以从host2
pingalpine1
(并且在这里我们添加了删除选项,以便自动清理容器)$ 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