DockOne微信分享(二六二):谐云Calico大规模场景落地实践

【编者的话】本文主要介绍谐云在Calico容器网络在实践过程中,面对在大规模容器场景,根据每种Calico网络模式的优劣势,如何进行选型。重点讲解在实践过程中的遇到的容器网络高可用、频繁动态变更、服务稳定性等相关的问题,以及对应的解决方式。

概述

Calico是一个纯三层的方案,为虚拟机及容器提供多主机间通信。Calico部署便捷,功能稳定,并且提供丰富的Network Policy和IP地址管理功能,是很多企业在选择容器网络的第一选择。

Calico网络模式

Calico本身支持多种网络模式,从overlay和underlay上区分。Calico overlay模式,一般也称Calico IPIP或VXLAN模式,不同Node间Pod使用IPIP或VXLAN隧道进行通信。

Overlay模式

IPIP node-to-node Mesh

Calico Overlay模式部署简单,要求Node节点允许IPIP协议,如果有安全组策略需要开放IPIP协议;要求Node允许BGP协议,如果有安全组策略需要开放TCP 179端口;官方推荐使用在Node小于100的集群,我们在使用的过程中已经通过IPIP模式支撑了100-200规模的集群稳定运行。

IPIP RR

采用Calico RR模式通过建立路由反射器接点减少每个工作节点的BGP邻居数量,保证了集群支撑规模。

Calico IPIP模式对物理网络无侵入,符合云原生容器网络要求;使用IPIP封包,性能略低于Calico BGP模式;无法使用传统防火墙管理、也无法和存量网络直接打通。Pod在Node做SNAT访问外部,Pod流量不易被监控。

BGP模式

Calico underlay模式,一般也称calico BGP模式,不同Node Pod使用直接路由进行通信。

Kubernetes集群为什么要与交换机建立BGP连接呢?

  • 性能要求,Calico IPIP模式虽然能够满足大部分应用对于容器网络的性能要求,有些对网络延迟敏感的业务是不能使用overlay网络的。
  • 规模要求,在Calico BGP模式下,如果不与网络设备建立BGP连接,Node只能在同一个局域网内。
  • 安全管理要求,使用IPIP隧道会导致容器网络流量不能被传统的硬件防火墙管控,无法满足安全管理要求。使用硬件防火墙管理Pod IP,集群的规模会受到硬件设备的限制。在Calico BGP模式下,路由条目会从Node级别成Pod级别,使用EBGP模式可以将路由全部由交换机设备处理,目前看来企业数据中心级别核心交换机和接入交换机三层组网在支持1000-2000Node时,路由规模、BGP邻居、路由收敛速度就接近瓶颈;如果启用双栈,路由规模的压力会进一步增加。

BGP小规模集群

Node节点与交换机建立BGP邻居关系,学习Pod路由;Node和容器网络交换机建立BGP连接,在现网核心交换机上添加一条到容器网络的静态路由。这种模式适合有性能要求和管理要求的小规模集群。集群规模过大,需要在原有网络网关上频繁添加静态路由,增加网络管理员的了维护工作;频繁变更网络设备的配置,也存在一定的业务风险。

BGP大规模集群

Calico可以根据接入交换和核心交换机的性能参数,使用IBGP和EBGP容器组网。我们通常使用Calico的Downward Default模式来与交换机建立BGP连接,使用Node节点与接入交换机建立EBGP邻居关系,学习Pod路由;接入交换机将Pod路由汇聚后上报给核心交换机,将Pod路由分发到现网;采用Downward Default,Node网关是接入交换机,接入交换机网关是核心。这种模式减少了接入交换机和Node上的路由条目数量,但缺点是发送到无效IP的流量必须到达核心交换机以后,才能被确定为目的不可达。

Calico实践经验

Calico容器网络的高可用

在Calico IPIP模式,Pod间跨Node通信是通过Node IP建立IPIP隧道建立通信,Pod访问集群外网络,是通过Node SNAT 出去。只要保证Node网络是高可用的,Calico网络也是高可用。

生产上物理主机的网卡都是双网卡,并且使用bond模块配置高可用模式。对于物理主机而言,实际上是连接的两台交换机设备,当物理主机与交换机建立BGP邻居时,在堆叠组网模式或LACP组网模式下,需要交换机支持不间断路由的特性或者在主机与上联接入配置双BGP来实现路由的高可用。

路由更新速率问题

为什么要考虑路由更新速率?在Calico默认的使用模式中,Calico每个Node一个分配一个Block,每个Block默认为64个IP,当单个Node启动的Pod超过64时,才会分配下一个Block。Calico BGP client默认只向外通告聚合后的Block的路由,默认配置,只有在Node上下线、Node上Pod数量超过Block size的倍数才会出现路由的更新,路由的条目数量是Node级别的。

而实际业务在使用的过程中,会针对一个服务或者一个deployment分配一个IP Pool,这种使用模式会导致Calico的IP Pool没有办法按照Node聚合,出现一些零散的无法聚合的IP地址,最差的情况,会导致每个Pod产生一条路由,会导致路由的条目变为Pod级别。

