Docker Engine的swarm模式原生支持覆盖网络(overlay networks),所以你可以启用容器到容器的网络。swarm模式的覆盖网络包括以下功能:
为了可以使用swarm的覆盖网络,在启用swarm模式之间你需要在swarm节点之间开放以下端口:
在swarm中创建一个覆盖网络
当你运行Docker Engine的swarm模式时,你可以在管理节点执行docker network create命令来创建一个覆盖网络。例如,创建一个名为my-network的网络:
- $ docker network create
- –driver overlay
- –subnet 10.0.9.0/24
- –opt encrypted
- my-network
- 273d53261bcdfda5f198587974dae3827e947ccd7e74a41bf1f482ad17fa0d33
默认情况下swarm中的节点通信是加密的。在不同节点的容器之间,可选的–opt encrypted参数能在它们的vxlan流量启用附加的加密层。
–subnet参数指定覆盖网络的子网。当你不指定一个子网时,swarm管理器自动选择一个子网并分配给网络。在一些旧的内核,包括kernel 3.10,自动分配的地址可能会与其它子网重叠。这样的重叠可能引起连接问题。
执行docker network ls来查看网络:
- $ docker network ls
- NETWORK ID NAME DRIVER SCOPE
- f9145f09b38b bridge bridge local
- ..snip..
- 273d53261bcd my-network overlay swarm
swarm scope表示部署到swarm的服务可以使用这个网络。当你创建一个服务并附加到一个网络后,swarm仅仅扩展该网络到服务运行的节点上。在一个没有运行有附加到网络的服务worker节点上,network ls命令不会显示有任何网络。
附加服务到覆盖网络
要附加一个服务到一个覆盖网络,在创建服务的时候传递–network参数。例如创建一个nginx服务并附加到一个名为my-network的网络:
- $ docker service create
- –replicas 3
- –name my-web
- –network my-network
- nginx
注意:在附加服务到网络前,必须先创建这个网络。
在同一个覆盖网络的容器之间能互相连接。在管理节点执行docker service ps 来查看哪些节点运行着这个服务:
- $ docker service ps my-web
- ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
- 63s86gf6a0ms34mvboniev7bs my-web.1 nginx node1 Running Running 58 seconds ago
- 6b3q2qbjveo4zauc6xig7au10 my-web.2 nginx node2 Running Running 58 seconds ago
- 66u2hcrz0miqpc8h0y0f3v7aw my-web.3 nginx node3 Running Running about a minute ago
pic1
你可以在运行着附加有网络的服务的节点上查看这个网络的详情:
- $ docker network inspect <NETWORK>
这个网络信息包括了该节点上附加到该网络的容器的列表。例如:
- $ docker network inspect my-network
- [
- {
- "Name": "my-network",
- "Id": "273d53261bcdfda5f198587974dae3827e947ccd7e74a41bf1f482ad17fa0d33",
- "Scope": "swarm",
- "Driver": "overlay",
- "EnableIPv6": false,
- "IPAM": {
- "Driver": "default",
- "Options": null,
- "Config": [
- {
- "Subnet": "10.0.9.0/24",
- "Gateway": "10.0.9.1"
- }
- ]
- },
- "Internal": false,
- "Containers": {
- "404d1dec939a021678132a35259c3604b9657649437e59060621a17edae7a819": {
- "Name": "my-web.1.63s86gf6a0ms34mvboniev7bs",
- "EndpointID": "3c9588d04db9bc2bf8749cb079689a3072c44c68e544944cbea8e4bc20eb7de7",
- "MacAddress": "02:42:0a:00:09:03",
- "IPv4Address": "10.0.9.3/24",
- "IPv6Address": ""
- }
- },
- "Options": {
- "com.docker.network.driver.overlay.vxlanid_list": "257"
- },
- "Labels": {}
- }
- ]
在上面的示例中,my-web服务的容器my-web.1.63s86gf6a0ms34mvboniev7bs附加到该节点的my-network网络。
使用swarm模式的service discovery
默认情况下,当你创建一个服务并附加到一个网络时,swarm就给服务分配一个VIP。VIP根据服务名称映射到DNS别名。在该网络的容器之间通过gossip来共享DNS映射信息,所以在该网络的容器能通过服务名称来访问彼此。
你不需要公开特定于服务的端口,以使服务可用于同一覆盖网络上的其他服务。 swarm的内部负载均衡会自动将请求分发到服务VIP。
你可以使用如下命令来查看服务的VIP:
- $ docker service inspect
- –format='{{json .Endpoint.VirtualIPs}}’
- my-web
- [{"NetworkID":"7m2rjx0a97n88wzr4nu8772r3" "Addr":"10.0.0.2/24"}]
下面的示例展示如何添加一个busybox服务到与nginx服务相同的网络,以及busybox服务使用DNS名称my-web访问nginx服务:
1.在管理节点,部署busybox服务到与my-web同一个网络:
- $ docker service create
- –name my-busybox
- –network my-network
- busybox
- sleep 3000
2.查看哪个节点运行着my-busybox服务:
- $ docker service ps my-busybox
- ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
- 1dok2cmx2mln5hbqve8ilnair my-busybox.1 busybox node1 Running Running 5 seconds ago
3.登录上一步查询到的node1节点,在busybox容器中打开一个可交互的shell:
- $ docker exec -it my-busybox.1.1dok2cmx2mln5hbqve8ilnair /bin/sh
你可以将容器名称推断为 + 。 或者,你可以在运行任务的节点上运行docker ps。
4.在busybox容器内部,查询my-web服务的VIP:
- $ nslookup my-web
- Server: 127.0.0.11
- Address 1: 127.0.0.11
- Name: my-web
- Address 1: 10.0.9.2 ip-10-0-9-2.us-west-2.compute.internal
5.在busybox容器内部,查询的DNS记录来找出my-web服务的所有容器IP地址:
- $ nslookup tasks.my-web
- Server: 127.0.0.11
- Address 1: 127.0.0.11
- Name: tasks.my-web
- Address 1: 10.0.9.4 my-web.2.6b3q2qbjveo4zauc6xig7au10.my-network
- Address 2: 10.0.9.3 my-web.1.63s86gf6a0ms34mvboniev7bs.my-network
- Address 3: 10.0.9.5 my-web.3.66u2hcrz0miqpc8h0y0f3v7aw.my-network
6.在busybox容器内,执行wget来访问my-web服务的nginx web server:
- $ wget -O- my-web
- Connecting to my-web (10.0.9.2:80)
- <!DOCTYPE html>
- <html>
- <head>
- <title>Welcome to nginx!</title>
- …snip…
通过访问服务的VIP,swarm负载均衡自动将HTTP请求路由可用的容器中。 它使用轮循的方式来平均地分发请求。
使用DNS轮循请求
你可以配置服务直接使用DNS轮循而不用VIP,在创建服务的时候设置–endpoint-mode dnsrr。在你要使用你自己的负载均衡器时可能会用此方法。
下面的示例展示一个服务使用dnsrr endpoint模式:
- $ docker service create
- –replicas 3
- –name my-dnsrr-service
- –network my-network
- –endpoint-mode dnsrr
- nginx
当你查询服务名称的DNS记录时,DNS服务会返回所有该服务容器的IP地址:
- $ nslookup my-dnsrr-service
- Server: 127.0.0.11
- Address 1: 127.0.0.11
- Name: my-dnsrr
- Address 1: 10.0.9.8 my-dnsrr-service.1.bd3a67p61by5dfdkyk7kog7pr.my-network
- Address 2: 10.0.9.10 my-dnsrr-service.3.0sb1jxr99bywbvzac8xyw73b1.my-network
- Address 3: 10.0.9.9 my-dnsrr-service.2.am6fx47p3bropyy2dy4f8hofb.my-network