前言
G行全栈云容器大规模运行在信创服务器的虚拟机里,发现如跨NUMA访问CPU可能导致性能不均衡、容器网络和IaaS SDN耦合、虚拟层本身资源消耗等诸多问题。为解决这些问题,G行探索将容器运行在裸金属服务器上,推出裸金属容器平台方案,使用纯三层网络设计,其中东西向网络流量使用开源Calico容器组件,南北向网络流量使用自研ELB。本文主要介绍Calico BGP相关技术原理、实践和思考。
BGP介绍
BGP(Border Gateway Protocol,边界网关协议)为取代外部网关协议(EGP)协议而创建,属于经典网络路由协议。BGP相关的开源项目有bird、goBGP 等,开源软件运行在云平台的宿主主机上,使主机与网络设备交换路由信息,实现云上网络和云下网络的通信。
关键概念:
- AS(Autonomous System): 一个自治系统是受控于一家组织机构的路由器集合。在企业内部AS号是统一管理的,根据网络设备的AS号异同,可分为IBGP和EBGP。
- IBGP(Internal BGP):在相同AS路由器之间建立会话,一般认为IBGP运行在安全的网络环境。特点是IBGP的路由信息只能传一跳,不会传递给其他IBGP路由节点。否则,需要开启Router Reflect特性。
- EBPG(External BGP):在不同AS路由器之间建立会话。特点是EBGP路由器之间会同步彼此的路由。?
图一 网络架构
在典型Spine-Leaf架构下,Spine与Leaf之间运行EBGP协议,Leaf与裸金属服务器之间运行IBGP协议。
Calico网络
Calico是基于CNI实现的纯三层网络开源项目,首个版本在2015年发布,截止当前版本为Calico 3.26.1。该项目已被业界广泛接受,并拥有许多大规模的实际案例。
图二 Calico架构示意图
1. Calico关键组件
- Felix
Felix负责管理容器网络,配置容器IP地址、路由、iptables、安全策略等功能。在每个Worker节点运行代理程序,负责与容器管理平面通信,获取并配置网络和安全策略。
- Confd
监控Calico相关数据(BGP配置、IPAM配置等),动态生成Bird配置文件,并使Brid重新加载配置文件。
- Brid
发布路由:从Felix获取路由,并把路由分发给BGP邻居,外部流量通过该路由找到POD所在Worker节点。
路由反射 (Route Reflector): 收到IBGP邻居发布的BGP路由,并反射路由给其他IBGP邻居。
路由过滤:物理网络设备的所有路由表项会同步到本机,配置路由过滤,可以大量减少本机的路由条目。
- Typha
Flex通过Tyhpa直接跟Etcd交互,不再经过容器管理平面,在百节点以上的规模,能够有效降低对容器管理平面的访问压力。
2. Calico组网模式
- IPIP模式
Calico默认网络架构,IPIP可理解为IPinIP,属于overlay的网络架构。不依赖于外部交换机设备,即可实现网络组网。缺点是报文的封装和解封装对网络效率有影响,节点规模有限制。
- BGP模式
Calico最佳实践推荐该模式,计算节点与网络设备建立BGP邻居,并对外宣告POD的路由信息,网络设备学习到路由信息后,外部用户就可通过路由直接访问POD的地址,期间不涉及到报文的封装,网络效率非常高。在合理的网络架构设计下,节点规模灵活扩展且不影响网络效率。缺点是一般硬件网络设备和云平台的计算节点是由不同团队管理,遇到网络故障时需联合处置。
3. IPAM地址管理?
?Calico通过IPPool进行IPAM管理,IPPool定义了地址池名字、地址段、blockSize等字段。IPPool的配置样例如下:
apiVersion:crd.projectcalico.org/v1
kind: IPPool
metadata:
name: ippool-test-0
spec:
blockSize: 32
cidr: 1.1.1.0/24
ipipMode: Never
natOutgoing: false
nodeSelector: “!all()”
vxlanMode: Never
nodeSelector: 该字段与Kubernetes节点的Label进行映射。默认为all(),表示所有节点均可使用。设置为!all(),表示所有node均不可自动使用,可通过设置命名空间或者POD的注解,实现IPPool的绑定。
block/blockSzie: block主要功能是路由聚合,减少对外宣告路由条目。block在POD所在节点自动创建,如在worker01节点创建1.1.1.1的POD时,blocksize为29,则该节点自动创建1.1.1.0/29的block,对外宣告1.1.1.0/29的BGP路由,并且节点下发1.1.1.0/29的黑洞路由和1.1.1.1/32的明细路由。在IBGP模式下,黑洞路由可避免环路。如果blockSize设置为32,则不下发黑洞路由也不会造成环路,缺点是路由没有聚合,路由表项会比较多,需要考虑交换机路由器的容量。
Calico创建block时,会出现借用IP的情况。如在 worker01节点存在1.1.1.0/29的block,由于worker01节点负载很高,地址为1.1.1.2的POD被调度到worker02节点,这种现象为IP借用。woker02节点会对外宣告1.1.1.2/32的明细路由,在IBGP模式下,交换机需要开启RR模式,将路由反射给worker01上,否则在不同worker节点的同一个block的POD,由于黑洞路由的存在,导致POD之间网络不通。可通过ipamconfigs来管理是否允许借用IP(strictAffinity)、每个节点上最多允许创建block的数量(maxBlocksPerHost)等。
4 BGP模式下路由分析
举例说明,创建1.1.1.0/31的地址池,IPPool配置如下:
root@master1:~# calicoctl get ippool ippool-test-0
NAME CIDR SELECTOR
ippool-test-0 1.1.1.0/31 all()
使用该地址池,创建一个名字为nettool的POD,创建完成后,查看workloadendpoint资源信息。可查看得到,POD的IP地址为1.1.1.1/32,其网络接口对应在worker01节点的网卡为cali200f7a51a47。
root@master1:~# calicoctl get workloadendpoint
NAMESPACE WORKLOAD NODE NETWORKS INTERFACE
default nettool worker01 1.1.1.1/32 cali200f7a51a47
进入该容器,查看路由和接口信息。可查看得到,容器默认路由为169.254.1.1,且均指向eth0。通过ethtool查看得到,eth0接口的peer_ifindex为532。
root@master1:~# kubectl exec -it nettool sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
sh-4.4# ip a
1: lo: 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
2: tunl0@NONE: mtu 1480 qdisc noop state DOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
4: eth0@if532: mtu 1480 qdisc noqueue state UP group default
link/ether 86:61:23:4e:4e:d0 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 1.1.1.1/32 scope global eth0
valid_lft forever preferred_lft forever
sh-4.4# ip route
default via 169.254.1.1 dev eth0
169.254.1.1 dev eth0 scope link
sh-4.4# ethtool -S eth0
NIC statistics:
peer_ifindex: 532
rx_queue_0_xdp_packets: 0
rx_queue_0_xdp_bytes: 0
rx_queue_0_xdp_drops: 0
登录worker01节点,查看index为532的网卡接口,正是该接口cali200f7a51a47。worker01节点已经配置了ARP代理(主机上网卡不管ARP请求的内容,直接将自己的Mac地址作为应答的行为称为ARP Proxy)。Calico把worker01节点当做容器的默认网关使用,所有报文会发送到节点上,节点再根据路由信息进行转发。
root@worker01:~# ip a |grep 532
532: cali200f7a51a47@if4: mtu 1480 qdisc noqueue state UP group default
root@worker01:~# cat /proc/sys/net/ipv4/conf/cali200f7a51a47/proxy_arp
1
针对回程报文,我们查看节点的1.1.1.1对应路由,也正是该接口cali200f7a51a47。此时worker01节点的收发报文通路已经明了。
root@worker01:~# route -n |grep cali200f7a51a47
1.1.1.1 0.0.0.0 255.255.255.255 UH 0 0 0 cali200f7a51a47
最后,确认下交换机的路由情况。目的地址为1.1.1.1的下一跳为192.168.1.4,该IP地址是worker01主机IP。此时POD就可以跟外部进行通信。
Destination/Mask Proto Pre Cost Flags NextHop Interface
1.1.1.1/32 IBGP 255 0 RD 192.168.1.4 vlanif100
全栈云探索实践
综合考虑微隔离、网路可观测等技术储备已在G行推广使用,Calico默认不开启网络安全策略,依靠微隔离做网络安全管控。主要考虑BGP和IPAM上设计和管理网络。
1.BGP配置
1) 创建BGPconfigurations配置文件,声明节点的默认AS号。
root@master1:~# cat bgpconfigurations.yaml
apiVersion: crd.projectcalico.org/v1
kind: BGPConfiguration
metadata:
name: default
spec:
asNumber: 1111111
logSeverityScreen: Info
nodeToNodeMeshEnabled: false
2) 创建BGPPeer,明确交换机的AS号、BGP Peer IP,并将含有rr-group=rr1 的节点与交换机建立邻居。
root@master:~# cat bgppper1.yaml
apiVersion: crd.projectcalico.org/v1
kind: BGPPeer
metadata:
name: bgp-peer-1
spec:
asNumber: 1111111
nodeSelector: rr-group == 'rr1'
peerIP: 192.168.1.1
3) Kubernetes的节点打rr-group=rr1的标签
root@master1:~# kubectl get node --show-labels |grep rr1 |grep worker01
worker01 Ready worker 21d v1.23.15 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker01,kubernetes.io/os=linux,node-role.kubernetes.io/worker=,rr-group=rr1
4) 交换机配置
- BGP建立邻居
- BGP Policy,防止对外发布不可信路由
5) 裸金属Kubernetes节点查看BGP状态,Established意味着BGP邻居已经建立。
root@worker01:~# calicoctl node status
Calico process is running.
IPv4 BGP status
+--------------+---------------+-------+------------+-------------+
| PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
+--------------+---------------+-------+------------+-------------+
| 192.168.1.1 | node specific | up | 2023-08-17 | Established |
| 192.168.1.2 | node specific | up | 2023-08-17 | Established |
+--------------+---------------+-------+------------+-------------+
IPv6 BGP status
No IPv6 peers found.
2. IPAM配置相关信息
G行云平台底座和业务的IP分开管理,业务自行决定POD的亲和或反亲和,业务部署在自己的命名空间,不会出现多种业务在同一个命名空间部署的情况。
在超过20个节点的容器平台,应用POD会频繁发生IP地址借用情况,block的路由聚合效率大幅度降低。综合考虑交换机性能和容量,地址池的blockSize设置为32,交换机不开启RR特性。
为确保IP不会被其他业务使用,设定所有地址池的nodeSelector为!all()。
root@master1:~# calicoctl get ippool
NAME CIDR SELECTOR
ippool-test-0 1.1.1.0/24 !all()
ippool-test-1 1.1.2.0/24 !all()
ippool-test-2 1.1.3.0/24 !all()
ippool-test-3 1.1.4.0/24 !all()
在namespace中设定对应annotation。
apiVersion: v1
kind: Namespace
metadata:
annotations:
cni.projectcalico.org/ipv4pools: '["ippool-test-0"]'
name: test
3. Calico相关监控
Calico监控体系从三个方面进行覆盖。
- Calico组件和功能的监控,包含IPPool监控、Felix、Typha等组件监控。
- Calico网络边界的监控,主要是跟交换机的网络边界监控,网络流量通过可观测平台监控,网络控制面依赖于BGP报文的监控。
- 容器平台网络固有的监控,跟采用哪种CNI插件无关。如Calico相关POD健康与否、业务POD网络状态、容器节点网络信息等。
图三 Calico监控体系
Calico BGP模式相关思考
建设方面:Calico BGP建设需要多团队的配合。管理物理网络设备的团队,需全局规划网络设备的BGP信息、AS号和静态路由等,技术上避免单台交换机宕机引起路由的震荡(如一对Leaf交换机拥有不同AS号,会造成路由震荡);管理云平台的团队,需要合理配置iBGP和IPPool,避免发布非法路由,影响其他网络设备。
运维方面:变更管理/故障管理需云和网配合进行,明确双方分工和问题界定,紧密协作。比如管理云平台的团队配置BGP Filter功能,物理网络设备配置BGP Policy,防止对外发布非法路由,形成双保险。在技术探索过程中,引入可观测平台全链路流量和BGP监控等工具,最大程度将问题边界描述清晰,并提高运维效率。
后续细化Calico BGP监控指标,探索Calico eBPF数据面的实现,弱化iptables对网络的影响。