Flannel
一、初识Flannel
flannel是一个专为kubernetes定制的 三层 网络解决方案,主要用于解决容器的 跨主机通信 问题。
优势:
- Kubernetes发行版都可以默认安装Flannel;
- 容易安装和配置;
- 中小型网络架构首选;
- 不需要专用的数据存储;
劣势:
- 性能损耗高;
- 不支持Network Policy;
二、Flannel的三种后端实现
- UDP模式(弃用):使用设备flannel.0进行封包解包,不是内核原生支持,上下文切换较大,性能差。
- VXLAN:Overlay Network方案。
- Host-GW模式,一种纯三层网络方案。
2.1、VXLAN(默认)
docker0(CNI):网桥设备,每创建一个pod都会创建一对 veth pair;
Flannel.1:overlay 网络的设备,用来进行 vxlan 报文的处理(封包和解包);
Flanneld:Flannel 在每个主机中运行 flanneld 作为 agent,它会为所有主机从集群的网络地址空间中,获取一个小的网段。维护了各个节点之间的路由表信息。
数据流传输流程:
- 1、源容器A向目标容器发送数据,数据首先发送给 cni0 网桥;
- 2、cni0 网桥接受到数据后,将其转交给 flannel.1 虚拟网卡处理;
- 3、flannel.1 接受到数据后,对数据进行封装,并发给Node1宿主机的 eth0;
- 4、目标容器Node2宿主机的eth0接收到数据后发现是vxlan的包,对数据包进行拆封,并转发给flannel.1虚拟网卡;
- 5、flannel.1 虚拟网卡接受到数据,然后将数据发送给docker0网桥;
- 6、最后,数据到达目标容器B,完成容器之间的数据通信;
这样通过一层层的封装和解包实现了一个跨节点的大VLAN数据传输;
缺点:先进行二层帧封装,再通过宿主机网络封装,解封装也一样,所以增加性能开销
2.2、节点内通信
节点内的容器间通信通过 cni0
网桥就能完成,不涉及任何VXLAN报文的封包解包。
例如在下面的图例中,Node1的子网为10.244.0.1/24, PodA 10.244.0.20 和 PodB 10.224.0.21通过 cni0
网桥实现互通。
2.3、Host-GW
Flannel的host-gw模式是一种纯三层的网络互通方案,Pod之间互相访问是通过路由方式实现。host-gw模式下跨节点网络通信网络通信需要通过节点上的路由表实现,因此必须要通信双方所在宿主机能够直接路由。这就要求该模式下集群中所有节点必须处于同一个网络内。
数据流传输流程:
在host-gw模式下,由于不涉及VXLAN的封包解包,不再需要flannel.1
虚机网卡。 flanneld
负责为各节点设置路由 ,将对应节点Pod子网的下一跳地址指向对应的节点的IP;
缺点:host-gw另外一个限制则是随着集群中节点规模的增大,flanneld维护主机上成千上万条路由表的动态更新也是一个不小的压力,因此在路由方式下,路由表规则的数量是限制网络规模的一个重要因素。
三、总结
VXLAN特点:
- 先进行二层帧封装,再通过宿主机网络封装,解封装也一样,所以增加性能开销
- 对宿主机网络要求低,只要三层网络可达
Host-GW特点:
- 直接路由转发,性能损失小
- 对宿主机网络要求二层可达
Calico
一、网络基础知识
广播域
01 交换机在转发数据时会先进行广播,这个广播可以发送的区域就是一个广播域
02 交换机之间对广播帧是透明的,所以交换机之间组成的网络是一个广播域
03 路由器的一个接口下的网络是一个广播域,所以路由器可以隔离广播域
ARP(地址解析协议)
01 发送这个广播帧是由ARP协议实现
02 ARP是通过IP地址获取物理地址的一个TCP/IP协议
三层交换机
01 二层交换机只工作在数据链路层
02 路由器则工作在网络层
03 三层交换机可同时工作在数据链路层和网络层,并根据 MAC地址或IP地址转发数据包
VLAN(Virtual Local Area Network):虚拟局域网
01 VLAN是一种将局域网设备从逻辑上划分成一个个网段
02 一个VLAN就是一个广播域,VLAN之间的通信是通过第3层的路由器来完成的
03 VLAN应用非常广泛,基本上大部分网络项目都会划分vlan
VLAN的主要好处
01 分割广播域,减少广播风暴影响范围。
02 提高网络安全性,根据不同的部门、用途、应用划分不同网段
1.2、路由技术
路由器主要分为两个端口类型
路由器主要分为两个端口类型:LAN口和WAN口
- WAN口:配置公网IP,接入到互联网,转发来自LAN口的IP数据包。
- LAN口:配置内网IP(网关),连接内部交换机
功能
- 路由器是连接两个或多个网络的硬件设备
- 将从端口上接收的数据包,根据数据包的目的地址智能转发出去
路由器的功能
• 路由
• 转发
• 隔离子网
• 隔离广播域
路由
- 01、静态路由:指人工手动指定到目标主机的地址然后记录在路由表中,如果其中某个节点不可用则需要重新指定。
- 02、动态路由:则是路由器根据动态路由协议自动计算出路径永久可用,能实时地适应网络结构的变化。
- 03、常用的动态路由协议:
• RIP( Routing Information Protocol ,路由信息协议)
• OSPF(Open Shortest Path First,开放式最短路径优先)
• BGP(Border Gateway Protocol,边界网关协议)
1.3、K8S网络模型
回看Docker容器网络模型
相关概念
- 01、Linux在网络栈中引入网络命名空间,将独立的网络协议栈隔离到不同的命令空间中,彼此间无法通信;
- 02、Docker利用这一特性,实现不同容器间的网络隔离。
• Veth设备对:Veth设备对的引入是为了实现在不同网络命名空间的通信。
• Iptables/Netfilter:Docker使用Netfilter实现容器网络转发。
• 网桥(docker0):网桥是一个二层网络设备,通过网桥可以将Linux支持的不同的端口连接起来,并实现类似交换机那样的多对多的通信。
• 路由:Linux系统包含一个完整的路由功能,当IP层在处理数据发送或转发的时候,会使用路由表来决定发往哪里。
容器之间通信
二层网络之间的通信
容器访问外网
通过docker0,NAT转发到外网
ip route
1.4、Pod网络
infra container
Pod是K8s最小调度单元,一个Pod由一个容器或多个容器组成,当多个容器时,怎么都用这一个Pod IP?
- 01、k8s会在每个Pod里先启动一个infra container小容器,然后让其他的容器连接进来这个网络命名空间
- 02、其他容器看到的网络就完全一样了。即网络设备、IP地址、Mac地址等。
- 03、在Pod的IP地址就是infra container的IP地址
pod通信
在 Kubernetes 中,每一个 Pod 都有一个真实的 IP 地址,并且每一个 Pod 都可以使用此 IP 地址与 其他 Pod 通信。Pod之间通信会有两种情况:
• 两个Pod在同一个Node上
• 两个Pod在不同Node上
两个Pod在同一个Node上
- 01、对 Pod1 来说,eth0 通过虚拟以太网设备(veth0)连接到 root namespace;
- 02、网桥cbr0中为veth0配置了一个网段。一旦数据包到达网桥,网桥使用ARP协议解析出其正确的目标网段veth1;
- 03、网桥 cbr0 将数据包发送到 veth1;
- 04、数据包到达 veth1 时,被直接转发到Pod2的network namespace中的eth0 网络设备。
两个Pod在不同Node上
相比同节点Pod通信,这里源Pod发出的数据包需要传递到目标节点,但是源Pod并不知道目标Pod在哪个节点上?
因此,为了实现容器跨主机通信需求,就需要部署网络组件,这些网络组件都必须满足如下要求:
• 一个Pod一个IP
• 所有的 Pod 可以与任何其他 Pod 直接通信
• 所有节点可以与所有 Pod 直接通信
• Pod 内部获取到的 IP 地址与其他 Pod 或节点与其通信时的 IP 地址是同一个(pod绑定IP生命周期)
1.5、CNI(容器网络接口)
CNI(Container Network Interface,容器网络接口):是一个容器网络规范,Kubernetes网络采用的就是这个CNI规范,负责初始化infra容器的网络设备。
二、架构实现
Calico在每个计算节点都利用Linux Kernel实现了一个高效的vRouter来负责数据转发。
每个vRouter都通过BGP协议把在本节点上运行的容器的路由信息向整个Calico网络广播,并自动设置到达其他节点的路由转发规则。
Calico 项目还实现了 Kubernetes 网络策略,提供ACL功能。
BGP 举个例子:
01 在这个图中,有两个自治系统(autonomous system,简称为AS):AS 1 和 AS 2。
02 在互联网中,一个自治系统(AS)是一个有权自主地决定在本系统中应采用何种路由协议的小型单位。
03 这个网络单位可以是一个简单的网络也可以是一个由一个或多个普通的网络管理员来控制的网络群体,它是一个单独的可管理的网络单元(例如一所大学,一个企业或者一个公司个体)。
04 一个自治系统有时也被称为是一个路由选择域(routing domain)。一个自治系统将会分配一个全局的唯一的16位号码,有时我们把这个号码叫做自治系统号(ASN)。
05 在正常情况下,自治系统之间不会有任何来往。如果两个自治系统里的主机,要通过 IP 地址直接进行通信,我们就必须使用路由器把这两个自治系统连接起来。BGP协议就是让他们互联的一种方式
Calico组件功能:
- Felix:daemonSet部署,主要负责维护宿主机路有规则及ACL;
- BGP:把Felix写入的路由信息分发到集群;
- ETCD:保存calico策略和路由信息;
- BGP Route Reflector(BIRD):大规模部署时使用,摒弃所有节点互联的mesh模式,通过一个或者多个 BGPRoute Reflector 来完成集中式的路由分发;
区别:
Flannel使用flanneld进程来维护路由信息;
Calico使用BGP协议来维护整个集群路由信息;
三、Calico架构图
Calico 通过巧妙的引导 workload 所有的流量至一个特殊的网关 169.254.1.1,从而引流到 host 的 calixxx 网络设备上,形成了二三层流量全部转换 host 的三层流量转发。
不同宿主机间的pod访问流程如下:
- 1、容器1的所有报文都会通过eth0发送到下一跳169.254.1.1;
- 2、主机上的calixx网卡接收到报文后,再根据路由表转发;
- 3、数据包会通过tun0设备发送到下一跳,也就是容器2的宿主机192.168.2.132/32;
- 4、通过路由表转发,接着从cali34af9914629网卡,发送到容器2。
四、Calico的具体实现
全互联模式(node-to-node mesh)
1、IPIP模式:
和flannel的vxlan差不多模式,基于二层数据的封装和解封;也会创建一个 虚拟网卡 tunl0,把两个本来不通的网络通过点对点连接起来,都是一种复杂的网络方案,IPIP和vxlan模式的性能基本上接近,所以在性能方面要相对于路由方面损失10-20%。
2、BGP模式:
和flannel的host-gw模式几乎一样,Calico 项目实际上将集群里的所有节点,都当作是边界路由器来处理,它们一起组成了一个全连通的网络,互相之间通过 BGP 协议交换路由规则。
路由反射模式Router Reflection(RR)
指定一个或多个BGP Speaker为RouterReflection,它与网络中其他Speaker建立连接,每个Speaker只要与Router Reflection建立BGP就可以获得全网的路由信息。
4.1、IPIP模式改为BGP模式
[root@k8s-master ~]# calicoctl get ippool -o wide
NAME CIDR NAT IPIPMODE VXLANMODE DISABLED SELECTOR
default-ipv4-ippool 10.244.0.0/16 true Always Never false all()
[root@k8s-master calico]# calicoctl get ippool -o yaml > ippool.yaml
[root@k8s-master calico]# vim ippool.yml
ipipMode: Always
这里是启用了ipip模式,设置为never就是关闭了ipip模式就会采用BGP模式
ipipMode: Never
ipipMode: Never
这样ipip模式关闭使用bgp
[root@k8s-master calico]# calicoctl apply -f ippool.yaml
Successfully applied 1 'IPPool' resource(s)
[root@k8s-master ~]# calicoctl get ippool -o wide
NAME CIDR NAT IPIPMODE VXLANMODE DISABLED SELECTOR
default-ipv4-ippool 10.244.0.0/16 true Never Never false all()
现在没有配置IP了,通过这个可以判断有没有成功
[root@k8s-master calico]# ip addr
4: tunl0@NONE: mtu 1440 qdisc noqueue state UNKNOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
inet 10.244.235.192/32 brd 10.244.235.192 scope global tunl0
valid_lft forever preferred_lft forever
这里tul0网卡就没用了,因为不需要封包,所以容器内部的数据到达到宿主机直接从网卡出去了,BGP模式相对于ipip模式少了tul0设备的介入,数据的封装。
[root@k8s-master ~]# ip route
default via 192.168.179.2 dev ens32 proto static metric 100
10.244.36.64/26 via 192.168.179.103 dev ens32 proto bird
10.244.169.128/26 via 192.168.179.104 dev ens32 proto bird
这里没有tul0的路由了,数据包到达宿主机上面了,根据这个路由表去转发。这个和flannel的host-gw是一样的。
4.2、BGP模式改为路由反射(Route Reflector)模式
Calico集群中的节点之间都会相互建立连接,用于路由交换。但是随着集群规模的扩大,mesh模式将形成一个巨大服务网格,连接数成倍增加,就会产生性能问题。
我们来具体看下路由信息:(集群3节点,如下节点维护了另外2条node节点的路由)
[root@k8s-master calico]# calicoctl node status
Calico process is running.
IPv4 BGP status
+-----------------+-------------------+-------+----------+-------------+
| PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
+-----------------+-------------------+-------+----------+-------------+
| 192.168.179.103 | node-to-node mesh | up | 06:49:37 | Established |
| 192.168.179.104 | node-to-node mesh | up | 06:48:39 | Established |
+-----------------+-------------------+-------+----------+-------------+
IPv6 BGP status
No IPv6 peers found.
这个就是BGP client里面有个进程叫bird,这个bird就是负责BGP协议的通信完成路由表学习,随着连接的增多,下面这两个也会增多,使用的端口是179。
[root@k8s-master ~]# ss -antp | grep ESTAB | grep bird
ESTAB 0 0 192.168.179.102:179 192.168.179.104:36323 users:(("bird",pid=3517,fd=8))
ESTAB 0 0 192.168.179.102:179 192.168.179.103:33128 users:(("bird",pid=3517,fd=9))
[root@k8s-node1 ~]# ss -antp | grep ESTAB | grep bird
ESTAB 0 0 192.168.179.103:179 192.168.179.104:41043 users:(("bird",pid=3098,fd=8))
ESTAB 0 0 192.168.179.103:33128 192.168.179.102:179 users:(("bird",pid=3098,fd=9))
[root@k8s-node2 ~]# ss -antp | grep ESTAB | grep bird
ESTAB 0 0 192.168.179.104:36323 192.168.179.102:179 users:(("bird",pid=2320,fd=8))
ESTAB 0 0 192.168.179.104:41043 192.168.179.103:179 users:(("bird",pid=2320,fd=9))
如果节点达到了100+节点,这样当业务出现高并发场景,巨大的网络路由会造成很大的损耗,这时就需要使用 Route Reflector(路由器反射)模式解决这个问题。
Route Reflector模式下的实现:
从集群当中找出多台性能较好的节点,当作路由反射器,让其他的BGP client通过这两个节点获取路由表的信息,这两个路由反射器相对于代理的角色(Nginx),其他人都是从这获取路由表的学习,那么压力就集中在这两台,做路由的集中下发,BGP client就是从这里面获取所有的路由表。所以每个节点只要和路由反射器建立关系就行,有两个路由反射器就建立两个链接,这样就避免了一个节点需要建立其它上千台node节点损耗的问题。
1、关闭 node-to-node模式
关闭node to node模式就代表网络不通(一旦更改,整个集群网路就会断掉!!!线上一定要先评估!!)
[root@k8s-master calico]# calicoctl get bgpconfig
NAME LOGSEVERITY MESHENABLED ASNUMBER
[root@k8s-master ~]# calicoctl get node -o wide
NAME ASN IPV4 IPV6
k8s-master (64512) 192.168.179.102/24
k8s-node1 (64512) 192.168.179.103/24
k8s-node2 (64512) 192.168.179.104/24
调整as的编号
[root@k8s-master calico]# cat bgpconfig.yaml
apiVersion: projectcalico.org/v3
kind: BGPConfiguration
metadata:
name: default
spec:
logSeverityScreen: Info
nodeToNodeMeshEnabled: false
asNumber: 64512
[root@k8s-master calico]# calicoctl apply -f bgpconfig.yaml
Successfully applied 1 'BGPConfiguration' resource(s)
[root@k8s-master calico]# calicoctl get bgpconfig
NAME LOGSEVERITY MESHENABLED ASNUMBER
default Info false 64512
在其他节点访问不了Pod
[root@k8s-master ~]# ping 10.244.169.138
PING 10.244.169.138 (10.244.169.138) 56(84) bytes of data.
[root@k8s-master ~]# calicoctl node status
Calico process is running.
IPv4 BGP status
No IPv4 peers found.
IPv6 BGP status
No IPv6 peers found.
2、配置指定节点充当路由反射器 从当前节点找两个节点充当路由反射器,作为路由反射器。 为方便让BGPPeer轻松选择节点,通过标签选择器匹配。给路由器反射器节点打标签:
kubectl label node k8s-node2 route-reflector=true
给选定的节点指定路由反射器 ID: routeReflectorClusterID
这个可以写任意集群当中没有使用的ip
[root@k8s-master ~]# calicoctl get node k8s-node2 -o yaml > rr-node.yaml
[root@k8s-master ~]# vim rr-node.yaml
bgp:
ipv4Address: 192.168.179.104/24
routeReflectorClusterID: 244.0.0.1 # 集群ID,保证唯一性
[root@k8s-master ~]# calicoctl apply -f rr-node.yaml
Successfully applied 1 'Node' resource(s)
3、配置路由反射器节点配置为对等
匹配所有节点带有这个标签的作为路由反射器,这就是非路由反射器和路由反射器建立关系
[root@k8s-master calico]# calicoctl apply -f bgppeer.yaml
Successfully applied 1 'BGPPeer' resource(s)
[root@k8s-master calico]# cat bgppeer.yaml
apiVersion: projectcalico.org/v3
kind: BGPPeer
metadata:
name: peer-with-route-reflectors
spec:
nodeSelector: all()
peerSelector: route-reflector == 'true'
查看节点的BGP连接状态:
[root@k8s-master calico]# calicoctl node status
Calico process is running.
IPv4 BGP status
+-----------------+---------------+-------+----------+-------------+
| PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
+-----------------+---------------+-------+----------+-------------+
| 192.168.179.104 | node specific | up | 08:18:00 | Established |
+-----------------+---------------+-------+----------+-------------+
IPv6 BGP status
No IPv6 peers found.
查看规则:
[root@k8s-master calico]# calicoctl get bgppeer
NAME PEERIP NODE ASN
peer-with-route-reflectors all() 0
现在网络就可以通了
[root@k8s-master ~]# ping 10.244.169.163
PING 10.244.169.163 (10.244.169.163) 56(84) bytes of data.
64 bytes from 10.244.169.163: icmp_seq=1 ttl=63 time=4.57 ms
64 bytes from 10.244.169.163: icmp_seq=2 ttl=63 time=0.306 ms
64 bytes from 10.244.169.163: icmp_seq=3 ttl=63 time=0.722 ms
[root@k8s-master calico]# ss -antp | grep ESTAB | grep 179 | grep bird
ESTAB 0 0 192.168.179.102:179 192.168.179.104:57580 users:(("bird",pid=3147,fd=8))
[root@k8s-node2 ~]# ss -antp | grep ESTA | grep bird
ESTAB 0 0 192.168.179.104:179 192.168.179.103:49411 users:(("bird",pid=2320,fd=8))
ESTAB 0 0 192.168.179.104:47748 192.168.179.102:179 users:(("bird",pid=2320,fd=9))
当然rr和nginx也是一致的,也需要高可用,所以我们尽量配置2台以上的节点!
条件允许的话,最好找2台单独的机器!
[root@k8s-master1 ~]# kubectl label node k8s-node1 route-reflector=true
node/k8s-node1 labeled
[root@k8s-master1 ~]# calicoctl get node k8s-node1 -o yaml > node1.yaml
[root@k8s-master1 ~]# vim node1.yaml(增加和node2一致即可)
···
routeReflectorClusterID: 244.0.0.1 # 集群ID,保证唯一性
···
[root@k8s-master1 ~]# calicoctl apply -f node1.yaml
Successfully applied 1 'Node' resource(s)
再次查看:
[root@k8s-master1 ~]# calicoctl node status
Calico process is running.
IPv4 BGP status
+----------------+---------------+-------+----------+-------------+
| PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
+----------------+---------------+-------+----------+-------------+
| 192.168.171.13 | node specific | up | 15:19:42 | Established |
| 192.168.171.12 | node specific | up | 15:26:13 | Established |
+----------------+---------------+-------+----------+-------------+
五、性能验证
Calico中BGP&IPIP&RR性能数据( qperf测试工具):测试分两阶段进行,分别测试“主机到pod”、“pod到pod”两种网络模型
- 1、calico BGP模式相对于IPIP模式,约有5%网络传输速率的提升。
- 2、calico BGP模式相对于IPIP模式,约有10%-30%延迟的减少。
- 3、calico IPIP模式支持跨网段访问,BGP模式不支持跨网段访问。
- 4、在nginx测试中,pod之间的小包延迟降低约33%
- 5、在nginx测试中,pod之间的大包延迟降低约40%
结论:
- calico使用BGP网络模式通信网络传输速率较好!
- 但是跨节点后pod不能通信!
六、总结:
- Calico作为kubernetes的网络组件之一已经在云原生众多开源项目中脱颖而出。
- Calico与flannel(大二层网络方案)对比,由于使用BGP网络协议代替二层网络中flannel进程的封包解包过程从而大大提高本身的传输性能;
- Calico可以配合使用Network Policy做pod和pod之前的访问控制,对于实际生产环境也是非常重要的一项安全功能。
CNI 网络方案优缺点及最终选择:
先考虑几个问题:
1、需要细粒度网络访问控制?–> flannel不支持,calico支持(ACL);
2、追求网络性能? –> flannel(host-gw),calico(BGP);
3、当前架构下是否可以跑BGP协议? –> 公有云有些不支持;
4、集群规模多大? –> 100台node左右推荐(flannel,host-gw)维护方便;
5、是否有维护能力? –> calico维护复杂,路由表!
服务器租用托管,机房租用托管,主机租用托管,https://www.e1idc.com