容器网络的解决方案
跨节点的容器网络要解决两个问题:
-
容器如何分配IP
flannel设计了一种全局的网络地址分配机制,即使用etcd存储网段和节点之间的关系,然后flannel配置各个节点上的Docker(或其他容器工具),只在分配到当前节点的网段里选择容器IP地址。这样就确保了IP地址分配的全局唯一性。
-
容器IP地址如何路由
- overlay网络
- vxlan
- udp
- 直接路由
- host-gateway
- overlay网络
在overlay网络模式下,不论是UDP模式还是VXLAN模式,容器发送到网络中的数据包都会进行封包操作,这就难免会对性能造成一定的影响。在host-hateway模式下flannel通过在各个节点上运行的agent将容器网络的路由信息刷到主机的路由表上,目标容器的宿主机IP就是吓一跳地址,然而flannel只能修改各个主机的路由表,一旦主机之间隔了其他路由设备,比如三层路由器,这个包就会在路由设备上被丢掉。这样一来,Host-Gateway的模式就只能用于二层直接可达的网络。由于广播风暴问题,这种网络通常都是较小规模的。这篇文章将会介绍另一种基于直接路由方式的容器网络方案。
Calico
Calico主要组件
Calico和hots-gateway模式很类似,都是通过在宿主机增加路由规则实现容器组网,但是Calico并不像Flannel那样通过Etcd和宿主的Flanned维护路由信息,而是使用BGP协议(边界网关协议) 在集群内分发路由信息。
Felix
Felix是一个守护程序(在k8s中以DeaemonSe部署),以agent形式运行在宿主机上,负责刷新主机路由表信息,维护网络接口和报告主机状态等工作。
BGPClient
BGPClinet的作用是读取Felix编写到内核中的路由信息,并将路由信息分发到集群中的其他节点。
Calico工作原理
以容器1访问容器2为例,先进入容器1查看它的路由表和网络配置。
root@nginx-deployment-6b474476c4-p82xb:/# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
3: eth0@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1440 qdisc noqueue state UP group default
link/ether f6:64:05:f3:4b:be brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.16.123.5/32 brd 172.16.123.5 scope global eth0
valid_lft forever preferred_lft forever
4: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
可以看到容器1的IP地址为172.16.123.5/32,而MAC地址为ff:ff:ff:ff:ff:ff,这明显是一个固定的MAC地址,因为Calico不关心二层的MAC地址,只关心三层的IP地址。
当容器1执行ping 172.16.215.3/32时,因为两者不在同一网络内,所以容器1会查看自己的路由表。
root@nginx-deployment-6b474476c4-p82xb:/# ip route
default via 169.254.1.1 dev eth0
169.254.1.1 dev eth0 scope link
容器的的所有报文都会通过eth0发送到下一跳169.254.1.1,容器需要知道下一跳的MAC地址,那ARP请求发送到哪里那。eth0是veth pair 的一端,那它的另一端在哪那。我们可以通过ethtool -S eth0
列出对端网卡的index。
root@nginx-deployment-6b474476c4-p82xb:/# ethtool -S eth0
NIC statistics:
peer_ifindex: 4
rx_queue_0_xdp_packets: 0
rx_queue_0_xdp_bytes: 0
rx_queue_0_xdp_drops: 0
主机上index为4的网卡
root@work2:/home/work2/Desktop# ip addr
4: cali85354e41ec1@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1440 qdisc noqueue state UP group default
link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::ecee:eeff:feee:eeee/64 scope link
valid_lft forever preferred_lft forever
这块网卡并没有IP第地址,它接收到查询169.254.1.1的ARP报文会进行"代答",即将自己的MAC地址告诉容器1,后续报文则会转发给主机处理。
root@work2:/home/work2/Desktop# cat /proc/sys/net/ipv4/conf/cali85354e41ec1/proxy_arp
1
主机上的calixx网卡接收到报文后,再根据路由表转发
root@work2:/home/work2/Desktop# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.2.2 0.0.0.0 UG 100 0 0 ens33
169.254.0.0 0.0.0.0 255.255.0.0 U 1000 0 0 ens33
172.16.123.0 0.0.0.0 255.255.255.192 U 0 0 0 *
172.16.123.5 0.0.0.0 255.255.255.255 UH 0 0 0 cali85354e41ec1
172.16.123.6 0.0.0.0 255.255.255.255 UH 0 0 0 cali35e3a5cb80b
172.16.215.0 192.168.2.132 255.255.255.192 UG 0 0 0 tunl0
172.16.243.192 192.168.2.131 255.255.255.192 UG 0 0 0 tunl0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
192.168.2.0 0.0.0.0 255.255.255.0 U 100 0 0 ens33
接下来数据包会通过tun0设备发送到下一跳,也就是容器2的宿主机192.168.2.132/32。当数据包到达宿主机时,会先经过iptables规则,如果被iptables拦截那么数据包将会被丢弃。然后通过路由表转发,接着从cali34af9914629
网卡,发送到容器2。
# 容器2宿主机路由表
root@work1:/home/work1/Desktop# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.2.2 0.0.0.0 UG 100 0 0 ens33
169.254.0.0 0.0.0.0 255.255.0.0 U 1000 0 0 ens33
172.16.123.0 192.168.2.133 255.255.255.192 UG 0 0 0 tunl0
172.16.215.0 0.0.0.0 255.255.255.192 U 0 0 0 *
172.16.215.3 0.0.0.0 255.255.255.255 UH 0 0 0 cali34af9914629
172.16.243.192 192.168.2.131 255.255.255.192 UG 0 0 0 tunl0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
192.168.2.0 0.0.0.0 255.255.255.0 U 100 0 0 ens33
以上过程如下图所示
IPIP模式
通过上面的分析可以看出calico和host一样要求二层网络是可达的,但是在实际的部署中集群的网络通常划分在不同的网段中,calico如何处理跨网段通信那。在这种情况下就需要为Calico打开IPIP模式。
在IPIP模式下,calico会使用tunl0
设备,tunl0是一个ip隧道设备,通过上面的路由表发现,IP包会被tunl0设备接管。tunl0设备会将IP包封装为宿主机IP包。经过封装后的IP包,如下图所示
这样新的IP包就可以通过宿主机路由器发送了,如下图所示
Cailco在IPIP模式下会进行封包,也会对性能造成一定的影响,但是相对Flannel的VXLAN模式来说要好一些。
BGP Route Reflector
在默认配置下每台宿主机的BGPClient需要和集群所有的BGPClient建立连接,进行路由信息交换,随着集群规模的扩大,集群的网络将会面临巨大的压力并且宿主机的路由表也会变的过大。所以在大规模的集群中,通常使用BGP Route Reflector充当BGP客户端连接的中心点,从而避免与互联网中的每个BGP客户端进行通信。Calico使用BGP Route Reflector是为了减少给定一个BGP客户端与集群其他BGP客户端的连接。用户也可以同时部署多个BGP Route Reflector服务实现高可用。Route Reflector仅仅是协助管理BGP网络,并没有工作负载的数据包经过它们。