使用覆盖网络进行网络连接
本系列教程涉及群服务的网络。 有关独立容器的网络,请参阅 独立容器的网络。如果您需要 了解更多关于Docker网络的信息,请参阅 概述。
本页面包含以下教程。您可以在Linux、Windows或Mac上运行每个教程,但对于最后一个教程,您需要在其他地方运行第二个Docker主机。
使用默认的覆盖网络 展示了如何使用Docker在初始化或加入swarm时自动为您设置的默认覆盖网络。此网络不是生产系统的最佳选择。
使用用户定义的覆盖网络展示了如何创建和使用您自己的自定义覆盖网络来连接服务。建议在生产环境中运行的服务使用此方法。
为独立容器使用覆盖网络 展示了如何使用覆盖网络在不同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的安装说明进行操作。
演练
创建集群
在此过程结束时,所有三个Docker主机将加入群集,并使用名为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 \ nginxingress的默认发布模式,当您没有为--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
使用用户定义的覆盖网络
先决条件
本教程假设群集已经设置好,并且您正在管理器上。
演练
创建用户定义的覆盖网络。
$ 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端口。
这个例子将我们的集群中的两个节点称为host1和host2。这个例子也使用了Linux主机,但相同的命令在Windows上也适用。
逐步讲解
设置集群。
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相同的网络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