1、overlay环境准备
为支持容器跨主机通信,Docker 提供了 overlay driver,使用户可以创建基于 VxLAN 的 overlay 网络。VxLAN 可将二层数据封装到 UDP 进行传输,VxLAN 提供与 VLAN 相同的以太网二层服务,但是拥有更强的扩展性和灵活性。
Docerk overlay 网络需要一个 key-value 数据库用于保存网络状态信息,包括 Network、Endpoint、IP 等。Consul、Etcd 和 ZooKeeper 都是 Docker 支持的 key-vlaue 软件,我们这里使用 Consul。
在docker-machine (192.168.1.118)的基础上
1、docker-machine 配置
在docker-machine (192.168.1.118)上部署安装模块Consul。
docker run -d -p 8500:8500 -h consul --name consul progrium/consul -server –bootstrap
容器启动后,可以通过 http://192.168.1.118:8500 访问 Consul.
2、host上配置
接下来修改 host1 和 host2 的 docker daemon 的配置文件/etc/systemd/system/docker.service.d/10-machine.conf。
vim /etc/systemd/system/docker.service.d/10-machine.conf
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2376 -H unix:///var/run/docker.sock --storage-driver aufs --tlsverify --tlscacert /etc/docker/ca.pem --tlscert /etc/docker/server.pem --tlskey /etc/docker/server-key.pem --label provider=generic --cluster-store=consul://192.168.1.118:8500 --cluster-advertise=ens33:2376
Environment=
--cluster-store
指定 consul 的地址。--cluster-advertise
告知 consul 自己的连接地址。
重启 docker daemon。
systemctl daemon-reload
systemctl restart docker.service
实验环境准备就绪。
2、创建 overlay 网络
在 host1 中创建 overlay 网络 ov_net1:
docker network create -d overlay ov_net1
-d overlay
指定 driver 为 overaly
docker network ls
查看当前网络
[root@host1 ~]# docker network create -d overlay ov_net1
03a4eae9e0284a55a5d5fbb88a0c4ece4016830a68cb76a5066d025a29e53af4
[root@host1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
8d6459d553ee bridge bridge local
1712c076ef7d host host local
68afbbc474fe none null local
03a4eae9e028 ov_net1 overlay global
注意到 ov_net1
的 SCOPE 为 global,而其他网络为 local。在 host2 上查看存在的网络:
[root@host2 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
f227bb89d52f bridge bridge local
3ddcec7189dd host host local
89dd1502fd36 none null local
03a4eae9e028 ov_net1 overlay global
host2 上也能看到 ov_net1。这是因为创建 ov_net1 时 host1 将 overlay 网络信息存入了 consul,host2 从 consul 读取到了新网络的数据。之后 ov_net 的任何变化都会同步到 host1 和 host2。
docker network inspect
查看 ov_net1 的详细信息
[root@host1 ~]# docker network inspect ov_net1
[
{
"Name": "ov_net1",
"Id": "03a4eae9e0284a55a5d5fbb88a0c4ece4016830a68cb76a5066d025a29e53af4",
"Created": "2020-03-06T00:37:42.447305499+08:00",
"Scope": "global",
"Driver": "overlay",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "10.0.0.0/24",
"Gateway": "10.0.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
IPAM 是指 IP Address Management,docker 自动为 ov_net1 分配的 IP 空间为 10.0.0.0/24。
3、在 overlay 中运行容器
运行一个 busybox 容器并连接到 ov_net1:
docker run -itd --name bbox1 --network ov_net1 busybox
[root@host1 ~]# docker run -itd --name bbox1 --network ov_net1 busybox
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
bdbbaa22dec6: Pull complete
Digest: sha256:6915be4043561d64e0ab0f8f098dc2ac48e077fe23f488ac24b665166898115a
Status: Downloaded newer image for busybox:latest
98a31b82f1b5e0b94e94ec96b05387eeba93cec7cb78ee5750b5ac7fb80a0778
[root@host1 ~]# docker exec bbox1 ip r
default via 172.18.0.1 dev eth1
10.0.0.0/24 dev eth0 scope link src 10.0.0.2
172.18.0.0/16 dev eth1 scope link src 172.18.0.2
查看容器的网络配置:
bbox1 有两个网络接口 eth0 和 eth1。
eth0 IP 为 10.0.0.2,连接的是 overlay 网络 ov_net1。
eth1 IP 172.18.0.2,容器的默认路由是走 eth1。
其实,docker启动容器时候 ,docker 会创建一个 bridge 网络 “docker_gwbridge”,为所有连接到 overlay 网络的容器提供访问外网的能力。
从 docker network inspect docker_gwbridge 输出可确认 docker_gwbridge 的 IP 地址范围是 172.18.0.0/16,当前连接的容器就是 bbox1(172.18.0.2)。
而且此网络的网关就是网桥 docker_gwbridge 的 IP 172.18.0.1。
容器 bbox1 就可以通过 docker_gwbridge 访问外网。
如果外网要访问容器,可通过主机端口映射,比如:
docker run -p 80:80 -d --net ov_net1 --name web1 httpd
4、overlay 如何实现跨主机通信?
在 host2 中运行容器 bbox2:
docker run -itd --name bbox2 --network ov_net1 busybox
[root@host2 ~]# docker run -itd --name bbox2 --network ov_net1 busybox
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
bdbbaa22dec6: Pull complete
Digest: sha256:6915be4043561d64e0ab0f8f098dc2ac48e077fe23f488ac24b665166898115a
Status: Downloaded newer image for busybox:latest
848edd67562d80cd46b2b34d62b8e89c8c3834bfb60c17ce44f26d091cedfd15
[root@host2 ~]# docker exec bbox2 ip r
default via 172.18.0.1 dev eth1
10.0.0.0/24 dev eth0 scope link src 10.0.0.4
172.18.0.0/16 dev eth1 scope link src 172.18.0.2
[root@host2 ~]#
bbox2 IP 为 10.0.0.4,可以直接 ping bbox1:
可见 overlay 网络中的容器可以直接通信,同时 docker 也实现了 DNS 服务。
overlay 网络的具体实现:
docker 会为每个 overlay 网络创建一个独立的 network namespace,其中会有一个 linux bridge br0,endpoint 还是由 veth pair 实现,一端连接到容器中(即 eth0),另一端连接到 namespace 的 br0 上。
br0 除了连接所有的 endpoint,还会连接一个 vxlan 设备,用于与其他 host 建立 vxlan tunnel。容器之间的数据就是通过这个 tunnel 通信的。逻辑网络拓扑结构如图所示:
要查看 overlay 网络的 namespace 可以在 host1 和 host2 上执行 ip netns(请确保在此之前执行过 ln -s /var/run/docker/netns /var/run/netns),可以看到两个 host 上有一个相同的 namespace “”1-03a4eae9e0“”
这就是 ov_net1 的 namespace,查看 namespace 中的 br0 上的设备。
查看 vxlan1 设备的具体配置信息可知此 overlay 使用的 VNI(VxLAN ID)为 256
5、overlay 是如何隔离的
不同的 overlay 网络是相互隔离的。
创建第二个 overlay 网络 ov_net2 并运行容器 bbox3。
docker network create -d overlay ov_net2
docker run -itd --name bbox3 --network ov_net2 busybox
bbox3 分配到的 IP 是 10.0.1.2,尝试 ping bbox1(10.0.0.2)。
ping 失败,可见不同 overlay 网络之间是隔离的。
即便是通过 docker_gwbridge 也不能通信。
如果要实现 bbox3 与 bbox1 通信,可以将 bbox3 也连接到 ov_net1。
docker network connect ov_net1 bbox3
6、overlay IPAM
docker 默认为 overlay 网络分配 24 位掩码的子网(10.0.X.0/24),所有主机共享这个 subnet,容器启动时会顺序从此空间分配 IP。
可以通过 --subnet 指定 IP 空间。
docker network create -d overlay --subnet 10.22.1.0/24 ov_net3