在默认情况下,交换机设备为了防止路由震荡,会对BGP路由进行收敛保护。但是Kubernetes集群中,Pod生命周期短,变化频繁,需要关闭网络设备的路由变更保护机制才能满足Kubernetes的要求;对于不同的网络设备,路由收敛速度也是不同的,在大规模Pod扩容和迁移的场景,或者进行双数据中心切换,除了考虑Pod的调度时间、启动时间,还需要对网络设备的路由收敛速度进行性能评估和压测。

路由黑洞问题

使用Calico Downward Default模型组网时,Node使用EBGP模式与Node建立邻居关系。当Pod使用的IP地址为内部统一规划的地址,出现Pod IP地址紧张的时候,会出现Pod之间不能正常访问的情况。

Calico分配IP地址的原则为,将整个IPPool分为多个地址块,每个Node获得一个Block,当有Pod调度到某个Node上时,Node优先使用Block内的地址。如果每个新增的Node分不到一个完整的地址块,Calico IP地址管理功能会去使用其他Node的Block的IP,此时,就会出现Pod无法访问的现象。

如下图所示,Pod 10.168.73.82无法访问Pod 10.168.73.83。

查看Node 10.0.0.170的路由表,其中“blackhole 10.168.73.80/28 proto bird”为黑洞路由。如果没有其他优先级更高的路由,主机会将所有目的地址为10.168.73.80/28的网络数据丢弃掉。所以在Node 10.0.0.70上ping Pod 10.168.73.84会报“参数不合法”的错误。此时,在Downward Default模式下,Calico配置的这一条黑洞路由使得Node 10.0.0.70不能够响应其他Node上PodIP在10.168.73.80/28网段发起的网络请求。

首先,分析Calico黑洞路由的作用,查看Calico BGP Client中bird的配置文件:

配置解释:

  • Protocol static里面配置了一条静态路由到Node节点,为一条黑洞路由。BGP本身的机制会将路由通告出去。
  • Function calico_aggr里面定义的路由通告规则:路由目的地地址等于10.168.73.80/28的路由会执行accept,BGP Client会将路由通告出去;路由的地址被10.168.73.80/28包含的执行reject,BGP Client不会被通告出去。

通过这两条规则和静态路由,Calico做到了路由聚合,并且不通告明细路由的功能。

要解决路由黑洞问题问题,首先,除了对整个Calico 的IP Pool总量进行监控外,还需要对可用的IP Block进行监控,确保不会出现IP Block不够分的情况,或者或者IP地址Block借用的情况;也可以通过在规划时计算IP地址总量,以及在kubelet配置参数中指定maxPods来规避这个问题;但是实际上Kubernetes节点的上线和规模的扩展是一个渐进的过程,对于IP地址紧张的企业来说,提前预分配太多IP地址会浪费IP地址资源。

取消Calico的黑洞路由只需修改bird_aggre.cfg的模板文件即可,如下图所示。

取消Calico的黑洞路由会带来一些副作用,BGP协议会将每个Pod的明细路由通告出去,且路由表无法聚合。这会导致交换机的压力增大,每创建一个Pod都会进行一次路由通告。

Calico默认配置是IPIP隧道是IBGP模式,启用IBGP非IPIP模式黑洞路由也不会影响Pod之间的通信,因为出现Block不够的时候,Pod的明细路由比黑洞路由的优先级更高。只有在EBGP模式下,Node不学习Pod通信路由,在IP地址紧张的情况下,集群才会出现Pod通信故障。

动态更新IPPool问题

由于Calico的IPPool的CIDR字段不支持数组的形式,导致在IP地址扩容时,只能修改Pod template的annotation,会导致服务滚动升级,影响业务的稳定性。

我们通过添加一个新的ServiceIPPool的CRD,来记录服务和IPPool的映射关系,通过修改Calico CNI地址分配的流程。的来避免更新服务IPPool而引起的滚动升级。IPPool的disabled标识也是Calico官方推荐用来替换IP地址的方式。

kind: ServiceIPPool

metadata:

name: svc1

spec:

ipv4poolList: [ippool1,ipool2]

disabledIPv4PoolList: [ippool3,ipool4]

ipv6poolList: [ippool5,ipool6]

disabledIPv6PoolList: [ippool7,ipool8]

ServiceIPPool存储Service和IPPool的映射关系,为1:n的关系,一个Service可以对应多个IPPool。Deployment的annotation从IPPool列表修改为ServiceIPPool CR;原有calico-cni修改deployment对应的IPPool,需要修改pod template的annotation,会导致Pod重启。修改后只需要变更serviceIPPool,不需要进行滚动升级。但是缩容操作涉及到IPPool的释放,仍然不可避免的需要在下次滚动升级时才能释放,但是滚动升级的动作被推迟了。

总结

Calico部署便捷,功能稳定,已经有大量的落地案例,但是在不同的应用场景和需求,衍生出不同的使用模式。Calico的IP地址管理和集群的扩展性存在一定的矛盾,使用的便携性和安全要求也存在冲突,需要结合实际场景去权衡。

