容器网络
在前面的博客中已经详细讲解了几种网络方案: none, host, bridge,user-defined。但是他们只是解决了单个主机间的容器的通信问题,并不能实现多个主机容器之间的通信。本篇博客将详细介绍如何实现该功能。
跨主机网络方案包括两大类:
- docker原生的:overlay和macvlan
- 第三方方案:flannel、weave和calico
本篇博客将详细讲解overlay以及weave两种方案。
overlay
Docerk overlay 网络需要一个 key-value 数据库用于保存网络状态信息,包括 Network、Endpoint、IP 等。Consul、Etcd 和 ZooKeeper 都是 Docker 支持的 key-vlaue 软件,我们这里使用 Consul。
在 docker 主机 host1(172.20.10.2)和 host2(172.20.10.7)上实践各种跨主机网络方案,在 172.20.10.2 上部署支持的组件,比如 Consul。
第一步:启动路由转发功能
两台主机上面都需要开启
[root@ken3 ~]# echo "1" > /proc/sys/net/ipv4/ip_forward
第二步:运行consul
最简单的方式是以容器方式运行 Consul:
[root@ken1 ~]# docker run -d -p 8500:8500 -h consul --name consul progrium/consul -server -bootstrap
第三步:浏览器访问
容器启动后,可以通过 http://172.20.10.2:8500 访问 Consul。
第四步:修改docker启动文件
接下来修改 host1 和 host2 的 docker daemon 的配置文件/usr/lib/systemd/system/docker.service
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H unix:// --cluster-store=consul://172.20.10.2:8500 --cluster-advertise=eth0:2376
...
--cluster-store
指定 consul 的地址。--cluster-advertise
告知 consul 自己的连接地址(eth0即为网卡名,固定格式)
重启 docker daemon。
[root@ken1 ~]# systemctl daemon-reload
[root@ken1 ~]# systemctl restart docker
重启consul
[root@ken1 ~]# docker rm $(docker ps -aq)
[root@ken1 ~]# docker run -d -p 8500:8500 -h consul --name consul progrium/consul -server -bootstrap
第五步:浏览器查看
可以发现两个主机已经自动注册上去了
创建overlay网络
在host1中创建网络ov_ken
[root@ken1 ~]# docker network create -d overlay ov_ken
25979f1d44c12362f3866295995756984468060c10479288835d64588f27fa3b
[root@ken1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
e36545bfeb92 bridge bridge local
43b0997b8ce5 host host local
36d9a3277b19 none null local
25979f1d44c1 ov_ken overlay global
注意到 ov_ken
的 SCOPE 为 global,而其他网络为 local。在 host2 上查看存在的网络:
host2 上也能看到 ov_ken。这是因为创建 ov_ken 时 host1 将 overlay 网络信息存入了 consul,host2 从 consul 读取到了新网络的数据。之后 ov_ken 的任何变化都会同步到 host1 和 host2。
docker network inspect
查看 ov_ken 的详细信息:
docker 自动为 ov_ken分配的 IP 空间为 10.0.0.0/24。
在overlay中运行容器
行一个 busybox 容器并连接到 ov_ken:
[root@ken1 ~]# docker run -itd --name b1 --network ov_ken busybox
fc6454145e12c1c1a494914e3c71d4a9c7c7da0d6ed888e4b6d2afe80379e000
访问外网测试
可以发现容器访问外网是没有问题的
外网想要访问主机可以通过端口映射
[root@ken1 ~]# docker exec b1 ping -c 2 www.baidu.com
PING www.baidu.com (61.135.169.125): 56 data bytes
64 bytes from 61.135.169.125: seq=0 ttl=54 time=25.144 ms
64 bytes from 61.135.169.125: seq=1 ttl=54 time=24.358 ms
--- www.baidu.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 24.358/24.751/25.144 ms
跨主机连通
在 host2 中运行容器 b2
[root@ken3 ~]# docker run -itd --name b2 --network ov_ken busybox
查看b2的网络
b2的ip为10.0.0.3
[root@ken3 ~]# docker exec b2 ip r
default via 172.18.0.1 dev eth1
10.0.0.0/24 dev eth0 scope link src 10.0.0.3
172.18.0.0/16 dev eth1 scope link src 172.18.0.2
测试b1能否ping通b2
[root@ken1 ~]# docker exec b1 ping -c 2 10.0.0.3
PING 10.0.0.3 (10.0.0.3): 56 data bytes
64 bytes from 10.0.0.3: seq=0 ttl=64 time=10.344 ms
64 bytes from 10.0.0.3: seq=1 ttl=64 time=1.694 ms
--- 10.0.0.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 1.694/6.019/10.344 ms
[root@ken1 ~]# docker exec b1 ping -c 2 b2
PING b2 (10.0.0.3): 56 data bytes
64 bytes from 10.0.0.3: seq=0 ttl=64 time=2.916 ms
64 bytes from 10.0.0.3: seq=1 ttl=64 time=1.950 ms
--- b2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 1.950/2.433/2.916 ms
可见 overlay 网络中的容器可以直接通信,同时 docker 也实现了 DNS 服务。
overlay网络隔离
不同的 overlay 网络是相互隔离的。我们创建第二个 overlay 网络 ov_ken2 并运行容器 b
[root@ken1 ~]# docker network create -d overlay ov_ken2
2008b1f950566f105a567ea422ef2269b1db226de58b2d8d8350a91106542d27
[root@ken1 ~]# docker run -itd --name b3 --network ov_ken2 busybox
9f6b4166169ebe5993f8533c57dbf0089fe539a09607d94d3d9442990c8393ea
查看b3分配到的IP
可以发现是10.0.1.2
[root@ken1 ~]# docker exec b3 ip r
default via 172.18.0.1 dev eth1
10.0.1.0/24 dev eth0 scope link src 10.0.1.2
172.18.0.0/16 dev eth1 scope link src 172.18.0.3
现在尝试ping b2
[root@ken1 ~]# docker exec b3 ping -c 2 10.0.0.3
PING 10.0.0.3 (10.0.0.3): 56 data bytes
--- 10.0.0.3 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss
ping 失败,可见不同 overlay 网络之间是隔离的。
如果要实现 b3 与 b2 通信,可以将 b3 也连接到 ov_ken。
[root@ken1 ~]# docker network connect ov_ken b3
[root@ken1 ~]# docker exec b3 ip r
default via 172.18.0.1 dev eth1
10.0.0.0/24 dev eth2 scope link src 10.0.0.4
10.0.1.0/24 dev eth0 scope link src 10.0.1.2
172.18.0.0/16 dev eth1 scope link src 172.18.0.3
可以发现现在的b3有了一个eth2的网卡,ip地址为10.0.0.4
现在再来测试一下b3能否ping通b2
[root@ken1 ~]# docker exec b3 ping -c 2 10.0.0.3
PING 10.0.0.3 (10.0.0.3): 56 data bytes
64 bytes from 10.0.0.3: seq=0 ttl=64 time=7.145 ms
64 bytes from 10.0.0.3: seq=1 ttl=64 time=2.769 ms
--- 10.0.0.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 2.769/4.957/7.145 ms
可以发现现在可以ping通了
weave网络
weave 不依赖分布式数据库(例如 etcd 和 consul)交换网络信息,每个主机上只需运行 weave 组件就能建立起跨主机容器网络。接下来在 host1 和 host2 上部署 weave 并实践 weave 的各项特性。
安装部署weave
weave 安装非常简单,在 host1 和 host2 上执行如下命令:
[root@ken1 ~]# curl -L git.io/weave -o /usr/local/bin/weave
[root@ken1 ~]# chmod a+x /usr/local/bin/weave
host1中启动weave
在 host1 中执行 weave launch
命令,启动 weave 相关服务。weave 的所有组件都是以容器方式运行的,weave 会从 docker hub 下载最新的 image 并启动容器。
[root@ken1 ~]# weave launch
查看启动的容器
[root@ken1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7a59dcccd908 weaveworks/weave:2.5.1 "/home/weave/weaver …" 37 seconds ago Restarting (1) 36 seconds ago weave
weave 运行了一个容器:
weave
是主程序,负责建立 weave 网络,收发数据 ,提供 DNS 服务等。
host1中启动容器
[root@ken ~]# eval $(weave env)
[root@ken ~]# docker run --name b1 --rm -itd busybox
e04f798321072542450ca800601e980d206e00e8850b1b1ce16f4cba8ce94a32
首先执行 eval $(weave env)
很重要,其作用是将后续的 docker 命令发给 weave proxy 处理。如果要恢复之前的环境,可执行 eval $(weave env --restore)
。
查看一下当前容器 bbox1 的网络配置:
b1 有两个网络接口 eth0 和 ethwe,其中 eth0 连接的是默认 bridge 网络,即网桥 docker0。
分配的 IP 10.32.0.1/12 ethwe 与 weave 相关
再运行一个容器 b2。
[root@ken ~]# docker run --name b2 --rm -itd busybox
abf55e9dead051e0e87afd524243fbb7c3a6985042d0d924a829a91399c76ade
测试b1与b2的连通性(相同主机host!)
可以发现b1与b2不仅可以互相ping通,还可以解析
[root@ken ~]# docker exec b1 ping -c 2 b2
PING b2 (10.32.0.2): 56 data bytes
64 bytes from 10.32.0.2: seq=0 ttl=64 time=0.141 ms
64 bytes from 10.32.0.2: seq=1 ttl=64 time=0.282 ms
--- b2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.141/0.211/0.282 ms
weave跨主机通信
第一步:首先在host2 执行如下命令
[root@ken3 ~]# weave launch 172.20.10.2
e69a5bec56eb8d5471b139ce2c3080f2681e44c7bf582ef798c017d83107e3ac
这里必须指定 host1 的 IP 172.20.10.2,这样 host1 和 host2 才能加入到同一个 weave 网络。
第二步:开启路由转发功能
echo "1">/proc/sys/net/ipv4/ip_forward
第三步:启动容器
[root@ken3 ~]# eval $(weave env)
[root@ken3 ~]# docker run --name b3 --rm -itd busybox
4c86439dd59d545eb73e796709872cd51e4953503e63c2a0ff4549b2eb3ce8fa
第四步:测试容器连接性
可以发现主机host2上运行的b3容器可以与host1主机上面运行的b1和b2容器进行通信,而且可以解压主机名。
[root@ken3 ~]# docker exec b3 ping -c 2 b1
PING b1 (10.32.0.1): 56 data bytes
64 bytes from 10.32.0.1: seq=0 ttl=64 time=7.157 ms
64 bytes from 10.32.0.1: seq=1 ttl=64 time=1.021 ms
--- b1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 1.021/4.089/7.157 ms
[root@ken3 ~]# docker exec b3 ping -c 2 b2
PING b2 (10.32.0.2): 56 data bytes
64 bytes from 10.32.0.2: seq=0 ttl=64 time=8.116 ms
64 bytes from 10.32.0.2: seq=1 ttl=64 time=1.960 ms
--- b2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 1.960/5.038/8.116 ms
weave网络隔离
默认配置下,weave 使用一个大 subnet(例如 10.32.0.0/12),所有主机的容器都从这个地址空间中分配 IP,因为同属一个 subnet,容器可以直接通信。如果要实现网络隔离,可以通过环境变量 WEAVE_CIDR
为容器分配不同 subnet 的 IP,举例如下:
[root@ken3 ~]# docker run -e WEAVE_CIDR=net:10.32.2.0/24 --rm -itd busybox
98bc93412af210e08b4be7a9456e40749ca4a0672f3ebbc5a5f616ab0b4d3b50
这里 WEAVE_CIDR=net:10.32.2.0/24
的作用是使容器分配到 IP 10.32.2.2
。由于 10.32.0.0/12 与 10.32.2.0/24 位于不同的 subnet,所以无法 ping 到 b2。
[root@ken3 ~]# docker exec 98bc93412af ping -c 2 b2
PING b2 (10.32.0.2): 56 data bytes
--- b2 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss
除了 subnet,我们还可以直接为容器分配特定的 IP:
[root@ken3 ~]# docker run -e WEAVE_CIDR=ip:10.32.6.6/24 -it busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
36: eth0@if37: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
38: ethwe@if39: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1376 qdisc noqueue
link/ether ae:e0:cd:41:ac:f5 brd ff:ff:ff:ff:ff:ff
inet 10.32.6.6/24 brd 10.32.6.255 scope global ethwe
valid_lft forever preferred_lft forever
/ # ping -c 2 b2
PING b2 (10.32.0.2): 56 data bytes
--- b2 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss
weave与外网的连通性
weave 是一个私有的 VxLAN 网络(容器可以访问外网),默认与外部网络隔离。外部网络如何才能访问到 weave 中的容器呢?
答案是:
- 首先将主机加入到 weave 网络。
- 然后把主机当作访问 weave 网络的网关。
第一步:要将主机加入到 weave,执行 weave expose
。
[root@ken3 ~]# weave expose
10.32.2.129
第二步:查看IP
这个 IP 10.32.2.129
会被配置到 host2 的 weave 网桥上。
第三步:测试连通性
ping同一主机的b3
[root@ken3 ~]# ping -c 2 10.44.0.0
PING 10.44.0.0 (10.44.0.0) 56(84) bytes of data.
64 bytes from 10.44.0.0: icmp_seq=1 ttl=64 time=0.327 ms
64 bytes from 10.44.0.0: icmp_seq=2 ttl=64 time=0.068 ms
--- 10.44.0.0 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.068/0.197/0.327/0.130 ms
ping host1中的b1
[root@ken3 ~]# ping -c 2 10.32.0.1
PING 10.32.0.1 (10.32.0.1) 56(84) bytes of data.
64 bytes from 10.32.0.1: icmp_seq=1 ttl=64 time=28.4 ms
64 bytes from 10.32.0.1: icmp_seq=2 ttl=64 time=0.975 ms
--- 10.32.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.975/14.708/28.442/13.734 ms
接下来要让其他非 weave 主机访问到 bbox1 和 bbox3,只需将网关指向 host1。例如在 172.20.10.9上添加如下路由:
[root@host2 ~]# ip route add 10.32.0.0/12 via 172.20.10.2
[root@host2 ~]# ping -c 2 10.32.0.1
PING 10.32.0.1 (10.32.0.1) 56(84) bytes of data.
64 bytes from 10.32.0.1: icmp_seq=1 ttl=63 time=1.45 ms
64 bytes from 10.32.0.1: icmp_seq=2 ttl=63 time=2.25 ms
--- 10.32.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 1.450/1.852/2.254/0.402 ms
10.32.0.0/12 是 weave 网络使用的默认 subnet,如果此地址空间与现有 IP 冲突,可以通过 --ipalloc-range
分配特定的 subnet。
weave launch --ipalloc-range 10.2.0.0/16
不过请确保所有 host 都使用相同的 subnet。