ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Calico IPIP模式详解:从原理到跨子网Pod通信配置与故障排查

Calico IPIP模式详解:从原理到跨子网Pod通信配置与故障排查 1. 先搞明白Calico IPIP到底在解决什么问题我最早接触Calico的时候心里一直有个疑问Calico主打的是纯BGP路由、性能高那为什么还要搞一个IPIP的Overlay模式出来后来在真实集群里跨网段部署了一次才彻底理解这个设计背后的取舍。先说结论Calico的IPIP模式本质上就是用一条“隧道”把原本不在同一张二层网络里的节点强行变成一个可以互相路由的三层网络。它解决的问题是节点之间跨子网、跨VPC、无法直接通过物理路由互联时的连通性问题。在Calico的架构里每个节点上跑着一个Felix组件它的职责是维护本节点的路由、iptables规则和veth对。Calico默认的BGP模式是把每个Pod的IP当作普通路由条目通过BGP协议在节点之间互相宣告。只要节点之间三层可达BGP就能把路由传过去PodIP自然也能通。这句话听起来很简单但有一个隐含前提节点之间的路由必须是通的。现实里的K8s集群不会那么理想。我遇到过很多场景节点分布在多个VPC网段中间隔着一台云厂商的转发网关节点的物理网卡连着交换机但交换机没有开启动态路由协议或者干脆就是混合云一部分机器在自建机房一部分在云上中间只有一条IPsec或专线。在这些场景里纯BGP宣告的Pod网段路由要么被云平台的黑洞路由挡住要么根本传不到对端节点甚至会把物理网络的转发搞乱。此时如果还是死守纯BGP模式Pod跨节点通信就会直接不通。IPIP的解法很粗暴它把PodIP的报文再包一层外层源IP是本节点物理IP外层目的IP是目标节点的物理IP内层才是真正的PodIP到PodIP的报文。这样一来网络中间设备看到的只是一条普通的IP单播流量不关心内层的Pod网段自然也就不会出现“路由不认识Pod网段”的问题。等报文到了目标节点内核再把外层头解开把内层报文交给本地的路由表处理完成交付。这个思路用大白话讲就像寄快递时写了两层地址外壳写的是两个节点机房的具体地址快递公司只认这层地址里面那层才写着Pod的真实地址。快递到了目的地由门口的值班人员拆开外壳再按内层地址送到具体工位。外层地址负责跨网段可达内层地址负责本地精确投递。我个人的理解是Calico在IPIP模式下依然保留了BGP的路由分发能力只是把数据面的转发路径从“物理路由直达”改成了“隧道封装”。这也是为什么不少资料里说IPIP是“介于纯BGP和VXLAN之间的折中方案”它比VXLAN少了UDP头封装开销小比纯BGP多了隧道层能穿透不感知Pod网段的三层网络。理解了这一层后面配置IPIP时你就知道什么时候该开、什么时候不该开而不是照抄网上的配置。2. 正式启用IPIP前要弄清楚的几个关键选择2.1 IPIP、VXLAN和纯BGP怎么选Calico官方在安装时会默认启用VXLAN这个默认值影响了很多刚上手的人。但实际生产里IPIP的使用场景比VXLAN更贴近“跨子网但不跨大区域”的网络所以不能简单地觉得“默认用VXLANIPIP就是过时的”。其实是三种模式各有各的适用面。我先给你一个对比维度方便做选择时心里有数对比维度纯BGPIPIPVXLAN封装方式无封装IP头封装UDPIP头封装额外开销0字节20字节24字节含UDP能否跨三层网络依赖物理路由可以可以报文载荷大小限制无额外限制需要处理MTU需要处理MTU性能损耗最低较低相对略高适合场景同二层/可控路由跨子网但不想上VXLAN大规模多租户或云环境选择时我有一个比较实用的判断顺序第一节点之间是否已经能直接ping通物理IP如果能再确认一下物理网络设备是否关心Pod网段路由。如果网络设备完全不感知也不产生干扰那纯BGP就可以。如果节点之间跨越了不归你管的路由域比如云平台VPC网关、第三方防火墙、机房核心交换机就优先考虑IPIP或VXLAN。第二网络带宽和延迟敏感度高不高在存储之类的场景里每次转发多20或24字节的开销高并发下累积起来是不容忽视的损耗。IPIP额外开销只有20字节比VXLAN少4字节而且没有UDP头在一些网卡支持Tunnel Offload的情况下性能会更接近纯BGP。第三你的网络需要IPv6吗IPIP在Calico中一直有IPv4和IPv6的区分VXLAN也支持但VXLAN的UDP封装在某些云安全组里需要额外放行端口。IPIP没有端口概念只依赖IP协议号4安全组上放行更简单。2.2 关键参数IPIPMode的三种写法Calico里启用IPIP核心是修改IPPool资源的ipipMode字段。很多人第一次看到这个字段时会懵因为它的取值不是简单的“开启”和“关闭”而是有三个Always对所有使用这个IPPool的Pod强制启用IPIP隧道不管目标节点在不在同一网段。CrossSubnet只有跨子网通信时才启用IPIP同子网内直接走纯BGP路由。Never完全禁用IPIP。我强烈建议有条件的话优先用CrossSubnet。原因很简单同子网内节点之间通过二层网络直连本来就可以靠ARP和直连路由完成通信硬套一层IPIP只会白白增加延迟和MTU问题。CrossSubnet让Calico自己判断目标节点是否位于不同子网只在真正需要隧道时封装。这个设计很贴心实际效果也确实能兼顾性能和连通性。Always则适用于“就算同子网也不想依赖BGP”的场景不过大多数情况下没必要。而且Always模式下如果物理网卡的MTU没有同步调小很容易出现Pod之间能ping通但HTTP大包访问超时的诡异问题。后面我会专门说MTU。Never就不用多说了纯BGP模式下的默认值。还有一点需要提醒IPIPMode是一个IPPool级别的基础配置不是全局的统一开关。这意味着你可以创建多个IPPool每个IPPool用不同的IPIP模式服务不同的业务组。这种做法在生产里很实用比如核心链路用Never跨机房业务用Always或CrossSubnet。Calico的Felix最终会为每个IPPool生成对应的路由和隧道规则多个池之间不会互相打架。3. 从零配置IPIP的实操步骤这一节我按最常见的场景来写集群已经用Calico插件建好节点分布在两个子网Pod网段使用的是默认的10.244.0.0/16或10.10.0.0/16现在要把跨子网通信从纯BGP模式切换到IPIP CrossSubnet模式。3.1 确认当前Calico的IPPool配置动手之前先看现状。Calico的资源里IPPool是决定Pod地址分配和路由策略的核心对象。用kubectl查看kubectl get ippool -o yaml输出里一般会有一个名为default-ipv4-ippool的池内容大概是apiVersion: projectcalico.org/v3 kind: IPPool metadata: name: default-ipv4-ippool spec: cidr: 10.244.0.0/16 ipipMode: Never natOutgoing: true vxlanMode: Never disabled: false这里ipipMode显示Never说明当前的Pod跨节点通信完全依赖BGP。如果你发现节点确实分布在多个子网而且跨子网Pod通信有问题就可以动手改成IPIP。我习惯在改动前先备份kubectl get ippool default-ipv4-ippool -o yaml ippool-backup.yaml这样万一改坏了能快速恢复。另外还要记录一下当前节点数和路由状态方便后面对比验证。3.2 修改IPPool启用IPIP模式Calico的IPPool支持在线热更新不需要重启任何组件。直接使用kubectl patch或kubectl edit修改ipipMode即可。我推荐用patch简洁且易于追踪变更kubectl patch ippool default-ipv4-ippool --typemerge -p {spec:{ipipMode:CrossSubnet}}改成Always的话就把CrossSubnet替换成Always。注意不能拼错Calico对字段值校验很严格拼错会直接报错。修改完成后Calico的Felix会自动为每个节点生成tunl0接口。这个接口就是IPIP隧道所用的设备。可以用ip命令确认ip addr show tunl0正常的话会显示一个状态为UNKNOWN的接口inet地址一般是本节点的物理IP或者显示为169.254.0.1之类的Link-Local地址具体取决于内核版本和Calico版本。只要tunl0存在就说明IPIP链路已被Felix拉起。接下来可以看下节点上的路由表ip route show proto bird你会看到默认路由表格里多出一些带有tunl0出口的路由条目目标网段指向其他子网内的Pod CIDR。这类路由就是Calico通过BGP宣告后由本机内核写入的IPIP路由。3.3 验证隧道接口与连通性配置完不能只看接口真正的验证方式是跑业务流量。我的习惯是先做一个最小化的跨子网连通性测试。从集群里挑两个节点一个在子网A一个在子网B分别记录它们的Pod网段。然后创建一个临时的测试Podkubectl run test-a --imagebusybox --rm -it --restartNever -- sleep 3600另一个节点上也创建类似Pod然后在其中一个Pod里ping对端Pod的IPping -c 3 对端PodIP如果通了基本可以确认IPIP链路正常工作。但我这里要提醒一句ping通不代表大包也通。常见的情况是MTU没对齐64字节的ping能过但一旦带大payload、或者访问HTTP页面时就会发现连接超时或内容下载不下来。所以验证时建议加上MTU测试ping -M do -s 1472 -c 3 对端PodIP-s 1472是因为IPIP封装会额外增加20字节头部如果物理网卡MTU是1500那IPIP隧道内层报文的最大可用payload就是1500减去20字节IP头、再减去实际IP头大小通常是1472。这个值能通说明隧道MTU链路基本没问题如果这个值超时而默认ping能通那基本就是MTU问题需要调整Pod网卡或物理网卡的MTU。3.4 针对特定业务配置混合模式默认的IPPool热更新适用于大多数场景。但在一些更精细的架构里你可能不想让所有Pod都走IPIP而是只想让部分业务跨子网时走隧道。这时可以通过创建额外的IPPool来实现。比如集群已有IPPool网段是10.244.0.0/16其中一块子网10.244.16.0/20专门给需要跨子网的业务使用可以新建一个IPPoolkubectl create -f - EOF apiVersion: projectcalico.org/v3 kind: IPPool metadata: name: high-traffic-ipip-pool spec: cidr: 10.244.16.0/20 ipipMode: Always natOutgoing: true EOF然后让对应命名空间下的Pod通过nodeSelector或者Pod的IP分配策略落到这个池子里。具体做法是在Deployment里指定pod.spec.nodeSelector同时让Calico根据节点标签为该节点分配该IPPool的地址。不过这个玩法坑也不少比如IPPool与节点亲和性的关系、多个IPPool的地址冲突问题需要你对IPAM机制有一定了解后再去尝试。我更推荐的做法是先用默认IPPool开CrossSubnet等业务样式稳定后再考虑要不要为特定业务拆分IPPool。一上来就搞混合模式很容易在排查问题时多了一层干扰。4. 抓包实测看IPIP报文到底长啥样理论说再多不如亲眼看一下报文结构。我每次在新的集群上调试网络都习惯用tcpdump抓一次包确认数据确实按预期封装了。这个方法也可以用来验证IPIP模式是否真的生效。在目标节点上执行tcpdump -i eth0 -n -v host 源节点物理IP and host 目标节点物理IP and proto 4proto 4指的是IP-in-IP协议也就是IPIP使用的协议号。如果你在物理网卡上抓到了这类报文说明IPIP封装已经生效。如果想看完整报文内容可以加-c参数限制包数tcpdump -i eth0 -n -v -c 5 host 对端节点IP and proto 4抓包输出中你会看到类似这样的字段IP (tos 0x0, ttl 63, id 0, offset 0, flags [DF], proto IPIP (4), length 68) 10.0.0.1 10.0.0.2: IP (tos 0x0, ttl 62, id 0, offset 0, flags [DF], proto ICMP (1), length 48) 10.244.1.2 10.244.2.3: ICMP echo request, id 1, seq 1, length 28外层是节点IP 10.0.0.1到10.0.0.2内层是Pod IP 10.244.1.2到10.244.2.3。看到这个嵌套结构毫无疑问IPIP隧道已经真实生效了。如果抓包时发现只有外层报文而没有内层或者干脆没有proto 4的包多半是路由表没生效或者Felix没有生成对应的tunl0路由。这时回到tunl0接口和路由表检查比继续抓包更高效。这里我补充一个经验在云环境里如果安全组或网络ACL没有放行协议号4IPIP报文会被云平台直接丢弃表现就是跨子网Pod不通但节点物理IP之间能互相ping通。遇到这种情况不要一味怀疑Calico配置先去云控制台检查安全组规则是否放行了IP-in-IP流量。有些云平台的安全组根本不提供这个选项那就只能在IPIP和VXLAN之间做个抉择。5. 常见问题与排查技巧实录5.1 问题速查表我把配置和运维IPIP时比较常见的几类问题整理成了速查表方便你遇到问题时能快速对号入座现象可能原因排查/解决办法跨子网Pod完全不通IPIP未启用、路由未生成、协议4被安全组拦截检查IPPool的ipipMode、tunl0接口与路由表抓包看proto 4核对安全组ping通但HTTP超时MTU不一致大包被丢弃调整物理网卡或Pod网卡MTU隧道建议设为1480同子网通信也走IPIP延迟偏高IPIPMode写成Always改成CrossSubnet让同子网走纯BGPtunl0接口存在但路由里没有跨子网路由BGP会话没建立或Felix状态异常检查calico-node日志、BGP Peer状态、节点Network配置启用IPIP后物理网络中出现大量未知协议流量IPIP本质就是协议4流量安全审计可能不认识在监控侧放行协议号4或改用VXLANUDP 4789便于审计跨子网时通同子网时不通反向路由检查或rp_filter问题检查节点的rp_filter设置必要时置为2并使用Calico管控路由5.2 三个容易踩的坑先说要命的一个坑MTU对齐。Calico默认情况下会把Pod网卡的MTU设置为1440比物理网卡的1500小60字节这个设计本来就是为了容纳VXLAN50字节和IPIP20字节的封装头。但有些人为了提升性能会手动把物理网卡MTU改成9000巨帧却忘了调整Calico的MTU配置导致Pod间的报文一到封装环节就出现分片问题。分片在大多数时候表现不明显因为小包能过但大包或者批量数据传输时就非常难受。我的处理方法是物理网卡MTU是多少Calico的MTU就设置为物理MTU减20IPIP或减50VXLAN不要偷懒。第二个坑是安全组和防火墙把协议号4给忽略了。很多云平台的管理界面只提供TCP/UDP/ICMP的规则想要放行IPIP这种IP层协议得通过CLI或者特定API去操作。我见过有同事在配置好Calico IPIP后业务流量始终不通排查了一整天最后发现是云安全组默认丢弃了非TCP/UDP/ICMP的协议。建议在更换网络模式前先确认平台是否支持IP-in-IP协议流量放行。第三个坑是BGP和IPIP同时启用时的路由风暴风险。Calico在IPIP模式下依然会保留BGP路由宣告如果节点间的BGP Peer配置有误比如节点A宣告了一条跨子网路由给节点B节点B又宣告给了节点C而C和B恰好在同一子网就可能出现路由优先级不一致的问题。表现是流量震荡、时通时断。排查时建议先用calicoctl node status或者calicoctl bird status看看BGP会话是否全部Established然后再看路由表是否有多条等价路由指向同一个目标网段。我自己排查这类问题时还有一个比较顺手的方法逐节点查看calico-node日志。在kubectl logs里搜“Failed to apply”或者“error”关键字能比较快定位Felix应用路由失败的原因。另外calicoctl也很重要像查看IPPool配置、节点BGP状态、Felix配置等操作用命令行比kubectl更直观calicoctl get ippool -o wide calicoctl node status5.3 切换模式时的一个可靠操作顺序如果你已经从纯BGP切换到IPIP发现效果不好想回退建议按这个顺序来避免出现中间状态导致集群网络短暂全断先更新IPPool的ipipMode回原来的值。等待2到3分钟让Felix重新计算路由并收敛。用一个非关键业务Pod做连通性验证确认路由正常。确认没有问题后再批量发布业务流量。千万不要同时修改多个IPPool也不建议在改动IPPool的同一时间段里去重启calico-node。我踩过一次这样的坑因为内存泄漏想重启calico-node释放内存结果正好赶上改IPPool两个操作叠加导致大量节点上的路由表刷新失败整个集群的跨节点通信瘫痪了将近五分钟。虽然不是不可恢复但在生产环境里那五分钟非常煎熬。从那以后我给自己定了一个规矩网络模式的变更永远是单线程操作一次只做一个变量。一点个人体会Calico IPIP这个东西初看只是一个简单的封装开关但真正落地时要考虑的因素远比参数本身多。它牵扯到你对底层网络拓扑的理解、对节点间路由可达性判断、对MTU和安全组的熟悉程度甚至还有对云平台限制的了解。我自己在经历过一次跨子网集群的IPIP配置之后最大的体会是不要迷信任何一种网络模式是银弹。纯BGP有性能优势但前提是底层网络配合VXLAN功能完善但封装开销和配置复杂度都不低IPIP刚好站在两者之间属于那种“用得好很顺手用不好也容易埋坑”的方案。关键还是得根据自己集群的实际拓扑把节点分布、路由约束、业务流量类型这些信息摸清楚再去做选型和配置。如果你正在为跨子网Pod通信发愁可以按本文的步骤先查看IPPool状态试着把ipipMode改成CrossSubnet再用抓包验证一次。这个过程花不了多少时间但它能让你对Calico的数据面有一个远比文档描述更真切的感知。
返回列表