我们遇到的这些问题主要还是安全管理要求带来的,后续也会陆续开源到社区。

Q&A

Q:Calico和Flannel的对比及选择?

A:Flannel支持很多种封包类型,例如VXLAN、host-gw、ali-vpc等,也支持Windows。Calico使用IPIP、VXLAN隧道,也支持通过BGP把容器网络分发到物理网络。另外,Calico的Network Policy能单独和Flannel一起使用,能够利用Flannel丰富的网络后端,和Calico的网络策略。

Q:Calico的静态IP有没有扩展,是否支持无损?有没有进行自定义CNI的一些二次开发?

A: Calico能够针对单个Pod指定IP,适用场景太少;也支持浮动IP,但是浮动IP目前需要通过feature gate来开启,并且不能保证client Pod通过浮动IP访问多个Server Pod时,请求全部发送由一个Master Server Pod,并且基于路由而实现的浮动IP,受BGP选路原则的影响,在一些故障场景无法满足要求。针对有状态服务的功能需求,基于Calico开发了固定IP的功能。

Q: 我看文档的方案里选择EBGP,为什么不选择IBGP?

A:目前遇到使用Calico BGP模式的场景,主要还是希望能够在网络层面管控IP地址,这种需求决定了路由压力会比较大,而交换机本身就是为了处理网络问题,在路由处理上比Linux主机更加高效。IBGP会导致Linux主机也有很大的路由表。

Q:为什么不用二层网络的IP地址管理(Macvlan、Bridge),要使用Calico BGP?

A:在IP地址管理方面,ARP的是一种动态的缓存机制,而路由是相对静态,对比每个Pod产生的ARP记录和路由记录,ARP确实是有优势。但是,二层网络要实现Cluster IP在主机上有过多的网络配置;在虚拟机环境,二层网络要求混杂模式,还需要考虑和底层的虚拟机的网络的兼容性;以及在大规模也需要考虑广播风暴和交换机的转发表的条目问题,相比之下,我们还是优先选Calico BGP模式。

Q:有没有关注过Cilium?

A:我们一直在持续关注Cilium,但是考虑的已有落地案例和对内核的要求,现阶段还是主要选用Calico。

Q:你的分享中遇到的主要问题是不是都是因为IPPool的需求所造成的?

A:除了高可用之外,基本是都IP地址管理带来的,其实我们也比较建议在应用层或者Network Policy上去做安全管理,但是现在很多企业的安全要求是需要在网络层面做安全管理的。

Q:Calico双栈有没有实践过?有需要关注的坑嘛?

A:目前由于kubernetes的双栈特性还不稳定,我们只是在测试环境使用,并没有运行生产业务。

Q:Calico IBGP模式下 每个Node分配一个IP block段, 为啥在收敛路由的时候会增加路由表压力呢?

A:有服务级别的IP地址管理的情况下会有的。

Q:如何理解有服务级别的IPAM会有问题呢?方便举个例子吗?

A:因为Pod的创建流程,是先调度到Node节点,再分配IP地址的。如果对一个deploymnet指定的IPPool,Pod首先会调度到集群的各个Node上,然后再获得ip地址,支持的IPPool就无法按照Block聚合了。

Q:BGP是需要机房的交换机物理上支持的吗?

A:如果Node跨子网了,是需要交换机支持的。

Q:每个机器分配一个c段,IP池在c段内,会不会Pod分配到一台Node上?

A:当出现IP地址段不够分给Node的时候,当时IP地址总量够的时候,还是会的。

Q:Calico使用BGP模式后,为什么不支持跨网段访问呢?BGP不是边界路由协议吗?

A:如果只是Node开启BGP,IPPool禁用IPIP和VXLAN,而没有交换机的话,Node是不允许跨网段的,因为路由的next hop需要是邻居。

Q:Calico能支持最大规模是多少?比如能支持多少个Pod?有限制吗?

A:Calico的扩展性还是很好的,可以通过路由聚合和路由反射器减少BGP的连接数量和路由学习压力。

Q:Calico优缺点是什么,使用过程中有什么值得注意的地方?

A:Calico是一款成熟稳定的CNI,基于子网管理的灵活性是比不上SDN方案的,Calico性能比MacVLAN要差一点,但是Calico使用BGP可以方便的对接物理网络,有丰富的Network Policy,能够满足大部分要求。

Q:BGP是起在容器上的?用的ExaBGP?

A:BGP进程是以HostNetwork的形式运行在容器里面的,默认配置是node-to-node Mesh的iBGP模式。

Q:Calico使用iptables实现Network Policy,策略很多的时候,会不会有很大性能问题?

A:Calico使用IPset集合管理PodIP,集群和策略在一定的规模情况下,性能还是能满足要求的。

以上内容根据2020年5月28日晚微信群分享内容整理。 分享人 刘泽宇,杭州谐云科技有限公司容器网络架构师,负责公司容器云网络整体架构 。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesf,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章