使用覆盖网络进行网络连接
本系列教程介绍了Swarm服务的网络配置。有关独立容器的网络配置,请参见独立容器的网络配置。如果您需要了解有关Docker网络的更多信息,请参见概述。
此页面包含以下教程。您可以在Linux、Windows或Mac上运行每个教程,但对于最后一个教程,您需要在其他地方运行第二个Docker主机。
使用默认overlay网络演示了如何使用Docker在初始化或加入Swarm时自动为您设置的默认overlay网络。此网络不是生产系统的最佳选择。
使用用户定义的overlay网络展示了如何创建和使用您自己的自定义overlay网络来连接服务。建议用于生产环境中运行的服务。
为独立容器使用overlay网络展示了如何使用overlay网络在不同Docker守护程序上的独立容器之间进行通信。
前提条件
这些都需要您至少拥有一个单节点Swarm,这意味着您已启动Docker并在主机上运行了docker swarm init
。您也可以在多节点Swarm上运行这些示例。
使用默认overlay网络
在此示例中,您启动一个alpine
服务,并从各个服务容器的角度检查网络的特性。
本教程不会深入介绍有关overlay网络实现方式的操作系统特定细节,而是重点介绍从服务的角度来看overlay的功能。
前提条件
本教程需要三个物理或虚拟Docker主机,它们都可以相互通信。本教程假设三个主机运行在同一网络上,并且没有涉及防火墙。
这些主机将分别称为manager
、worker-1
和worker-2
。manager
主机将同时充当管理器和工作节点,这意味着它可以同时运行服务任务和管理Swarm。worker-1
和worker-2
将仅充当工作节点。
如果您没有三个主机可用,一个简单的解决方案是在云提供商(例如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
上,列出所有节点。此命令只能从管理器执行。$ 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 管理节点和工作节点。如果您创建 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
使用用户定义的overlay网络
前提条件
本教程假设 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
并通过查看Containers
部分来验证my-nginx
服务任务是否已连接到它。删除服务和网络。
$ docker service rm my-nginx $ docker network rm my-overlay
为独立容器使用overlay网络
此示例演示了 DNS 容器发现——具体来说,是如何使用覆盖网络在不同 Docker 守护程序上的独立容器之间进行通信的。步骤如下:
- 在
host1
上,将节点初始化为 Swarm(管理节点)。 - 在
host2
上,将节点加入 Swarm(工作节点)。 - 在
host1
上,创建一个可附加的覆盖网络(test-net
)。 - 在
host1
上,在test-net
上运行一个交互式alpine容器(alpine1
)。 - 在
host2
上,运行一个交互式和分离的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
的可附加覆盖网络。$ docker network create --driver=overlay --attachable test-net uqsof8phj3ak0rq9k86zta6ht
注意返回的网络 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
上,启动一个分离的(-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 容器,您可以从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