尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Calico IPIP模式详解:原理、配置与故障排查实战

Calico IPIP模式详解:原理、配置与故障排查实战 IPIP 模式说实话是我在维护 Kubernetes 集群网络时觉得最“省心”但也是最容易被忽视的一种工作模式。很多朋友一开始接触 Calico默认装完就在用甚至没留意过 Pod 之间跨节点通信的流量到底是怎么走的。等哪一天底层网络架构调整、节点跨网段了或者性能突然出现瓶颈才回头翻文档发现 IPIP 里面的门道比想象中多。这篇文章不打算做成文档翻译而是结合我平时排查问题、部署集群的实际经验把 Calico 的 IPIP 模式从头到尾拆一遍。你会搞清楚它到底封装了什么、为什么需要它、什么时候千万别用它、以及如何对照着自己的环境一步步配置和验证。对了连如何下载指定版本的 Calico 组件这种容易卡壳的小问题我也会一并写清楚。1. Calico 与 IPIP先搞清楚这套网络方案在做什么1.1 Calico 的核心思路三层路由而不是二层大二层理解 IPIP 之前必须先理解 Calico 为什么是今天这个样子。Calico 和 Flannel 的 VXLAN 模式、Cilium 的 Overlay 方案最大的不同在于它的根基是BGP 路由协议。它假设你的底层网络——无论是物理交换机、云上 VPC 还是机房路由器——是支持动态路由或者可以手动加静态路由的。在这种设计下每一个 Kubernetes 节点都被当作一个“路由器”。节点上的 Pod IP 段通常是一个 /26 的网段会通过 BGP 协议告诉整个网络里的其他节点“嗨这个网段的下一跳是我”。这样一来Pod 访问 Pod 的时候数据包其实是按照正常的三层 IP 路由规则在走从 Node A 发到 Node B再由 Node B 转发给上面的 Pod。整个过程没有隧道封装协议栈开销最小这也是为什么 Calico 在很多性能测试中表现优秀。但是这套“纯三层”的方案有一个硬前提所有节点必须在同一个二层网络内或者至少底层网络设备愿意接收并转发节点之间的路由条目。如果你把节点分布在多个机房、多个 VPC或者你用的是某些不支持动态路由的云平台节点之间的 BGP 路由根本没法建立这时候 Pod 跨节点通信就断了。为了在“网络设备不可控”的环境里也能跑通Calico 才提供了 IPIP 这种 Overlay 隧道模式作为兜底方案。1.2 IPIP 到底封装了什么一个包变成两个包IPIP 全称是 IP in IP标准定义在 RFC 2003。它做的事情非常朴素把你原本要发送的 IP 数据包原封不动地塞进另一个 IP 数据包的 Payload 里。这个外层 IP 头的源地址是当前节点的物理网卡 IP目的地址是目的节点的物理网卡 IP而内层那个 IP 头才是真正的 Pod IP 到 Pod IP 的通信。我打个比方你就懂了。这就像寄快递你给朋友寄一箱书里面包的收货人地址是“北京朝阳区某小区某栋”但快递公司不会直接写这个地址而是先在外包装上写“北京朝阳区某快递分拨中心”等包裹到了分拨中心再根据内层地址送去具体楼栋。在 IPIP 模式下集群节点充当了这些“分拨中心”外层 IP 负责把包送达正确的机器内层 IP 再负责在机器内部找到正确的 Pod。从数据包结构上看原始报文经过 IPIP 封装后总长度会增加20 字节iptunnel 头不计算外层 IP 头的可选字段。这意味着你的 Pod 内网卡 MTU 必须相应调小否则在物理链路 MTU 被限制在 1500 的环境下一旦数据包超过 1480就会出现分片或者直接丢包。很多人第一次配置 IPIP 后遇到 SSH 卡顿、HTTP 大包失败十有八九是 MTU 没做对应的调整。2. IPIP 的适用场景与选型对比该用的时候不犹豫不该用的时候别硬上2.1 三种模式的横向对比BGP 原生、IPIP、VXLANCalico 中除了 IPIP还有纯 BGP 和 VXLAN 两种主要的数据面模式。选哪个取决于你的网络环境、性能诉求和运维成本。我用下面这个表格帮你快速建立整体认知模式是否 Overlay额外协议开销底层要求适合场景运维复杂度BGP 原生否0 字节二层可达支持 BGP 路由自建机房网络设备可控中等需管理 BGP 邻居IPIP是20 字节三层可达允许 IP 协议号 4跨网段、路由不可控但不想上 VXLAN低VXLAN是50 字节UDP VXLAN 头三层可达放通 UDP 4789云平台或安全限制较严格的环境低从性能角度看纯 BGP 模式的转发路径最短基本就是内核路由转发效率极高。IPIP 虽然加了一层封装但由于封装和解封装发生在数据包出节点和进节点的瞬间且没有经过用户态协议栈不像 VXLAN 在某些实现下需要更复杂的 UDP 处理所以实际损耗很小。一般来说IPIP 模式相对原生 BGP吞吐量损失在 5% 到 10% 之间具体取决于节点 CPU 主频和内核版本VXLAN 因为涉及 UDP 封装资源开销通常会比 IPIP 更高一些。2.2 你需要 IPIP 的四种典型信号结合我自己的实践经验出现下面几种情况时你就应该认真考虑启用 IPIP集群节点跨多个三层网段。比如一部分节点在 10.0.1.0/24一部分在 10.0.2.0/24由于网段之间被路由器隔离纯 BGP 无法直接传递路由而 IPIP 的隧道可以跨越三层网络建立通信。你无法在物理网络设备上配置路由或 BGP。很多云厂商的交换机、负载均衡器不开放配置权限你不可能手动加一条“某个 Pod 网段下一跳指向某台云主机”的路由。用 IPIP 后数据包目的地是节点物理 IP底层网络只需要转发普通的单播包即可。节点间网络策略、防火墙规则非常复杂你希望把 Pod 网络的通信隐藏在一个简单的“节点到节点的隧道”里从而减少对底层防火墙策略的依赖。你暂时不想引入 VXLAN 的额外负担又需要 Overlay 的灵活性。IPIP 是两者之间的一个折中方案配置简单开销也比 VXLAN 小。2.3 千万别用 IPIP 的场景IPIP 不是银弹。它把大量数据包封装到 IP 协议号 4 里面问题也随之而来云平台安全组不支持或禁止 IP 协议 4。不少公有云的网络安全组规则只放行 TCP、UDP、ICMP对这种“裸 IP 封装”会比较难处理甚至安全审计会将其判定为异常流量。如果你在云上遇到这种限制老老实实切换成 VXLANUDP 4789 端口通常可以放行别和云平台死磕。底层网络 MTU 已经很小。比如你走的是某些隧道 Overlay 底链底层本身就有 1400 的 MTU再叠加 IPIP 的 20 字节留给 Pod 的 MTU 可能只剩 1380会导致很多依赖大包的应用出现诡异问题。你追求极致的网络性能。虽然 IPIP 性能损耗不大但毕竟是 Overlay。如果你的业务是高频交易、计算密集型的网络转发场景优先使用 BGP 原生模式别把时间浪费在排查封装带来的抖动上。3. 动手开启 IPIP 模式一步一步配置与验证3.1 理解 Calico 安装包里的关键参数Calico 安装方式比较多早期用calico.yaml一把梭后来官方推荐用 Helm 或者 Operator。无论哪种方式核心配置文件里都要关注环境变量CALICO_IPV4POOL_IPIP。它有三个可选值Always所有跨节点的 Pod 流量都走 IPIP 封装。CrossSubnet只有跨网段的 Pod 流量才走 IPIP同网段内仍然走 BGP 原生路由。Never完全禁止 IPIP只用 BGP。CrossSubnet是我个人强烈推荐的默认选项。它兼顾了性能和适应性同一个二层网络内的流量不封装效率最高一旦遇到跨网段这种“底层网络不可控”的情况自动切换成隧道保证连通性。如果你不确定自己的网络环境直接用CrossSubnet一般不会踩坑。在裸机直接用 YAML 安装的时候你下载的calico.yaml里会包含一段类似这样的配置记得先检查再应用- name: CALICO_IPV4POOL_IPIP value: Always如果是用 Helm 安装对应的参数通常是ipPool.ipIpMode。以我的实践经验用 Helm 管理的 Calico 更利于后续统一升级建议新项目直接用 Helm。3.2 运行时切换 IPIP 模式不动节点 NetConf只改 IPPool很多人误以为 IPIP 模式在安装后就定死了想改只能重新安装。其实不然。Calico 的 IPIP 模式是绑定在 IPPool 对象上的你可以直接动态修改。查看当前的 IPPoolkubectl get ippool default-ipv4-ippool -o yaml输出里你能看到ipipMode字段。要改成Always执行kubectl patch ippool default-ipv4-ippool --type merge -p {spec: {ipipMode: Always}}如果你是用calicoctl命令行的calicoctl patch ippool default-ipv4-ippool -p {spec:{ipipMode:Always}}改完之后Calico 的 felix 组件会自动把新的模式下发到各个节点大概几秒钟到十几秒钟生效不需要重启节点。你只需要在节点上看路由表确认tunl0网卡和相关的路由规则已经出现即可。3.3 验证 IPIP 是否真的生效比看配置更有用的手段配置只是第一步验证才是关键。这里我总结了三层验证手段从轻到重快速判断 IPIP 是否按预期工作。第一看路由表。在任意节点执行ip route show如果 IPIP 生效你大概率能看到类似下面的路由项10.244.1.0/24 via 192.168.1.101 dev tunl0 proto bird onlink 10.244.2.0/24 via 192.168.1.102 dev tunl0 proto bird onlink注意那个dev tunl0它表明这个网段的路由是走 IPIP 隧道的。如果显示的是dev eth0或者dev ens192说明走的是 BGP 原生路由。第二看隧道接口。执行ip link show tunl0正常情况下应该能看到tunl0状态是UP并且带有tunnel mode ipip的标识。注意一些内核版本中tunl0如果没有任何流量状态可能是UNKNOWN只要链路没有被 down 掉就属于正常。第三也是最直接的验证——抓包。在目的节点上抓取流入的 IPIP 报文tcpdump -i eth0 -n proto 4当你在另一台机器上 ping 某个 Pod IP 时只要能抓到IP 192.168.1.100 192.168.1.101: IP 10.244.1.5 10.244.2.6: ICMP echo request说明 IPIP 封装正在正常工作。注意这里外层是节点 IP内层才是 Pod IP。4. 版本选择与下载指定版本 Calico别再被困在 latest 上了4.1 为什么明明配置正确却因为版本差异踩坑Calico 的功能迭代挺快的不同大版本之间IPIP 的默认值、配置 API 版本比如projectcalico.org/v3升级到后面的版本、甚至 YAML 里的字段结构都可能发生变化。我见过太多人从网上复制了一份老旧的calico.yaml装出来的版本是老古董配置语法和现在的文档对不上折腾老半天。就拿 API 版本来说较早的 Calico v3.8 之前配置 IPPool 用的 CRD 是crd.projectcalico.org/v1后来升级成projectcalico.org/v3。如果你下载的calico.yaml和控制器的 CRD 版本不匹配应用之后会直接报error validating data: unknown field ipipMode这个报错看得人头皮发麻。所以锁定指定版本再安装是避免这类低级问题的第一步。4.2 如何稳定、干净地下载指定版本 Calico manifests最可靠的方法是从 GitHub 官方 releases 页面获取。Calico 的发布页面地址是github.com/projectcalico/calico/releases。每个 release 版本下会列出对应的版本号比如v3.28.1、v3.27.2。下载企业版或标准版的方式略有差异。标准版直接使用原生 YAML 文件即可在任何一个能访问 GitHub 的环境上执行wget https://raw.githubusercontent.com/projectcalico/calico/v3.27.2/manifests/calico.yaml注意 URL 中的v3.27.2是版本 tag务必与你查看 releases 时看到的版本号保持一致。下载后先grep image:看一下里面的镜像版本是否正确再kubectl apply -f calico.yaml。如果你是我的同类习惯用 Helm 管 Kubernetes 应用那可以通过 Helm 仓库下载。Calico 官方提供了两个主要 Helm chart一个是tigera-operator用于 Operator 方式安装另一个是更传统的calico可以直接配置ipPool.ipIpMode等参数。以安装 v3.27.2 为例helm repo add projectcalico https://projectcalico.docs.tigera.io/charts helm pull projectcalico/tigera-operator --version v3.27.2 helm install calico tigera-operator.tgz --namespace tigera-operator --create-namespace4.3 镜像版本的一致性检查比你想象中重要无论用 YAML 还是 Helm安装完成后第一时间要检查镜像版本。Calico 分为多个组件镜像包括calico/node、calico/cni、calico/kube-controllers、calico/apiserver如果用 API Server 的话。这些组件的镜像 tag 必须一致否则容易出问题。执行kubectl get daemonset -n kube-system | grep calico kubectl get deployment -n kube-system | grep calico然后看容器镜像里的 tag。如果某些镜像 tag 不一致要么是你手动改乱了要么是你下载的 YAML 经过了别人二次加工。这种情况需要直接从官方源重新拉取对应版本别指望它能正常运行。另外如果你的节点在国内、拉取 Docker Hub 镜像很慢请优先考虑配置镜像加速器或者在企业内网自建镜像仓库。千万别为了图快把某个镜像 tag 替换成 latest那样你会失去版本一致性以后排查问题极其痛苦。5. 从配置到运维IPIP 模式下的 MTU 设计与故障排查实录5.1 MTU 的联动调整没有捷径可走开启 IPIP 模式后节点的物理网卡 MTU 和 Pod 虚拟网卡 MTU 之间存在 20 字节的差值。假如你的物理网卡 MTU 是标准的 1500那 Pod 内的eth0MTU 应设置为 1480如果物理链路有额外封装比如底层是 VLAN 或者 VXLAN还得再往小算。在 Calico 中可以在安装时通过环境变量FELIX_IPINIPMTU来指定 IPIP 隧道的 MTU 值默认它会在物理网卡 MTU 基础上自动减去 20。但如果你用了hostNetwork模式的 Pod或者某些特殊场景下希望 Pod 使用更大 MTU需要手动调整成你期望的值。实际调试时用下面的命令在 Pod 内验证 MTU 是否合理kubectl exec -it pod-name -- ip link show eth0然后从 Pod 内 ping 集群外某个地址并加上-M do -s 1472参数1472 是 IP 层最大负载不会触发分片kubectl exec -it pod-name -- ping -M do -s 1472 8.8.8.8如果这条命令通了说明 MTU 设置基本够用如果ping: local error: Message too long或者超时就需要调小 MTU。5.2 高频故障一IPIP 隧道建立成功但 ping 不通其他节点 Pod这个问题的出现频率极高而且坑得很隐蔽。你按前面说的步骤配置了ipipMode: Alwaystunl0状态也是 UP路由表也正常但跨节点 Pod 就是 ping 不通。我先说排查思路先在目的节点上抓包看有没有 IPIP 类型的流量进来。如果在目的节点的物理网卡上抓不到proto 4的任何数据包说明数据包在中间被丢弃了。常见原因之一节点的安全组或防火墙没有放行 IP 协议号 4。Linux 的 iptables 和云安全组只放行 TCP/UDP/ICMP 很常见而 IPIP 封装后的外层协议既不是 TCP 也不是 UDP容易被默认策略丢掉。排查方法很简单在目的节点上执行iptables -L INPUT -n --line-numbers看有没有显式放行proto 4的规则。如果没有加上iptables -I INPUT -p 4 -j ACCEPT针对常见防火墙你还需要检查 firewalld 是否放行 ipip 协议或者直接在云控制台的安全组入方向放行协议类型“IPIP”。5.3 高频故障二CrossSubnet 模式下同网段也走了 IPIPCrossSubnet的初衷是只对跨子网的流量进行封装。但如果你配置完发现同网段内的节点通信竟然也走了tunl0那是因为你节点上的路由信息缺失或者 BGP Peer 没建好Calico 判断对方“不在同一子网”。这时候需要检查节点的 IP 和子网掩码确认 Calico 是否正确识别节点所在的子网。Calico 是以节点的kube-node名称来映射 IP 的如果节点 IP 多次变动比如 DHCP会导致路由配置错乱。一个更稳妥的做法是为节点显式指定IPIPIPIP隧道不会再对同网段流量生效# 查看节点信息是否准确 kubectl get nodes -o wide # 修改 IPPool 为 CrossSubnet如果之前是 Always kubectl patch ippool default-ipv4-ippool --type merge -p {spec: {ipipMode: CrossSubnet}}改完等待几秒再ip route show同网段节点的路由就会从tunl0切换回物理网卡。5.4 高频故障三IPIP 模式下 Service 访问异常Service 的流量转发依靠 kube-proxy 的 iptables 规则或者 IPVS。如果 ClusterIP 通但 Pod IP 不通说明问题出在 Pod 网络如果 Pod IP 通但 ClusterIP 不通多半是 kube-proxy 或 Service 后端选择的问题。在 IPIP 模式下我遇到过一个很少见但很难查的情况节点开启了rp_filter反向路径过滤当数据包从tunl0口进来时内核检测到回包从物理网卡出去源地址“不在正确接口”于是把包丢弃了。解决办法是调整rp_filtersysctl -w net.ipv4.conf.all.rp_filter0 sysctl -w net.ipv4.conf.default.rp_filter0为了让这个配置永久生效在/etc/sysctl.d/99-calico.conf里写入上面两行并执行sysctl --system。这个坑在新部署、多网卡的环境里尤其隐蔽值得刻进 DNA。5.5 谈谈性能调优与工具链建议IPIP 使得跨节点通信多了一层内核封装CPU 消耗主要集中在内核协议栈。遇到性能瓶颈时先确认是不是封装带来的开销再决定是否调优。方法之一是开启网卡gro和gso一般默认就是开启的如果关闭了可以打开ethtool -K eth0 gro on gso on另外排查网络问题时我一直建议把tcpdump、ip route、calicoctl node status这三个工具配合使用。calicoctl node status可以查看 BGP Peer 状态比如是否 Establishedcalicoctl node status如果 BGP 状态不是 EstablishedIPIP 隧道即使建立了也可能因为缺少对端路由而通不了。这又是一个容易被忽视的细节——IPIP 需要两端节点都知道对端的隧道路由而 BGP 正是承担这个任务的。6. 写在最后的一次实战回忆记得有次帮一个客户排查跨地域机房集群的间歇性网络超时一开始大家都怀疑是 IPIP 隧道不稳定反复删除重建隧道折腾了两天没结果。后来我直接在两个节点之间用iperf3打流发现吞吐量一路下滑可 CPU 占用却不高最后才发现是底层物理链路 MTU 被配成了 1450而 IPIP 没感知到还在按 1500 减 20 的节奏跑导致数据包分片严重。从那以后我养成了一个习惯每到一个新环境第一件事就是确认整条物理链路的端到端 MTU而不是只信ip link show那一层。IPIP 就像给数据包穿上了一件厚重的外套你的外套尺码必须和里面那件衣服匹配否则穿上去走两步就崩线。希望你配置 Calico 的时候能少走这些弯路。
返回列表