docker学习|docker overlay网络详解

之前我们学习的网络是单台主机的网络通讯方案,这里我们学习的是跨主机方案。
我们原生的docker跨主机方案有macvlan和overlay,这里我们重点学习overlay
第三方网络插件有flannel,calico,weave网络。
docker网络之所以这么活跃,是因为网络部分的代码单独抽离出来成为docker的网络库,即libnetwork。
为了标准化网路驱动的开发步骤和支持各种网络驱动,libnetwork中使用了CNM(container network model),CNM定义了构建容器虚拟化网络的模型,同时还提供了可以用于开发多种网络驱动的标准化接口和组件。
现在我们有两台主机,里面的容器之间要进行通讯的话,要保持一个公式相等,即一个网段=一个广播域=一个VLAN。
下面介绍一下两个container的通讯构建过程,
首先会在我们的主机当中构建一个网络,这个网络叫做sanbox,这个是网络容器内的协议栈。
docker学习|docker overlay网络详解
文章图片

在每个容器里面都会这样的一个设备叫做endpoint,它的作用就是把容器(sandbox)接入到network中去,endpoint最典型的案例就是veth pair
docker学习|docker overlay网络详解
文章图片

network包含的是一组endpoint,同一个network下的endpoint可以通信,network实现的方法就是桥接加VLAN的方式。
docker学习|docker overlay网络详解
文章图片

docker学习|docker overlay网络详解
文章图片

什么叫做overlay网络?
字面意思就是叠加的网络,指的就是在物理网络层上再搭建一层网络,通过某种技术再构建一张相同的网络,这张称为逻辑网。也就是说我们想要两台主机的容器进行通讯,首先这两台主机自己要可以通讯,然后在这个物理机的基础之上部署一张逻辑层的网络,他具有物理网络的所有特性,跟物理网络一模一样。
VLAN是什么,我们想要划分网络就叫做VLAN,VLAN只是单纯的对物理网络进行划分,隔离ip,Mac。VLAN是划分广播域的最基础概念。
vxlan是在物理网络基础之上构建出来的网络,这个网络可以通过 vxlan进行划分,ip,Mac只需要在一个vxlan中就可以进行通讯。
我们overlay网络的需求就是需要一个非关系型的数据库,这里以consul为例

[root@master1~]# docker pull progrium/consul
这里将要存放的是network,endpont,sandbox,ip等信息。
两台主机名必须不一样,然后启动我们的consul镜像
[root@master1 ~]# docker run -d --restart always -p 8400:8400 -p 8500:8500 -p 8600:53/udp -h consul progrium/consul -server -bootstrap -ui-dir /ui c1f0022ecfdb494a3ecc86384ef132479fe251a0c53e35146e120bba3d955987 [root@master1 ~]#
这个时候我们可以通过浏览器访问到我们的consul
docker学习|docker overlay网络详解
文章图片

启动完成之后,这个时候我们需要把测试的两个主机加入到我们的consul中来
在docker.service这个文件中加即可
加入第一台主机:
增加参数如下:
docker学习|docker overlay网络详解
文章图片

ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --cluster-store=consul://192.168.64.150:8500 --cluster-advertise=ens33:2376
分析:
  1. --cluster-store 表示存储在哪里
  2. --cluster-advertise 本机网卡地址,2376为默认端口
第二台机器加入同样的参数即可。
然后先重启consul所在主机的docker,然后重启第二台主机。
然后看一下consul的web端
docker学习|docker overlay网络详解
文章图片

