docker swarm 网络模式
swarm的三个网络
名称 | 类型 | 注释 |
---|---|---|
docker_gwbridge | bridge | none |
ingress | overlay | none |
overlay | none |
- docker_gwbridge和ingress是swarm自动创建的,当用户执行了docker swarm init/connect之后。
- docker_gwbridge是bridge类型的负责本机container和主机直接的连接
- ingress负责service在多个主机container之间的路由。
是用户自己创建的overlay网络,通常我们都需要创建自己的network并把service挂在上面。
swarm service的路由办法通常有两种,VIP和DSN
service路由之:虚拟IP
这是缺省情况设置,当用户创建service的时候,这个service会被分配一个VIP,然后每一个具体的container都有一个独立的IP,ingress会负责从VIP到各个container之间的路由。
举例来说:
- 创建网络
$ docker network create --driver overlay my-network
kw3iy5w8ws7l568fe2o0ntpgw
$ docker network inspect my-network
[
{
"Name": "my-network",
"Id": "kw3iy5w8ws7l568fe2o0ntpgw",
...,
"IPAM": {
...,
"Config": [
{
"Subnet": "10.0.1.0/24",
"Gateway": "10.0.1.1"
}
]
},
并且看到了它的属性。
创建两个service:
$ docker service create --replicas 2 --network my-network --name my-web nginx
$ docker service create --replicas 1 --network my-network --name my-box busybox sleep 3000
nslookup查看域名解析:
$ docker ps | grep my-box
d0c2c0c88e20 busybox:latest "sleep 3000" 32 seconds ago Up 30 seconds my-box.1.rbdxb9ta7uk0606u7qw25wypc
$ docker exec -it d0c2c0c88e20 sh
/ # nslookup my-web # 查看service的虚IP
Server: 127.0.0.11
Address: 127.0.0.11:53
Non-authoritative answer:
Name: my-web
Address: 10.0.1.2 # 10.0.1.2就是service my-web的虚IP
/ # nslookup tasks.my-web # 这个命令查看所有的tasks,即containers
Server: 127.0.0.11
Address: 127.0.0.11:53
Non-authoritative answer:
Name: tasks.my-web
Address: 10.0.1.4
Name: tasks.my-web
Address: 10.0.1.3
/ # nslookup 10.0.1.2
Server: 127.0.0.11
Address: 127.0.0.11:53
** server can't find 2.1.0.10.in-addr.arpa: NXDOMAIN
/ # nslookup 10.0.1.3
Server: 127.0.0.11
Address: 127.0.0.11:53
Non-authoritative answer:
3.1.0.10.in-addr.arpa name = my-web.1.61t2nfcofsh3sqxarydp1tobi.my-network
/ # nslookup 10.0.1.4
Server: 127.0.0.11
Address: 127.0.0.11:53
Non-authoritative answer:
4.1.0.10.in-addr.arpa name = my-web.2.3ngpbetri2v6jb84wysud76ux.my-network
从这个例子我们可以看到:
- service my-web的虚拟IP是10.0.1.2
- 它有两个containers,IP分别是:10.0.1.3 和 10.0.1.4
- 127.0.0.11是swarm内置的DSN服务器,用来解析service名字到IP地址
我们再进入container看看:
$ docker exec -it my-web.1.61t2nfcofsh3sqxarydp1tobi bash
root@1a55df476e01:/tools/tools# ./ifconfig
eth0: flags=4163 mtu 1450
inet 10.0.1.3 netmask 255.255.255.0 broadcast 10.0.1.255
ether 02:42:0a:00:01:03 txqueuelen 0 (Ethernet)
...
eth1: flags=4163 mtu 1500
inet 172.18.0.4 netmask 255.255.0.0 broadcast 172.18.255.255
ether 02:42:ac:12:00:04 txqueuelen 0 (Ethernet)
...
lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
...
每一个container有两块网卡:
eth0: 10.0.1.3 这就是我们前面看到的service container IP地址,是属于网络my-network的。
eth1: 172.18.0.4,这是另一个网络地址;是谁的呢, 是网络docker_gwbridge。(另外bridge网络使用的是172.17网段)
也就是说每一个container属于两个网络,my-network和docker_gwbridge,分别用来service路由,和连接主机网络。
补充一点网卡eth1: 172.18.0.4,对应的网关地址是172.18.0.1,那个这个网关地址172.18.0.1是谁呢,它就是主机网络上的docker_gwbridge,在主机上运行ifconfig可以看到:
$ ifconfig
docker0: flags=4099 mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:4bff:fe9a:8b9a prefixlen 64 scopeid 0x20
ether 02:42:4b:9a:8b:9a txqueuelen 0 (Ethernet)
...
docker_gwbridge: flags=4163 mtu 1500
inet 172.18.0.1 netmask 255.255.0.0 broadcast 172.18.255.255
inet6 fe80::42:cfff:fedc:ca8 prefixlen 64 scopeid 0x20
ether 02:42:cf:dc:0c:a8 txqueuelen 0 (Ethernet)
...
bridge网络的网段地址从172.17.X.X/16开始,第一个内置的docker0使用了172.17.X.X,后面每新增一个bridge网络就新增一个网地址,172.18.X.X, 172.19.X.X,。。。
至此两个bridge网络都比较清楚了。
另外如果发布service的时候指定了主机端口映射,那么container里面会有三块网卡分别属于:
- docker_gwbridge
- ingress, 其网段是10.255.X.X,每一个service在ingress上也有一个VIP,例如VIP=10.255.0.2,对映两个container:10.255.0.3和10.255.0.4
做一个总结:
发布service的时候:
- 如果指定了--publish端口,那么会在ingress网络中创建接口,并产生路由信息。
- 如果指定了--network网络,那么会在指定网络里面创建接口,并产业路由信息。
- 如果都没有指定,实际上相当于没有通信,不和主机通信,互相之间也不通信。
- 如果两者都指定了,那么在两处均创建接口。
- 如果没有指定--network网络,那么无法通过service名字寻址,例如
curl my-web:80
将无法访问;所以通常来说创建swarm service都需要指定一个overlay网络。
注意swarm VIP使用的一个限制:
Swarm routes requests for the VIP in a round robin fashion at L4.
This means that the following Interlock features are incompatible with VIP mode:
* Sticky sessions
也就是说无法做到同一个client过来的请求保持路由到同一个container去。
service路由之:DSN轮询
适合使用自己的DSN Load-Balance算法,例如HAProxy。
创建使用DSN轮询的service。
$ docker service create --replicas 2 --network my-network --name my-dnsrr-web --endpoint-mode dnsrr nginx
由参数--endpoint-mode决定。
先看一下两个container的ip 地址:
# ifconfig # container 1
eth0: flags=4163 mtu 1450
inet 10.0.1.28 netmask 255.255.255.0 broadcast 10.0.1.255
ether 02:42:0a:00:01:1c txqueuelen 0 (Ethernet)
...
eth1: flags=4163 mtu 1500
inet 172.18.0.7 netmask 255.255.0.0 broadcast 172.18.255.255
ether 02:42:ac:12:00:07 txqueuelen 0 (Ethernet)
...
lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 0 (Local Loopback)
...
# ifconfig # container 2
eth0: flags=4163 mtu 1450
inet 10.0.1.29 netmask 255.255.255.0 broadcast 10.0.1.255
ether 02:42:0a:00:01:1d txqueuelen 0 (Ethernet)
...
eth1: flags=4163 mtu 1500
inet 172.18.0.6 netmask 255.255.0.0 broadcast 172.18.255.255
ether 02:42:ac:12:00:06 txqueuelen 0 (Ethernet)
...
lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 0 (Local Loopback)
...
两个contaienr的ip 地址分别是:
- my-dnsrr-web.1.6a1xknrmh8rxnlvwftuzytwxp: eth0 10.0.1.28, eth1 172.18.0.7
- my-dnsrr-web.2.i5sgozdgtj4vs6ahok9wxs1o3: eth0 10.0.1.29, eth1: 172.18.0.6
再看DSN解析结果:
# ping my-dnsrr-web
PING my-dnsrr-web (10.0.1.28) 56(84) bytes of data.
64 bytes from 0cd9f35e6082 (10.0.1.28): icmp_seq=1 ttl=64 time=0.043 ms
64 bytes from 0cd9f35e6082 (10.0.1.28): icmp_seq=2 ttl=64 time=0.040 ms
# ping my-dnsrr-web
PING my-dnsrr-web (10.0.1.29) 56(84) bytes of data.
64 bytes from my-dnsrr-web.2.i5sgozdgtj4vs6ahok9wxs1o3.my-network (10.0.1.29): icmp_seq=1 ttl=64 time=0.096 ms
64 bytes from cf75bccfbacd.my-network (10.0.1.29): icmp_seq=2 ttl=64 time=0.070 ms
# ping my-dnsrr-web
PING my-dnsrr-web (10.0.1.28) 56(84) bytes of data.
64 bytes from 0cd9f35e6082 (10.0.1.28): icmp_seq=1 ttl=64 time=0.024 ms
64 bytes from 0cd9f35e6082 (10.0.1.28): icmp_seq=2 ttl=64 time=0.041 ms
# ping my-dnsrr-web
PING my-dnsrr-web (10.0.1.29) 56(84) bytes of data.
64 bytes from my-dnsrr-web.2.i5sgozdgtj4vs6ahok9wxs1o3.my-network (10.0.1.29): icmp_seq=1 ttl=64 time=0.061 ms
64 bytes from my-dnsrr-web.2.i5sgozdgtj4vs6ahok9wxs1o3.my-network (10.0.1.29): icmp_seq=2 ttl=64 time=0.051 ms
# ping my-dnsrr-web
PING my-dnsrr-web (10.0.1.28) 56(84) bytes of data.
64 bytes from 0cd9f35e6082 (10.0.1.28): icmp_seq=1 ttl=64 time=0.022 ms
64 bytes from 0cd9f35e6082 (10.0.1.28): icmp_seq=2 ttl=64 time=0.022 ms
# ping my-dnsrr-web
PING my-dnsrr-web (10.0.1.29) 56(84) bytes of data.
64 bytes from cf75bccfbacd.my-network (10.0.1.29): icmp_seq=1 ttl=64 time=0.063 ms
每次运行ping解析出的IP地址在两个container之间轮换,也就没有虚IP概念了,而且swarm自动实现了DSN轮询的功能。
再看一个nslookup结果:
# nslookup my-dnsrr-web
Server: 127.0.0.11
Address: 127.0.0.11#53
Non-authoritative answer:
Name: my-dnsrr-web
Address: 10.0.1.28
Name: my-dnsrr-web
Address: 10.0.1.29
可见nslookup直接把两个container的地址都解析出来,说明一个域名(service name)对映有两个IP地址。对照前面使用VIP的,一个service name只对映一个IP地址,就是VIP地址,而不管具体有多少个container实例。