前段时间抽了很多时间进入了网络开发,所以也恶补了不少知识,由于是现成的方案,于实上手就可以开始设计程序编码,少了很多思考的过程。譬如该方案相比其它的方案,有何优势与劣势,缺少了选型的一环。
需要全面的掌握一个方向的知识,各种方案的了解是必不可少的,首先先来简单的来看一下Calico这个网络架构方案。
Calico也主要是创建一个虚拟网络,让宿主机上的多个容器或者虚机之类的,可以进行通讯。首先它与隧道方案最大的不同在于,它不必封装外部隧道头,直接利用linux现有的各种网络虚拟设备与路由表即可实现流量的转发。
这里简单的记录下最核心的一点,网络流量的走向信息。
假设我们有宿主机A与B,其上分别各有一个容器,分别称之为CA,CB,容器的ip分别为192.168.18.64/32与192.168.196.129/32。
首先我们看一下CA的网络信息:
[root@node00 ~]# docker exec -it containerA sh
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue
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
5: cali0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff
inet 192.168.18.64/32 scope global cali0
valid_lft forever preferred_lft forever
假设CA需要与CB进行通讯,执行ping命令ping 192.168.196.129
,首先看下CA的路由信息:
/ # ip route
default via 169.254.1.1 dev cali0
169.254.1.1 dev cali0
从路由信息可知,它们肯定不在同一个网段,必须经过169.254.1.1
这个网关来进行三层转发。所以ping包最终会交给该网关,二层地址是该网关地址,三层地址是要ping的ip地址。
为了获取该网关地址,需要发送一个arp广播包,我们来看下arp reply的回复的MAC地址是什么:
[root@node00 ~]# tcpdump -nn -i calif24874aae57 -e
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on calif24874aae57, link-type EN10MB (Ethernet), capture size 262144 bytes
13:54:28.280252 ee:ee:ee:ee:ee:ee > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: Request who-has 169.254.1.1 tell 192.168.18.64, length 28
13:54:28.280274 a2:ff:0a:99:57:d2 > ee:ee:ee:ee:ee:ee, ethertype ARP (0x0806), length 42: Reply 169.254.1.1 is-at a2:ff:0a:99:57:d2, length 28
我们发现arp的回包的mac地址是a2:ff:0a:99:57:d2
,这个地址是哪里来的呢?
首先我们得知道容器与宿主机该如何进行网络通讯。容器由于进行了网络隔离,所以宿主机是无法访问到容器内的网卡的,所以一般都会建立一个虚拟设备,叫veth
,它有两端,一端在容器内,一端在宿主机内,它的作用是作为一个通道,一端进去的数据,会由另一端读出,反之也是。所以我们通过veth
设备,就可以让宿主机和容器之间进行通讯了。
我们在CA中看到的网络设备,其中有一个叫cali0
的,就是veth
的一段,另一端则是宿主机的一个端口。我们来宿主机上看一下该veth pair
的信息:
# ethtool -S cali0
NIC statistics:
peer_ifindex: 6
# ip addr
6: calif24874aae57: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether a2:ff:0a:99:57:d2 brd ff:ff:ff:ff:ff:ff
inet6 fe80::a0ff:aff:fe99:57d2/64 scope link
valid_lft forever preferred_lft forever
我们可以看到,cali0
的对应的宿主机的一端,名为calif24874aae57
,MAC地址为a2:ff:0a:99:57:d2
,正式arp reply中回复的MAC地址。但是该网卡的ip并不是网关的ip,为何会做应答呢?
calico做了个特殊的设置,它开启了该网卡的arp proxy,让该网卡代答arp请求,收到任何请求,它都会将自己的MAC地址作为arp reply来发送回包:
# cat /proc/sys/net/ipv4/conf/calif24874aae57/proxy_arp
1
于是任何的数据包,最终都会到对应veth
宿主机上的网卡上,然后进行下一步的转发。
宿主机收到该数据包后,行为则是根据宿主机的路由表来进行了:
[root@node00 ~]# ip route
169.254.0.0/16 dev enp0s3 scope link metric 1002
169.254.0.0/16 dev enp0s8 scope link metric 1003
192.168.18.64 dev calif24874aae57 scope link
blackhole 192.168.18.64/26 proto bird
192.168.18.65 dev cali4e5ed993aed scope link
192.168.196.128/26 via 172.17.8.101 dev enp0s8 proto bird
我们可以看到,ping的对端ip地址是192.168.196.129
,命中的路由表条目为:
192.168.196.128/26 via 172.17.8.101 dev enp0s8 proto bird
最终该数据包会通过enp0s8
物理网卡口子通过物理网络的网关172.17.8.101
来进行发送。
经过物理网络的传输之后,宿主机B的物理网卡口子enp0s8
收到了网络数据包,我们看下宿主机B上的路由表条目:
[root@node01 ~]# ip route
169.254.0.0/16 dev enp0s3 scope link metric 1002
169.254.0.0/16 dev enp0s8 scope link metric 1003
192.168.18.64/26 via 172.17.8.100 dev enp0s8 proto bird
192.168.196.128 dev cali4907e793262 scope link
blackhole 192.168.196.128/26 proto bird
192.168.196.129 dev cali69b2b8c106c scope link
可以看到,dip为192.168.196.129
的数据包,最终会命中
192.168.196.129 dev cali69b2b8c106c scope link
该路由表条目,被转发到设备cali69b2b8c106c
上,和宿主机A一样,该网卡是一个veth pair
,最终就由CB容器收到了该数据包,该数据包就会由容器进行处理。
所以我们可以看出,calico的网络模型,需要在每台机器上都有各个该虚拟网络中所有节点的路由信息,不然数据包无法进行转发,该工作通常由BGP协议来实现的。