这个时候,我们的试验环境就已经准备好了
此时查看宿主机的network
[root@master1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2238d0cf60dc bridge bridge local
3b93f4bad0a9 host host local
6b6f0e006e46 none null local
这个时候我们需要创建一个网络,创建之前先看一下物理网卡支不支持vxlan,这里不支持,按照如下方式修改即可:
docker学习|docker overlay网络详解
文章图片

[root@master1 ~]# ifconfig ens33 promisc
promisc:混杂模式
Linux下网卡的混杂模式浅谈 - 云+社区 - 腾讯云
docker学习|docker overlay网络详解
文章图片

在第二台主机相同的操作。。。
补充:删除的命令 ifconfig ens33 -promisc
这个时候我们就可以创建overlay的网络驱动器了
[root@master1 ~]# docker network create --driver overlay --attachable ov_net1 5473d38fd5fd0b4a1d432c60af2d8a9fef942b72b8333b41cbf210c86a451d69
[root@master1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2238d0cf60dc bridge bridge local
3b93f4bad0a9 host host local
6b6f0e006e46 none null local
【docker学习|docker overlay网络详解】5473d38fd5fd ov_net1 overlay global //这个global表示全局生效
attachable的作用是:默认情况下。overlay生效的返回是在dockerswarm集群中,如果想要单独拿出来用的话,没有在这个集群中创建的话,就需要加这个单词。
这个时候我们去我们另外一台主机上看,发现也会自动同步一个overlay网络
[root@master2 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
d0b01765b18e bridge bridge local
822ef830c4f7 host host local
ff5394e0cfc8 none null local
5473d38fd5fd ov_net1 overlay global
[root@master2 ~]#
我们观察一下这个网络的特点
docker学习|docker overlay网络详解
文章图片

根据我们之前的经验,网关地址可能是桥接卡的地址,我们ip a看一下宿主机网络,发现没有
docker学习|docker overlay网络详解
文章图片

这个时候猜想可能在另外的一个namespace网络空间,因为我们的overlay网络是在一层物理机网络之上,在铺设一层网络。
我先使用一下这个overlay网络
docker学习|docker overlay网络详解
文章图片

发现overlay网络有两个网卡,12的那个是overlay的网段的网卡,15的那个172.18的网段,现在看看这两块网卡分别连到宿主机的哪块网卡。。
docker学习|docker overlay网络详解
文章图片

(容器里面12号网卡连接容器外边的13号,没有在宿主机找到,这个其实在ip netns网络空间里面,这个我们后边会讲到,暂时先不解释这个连接,即先不管10.0这个网段,下面的先讲15连16的情况)
我们发现在主机当中多了14号的那块网卡,docker_gwbridge,刚好也是172.18的网段。
根据名字可以猜到这个是块网关桥接卡
[root@master1 ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02428ec5c553 no vetha5eebba
docker_gwbridge 8000.02423841ce9a no veth78af435
[root@master1 ~]#
新增了一个名为docker_gwbridge的桥接卡
docker network ls查看一下docker的网络,也多了一块网卡
[root@master1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2238d0cf60dc bridge bridge local
09575e4ff9dc docker_gwbridge bridge local
3b93f4bad0a9 host host local
6b6f0e006e46 none null local
5473d38fd5fd ov_net1 overlay global
[root@master1 ~]#
docker学习|docker overlay网络详解
文章图片

我们大概画一下这个关系
docker学习|docker overlay网络详解
文章图片

那么这个网络能不能对外通讯呢?
其实整个对外通讯走的都是docker_gwbridge这个桥接卡,因为物理机上没有10网段的路由转发
[root@master1 ~]# ip r
default via 192.168.64.2 dev ens33 proto static metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src
172.17.0.1 172.18.0.0/16 dev docker_gwbridge proto kernel scope link src
172.18.0.1 192.168.64.0/24 dev ens33 proto kernel scope link src 192.168.64.150 metric 100
即容器想要通过物理机对外进行通讯的话,一定要依赖这个docker_gwbridge的网卡。
测试一下
docker学习|docker overlay网络详解
文章图片

使用network ls命令查看,也没有增加额外的网卡信息。。。
查看网桥信息,可以发现多了veth19bab1f连接到docker_gwbridge这个桥接卡上了。
docker学习|docker overlay网络详解
文章图片

所以这个docker_gwbridge其实是用来跟外网进行通讯的。。。
这里还没有到我们的overlay网络的讲解,因为上面的讲解是容器如何实现对外网通讯的,这来我们刚开始可能有个疑问,明明最开始创建容器(bbox1或者web1)的时候我们--network选择式是overlay网络。。。我们想想啊,选择的是overlay,能实现跨主机通讯,但是总要跟外网通讯的呀,而且刚开始的是,创建bbox1的时候,我们进入容器里面Ip a看到的是有两块网卡信息,上面解释了能够在物理机使用ip a命令看到的那一块。。。
下面我们才真正开始解释,为啥物理机看不到另外的一块信息。
我们在另外一台主机上创建一个bbox2,让它来连接开始的那台主机的bbox1
[root@master2 ~]# docker run -itd --name bbox2 --network ov_net1 busybox 6087d1baca4499f68dfabc65486177b6d2814b4ff33e9f561dcae16a0ed87f4a [root@master2 ~]# docker exec -it bbox2 sh
/ # ip a
1: lo: 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
6: eth0@if7: mtu 1450 qdisc noqueue link/ether 02:42:0a:00:00:04 brd ff:ff:ff:ff:ff:ff inet 10.0.0.4/24 brd 10.0.0.255 scope global eth0 valid_lft forever preferred_lft forever
9: eth1@if10: mtu 1500 qdisc noqueue link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff inet 172.18.0.2/16 brd 172.18.255.255 scope global eth1 valid_lft forever preferred_lft forever
/ # ping bbox1
PING bbox1 (10.0.0.2): 56 data bytes
64 bytes from 10.0.0.2: seq=0 ttl=64 time=8.489 ms
64 bytes from 10.0.0.2: seq=1 ttl=64 time=0.765 ms
^C
--- bbox1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.765/4.627/8.489 ms
/ # ping 10.0.0.1
PING 10.0.0.1 (10.0.0.1): 56 data bytes
64 bytes from 10.0.0.1: seq=0 ttl=64 time=0.085 ms
64 bytes from 10.0.0.1: seq=1 ttl=64 time=0.054 ms
^C
--- 10.0.0.1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.054/0.069/0.085 ms
/ #
/ # ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2): 56 data bytes
64 bytes from 10.0.0.2: seq=0 ttl=64 time=0.280 ms
64 bytes from 10.0.0.2: seq=1 ttl=64 time=0.256 ms
^C
--- 10.0.0.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.256/0.268/0.280 ms
/ #
/ # ping 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=0.504 ms
64 bytes from 10.0.0.3: seq=1 ttl=64 time=0.671 ms
^C
--- 10.0.0.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.504/0.587/0.671 ms
/ #
如上试验,我们也支持DNS通讯,overlay实现了跨主机通讯的同时,docker也实现了DNS的解析,docker会为我们创建一个独立的网络空间,因为10网段不在物理机上,即我们使用ip a无法看到某个网卡是10网段的。
((docker inspect 403784c26c7e |grep -i sand 查看某个容器属于哪个netns))
使用ip netns 查看宿主机的网络空间,发现没有看到,此时我们需要去docker的文件系统目录下看
[root@master1 ~]# cd /var/run/docker/
[root@master1 docker]# ls
containerd libnetwork metrics.sock netns plugins runtime-runc swarm
[root@master1 docker]# ls netns/
1-5473d38fd5 51fc6a02edce 604c7fb0bdfb 74c2063136cd
[root@master1 docker]#
里面有个netns目录,我们把它连接到我们常规查看的网络空间的目录下,然后再次查看
[root@master1 ~]# ln -s /var/run/docker/netns/ /var/run/netns
[root@master1 ~]# ip netns
604c7fb0bdfb (id: 3)
74c2063136cd (id: 2)
1-5473d38fd5 (id: 1)
51fc6a02edce (id: 0)
[root@master1 ~]#
同理我们在第二台主机上也软连接一下
[root@master2 ~]# ln -s /var/run/docker/netns/ /var/run/netns
[root@master2 ~]#
[root@master2 ~]#
[root@master2 ~]#
[root@master2 ~]# ip netns
5eebc027694b (id: 1)
1-5473d38fd5 (id: 0)
[root@master2 ~]#
我们发现两台主机都有一个1-5473d38fd5的空间名字,查看一下这个网络空间,我们发现了13号网卡了,之前不是讲过我们创建的bbox1容器里面,有12号网卡连接到13号网卡,但是宿主机找不到13号网卡,在这里面可以找到。(18号网卡是连接到我们的web1容器里的17号)
docker学习|docker overlay网络详解
文章图片

[root@master1 ~]# ip netns exec 1-5473d38fd5 brctl show
bridge name bridge id STP enabled interfaces br0 8000.723a3c527d07 no veth0 veth1 vxlan0
[root@master1 ~]#
发现在1-5473d38fd5这个网络空间内br0这块网卡才是10.0网段的,13那块网卡并没有10.0网段地址,其实我们的13号网卡,也就是veth0桥接到br0上了。
在主机当中有另外的一个空间的存在,这里就是1-5473d38fd5,这个空间里面有如上的桥接关系。
(复习一个知识点,不同空间的网卡数据转发方式是veth pair,同一个空间是桥接)
我们发现br0上有vxlan0的接口,vxlan0的作用是跟对端主机进行通讯的,也就是我们这里的第二台主机。对端主机的网络也是这样的形式,如下:
docker学习|docker overlay网络详解
文章图片

两台主机的容器进行通讯依靠的是vxlan在相同的网络里面,此时查看一下vxlan0的ID号
docker学习|docker overlay网络详解
文章图片

docker学习|docker overlay网络详解
文章图片

VXLAN ID相同,大家在同一个广播域里面,地址又是同一个网段的,既可以通讯。
docker学习|docker overlay网络详解
文章图片

通讯的话,就是上面的介绍。
下面介绍一下如何实现隔离的
先创建一个overlay网络
[root@master1 ~]# docker network create --driver overlay --attachable ov_net2 aafcf8d932c847d3f520a1b350cb36c63ceacd18cbf96ca01d75e09881179d59
[root@master1 ~]#
[root@master1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2238d0cf60dc bridge bridge local
09575e4ff9dc docker_gwbridge bridge local
3b93f4bad0a9 host host local
6b6f0e006e46 none null local
5473d38fd5fd ov_net1 overlay global
aafcf8d932c8 ov_net2 overlay global
[root@master1 ~]#
新创建的ov_net2的网段是10.0.1.0
docker学习|docker overlay网络详解
文章图片

此时创建一个容器,是无法跟之前ov_net1的容器进行通讯的
docker学习|docker overlay网络详解
文章图片

若我们想要让ov_net2创建的容器跟ov_net1的容器进行通讯的话,操作如下:
把我们的ov_net2的容器跟ov_net1网络连接起来,此时我们的ov_net2的容器里面多了一块ov_net1的网段的网卡。
docker学习|docker overlay网络详解
文章图片

补充:自己手动创建网络的网关,网段的命令
docker学习|docker overlay网络详解
文章图片

参考资料:《Docker 容器与容器云(第2版)》

说明
--------------------------------------------------------我是分割线----------------------------------------------------------
这里所有的资料都是自己平时学习之中的笔记,拿出来分享一下,这其中难免有些不到之处,所以仅供参考哈
docker学习|docker overlay网络详解
文章图片


    推荐阅读