news 2026/10/15 19:04:01

给 K8s 换心脏:把 CNI 从 Calico/Flannel 迁到 Cilium 的完整流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
给 K8s 换心脏:把 CNI 从 Calico/Flannel 迁到 Cilium 的完整流程

给 K8s 换心脏:把 CNI 从 Calico/Flannel 迁到 Cilium 的完整流程

【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium

Kubernetes 集群的网络插件(CNI)决定了 Pod 之间、Pod 与外部世界之间所有流量的走向,某种意义上它就是集群的"心脏"。很多团队最初选择 Calico 或 Flannel 作为起步方案,但随着集群规模扩大、微服务数量增长,kube-proxy + iptables 的性能瓶颈、网络策略的粗粒度、排障时"两眼一抹黑"的可观测性缺失,会逐渐变成刺痛运维的顽疾。Cilium 正是冲着这些问题来的——它用 eBPF 把数据面下沉到内核,绕过整条 iptables 链,还能在数据面上直接实现网络策略、负载均衡与全栈可观测性。

但"换心脏"最让人恐惧的从来不是新技术本身,而是迁移过程中的停机与未知风险。好消息是,Cilium 官方在仓库中维护了一份完整的迁移方案(见 迁移文档),支持在不重启整个集群、不中断存量流量的前提下,按节点逐个滚动替换 CNI。本文以这份官方流程为主线,拆解从现状盘点、滚动替换到策略与可观测性对齐的完整路径,并给出可直接落地的 Helm 配置与命令行步骤。

一、迁移前的现状盘点与风险识别

1.1 先想清楚:为什么值得迁移

在动手之前,先确认迁移的收益是真实的。Cilium 的核心差异在于数据面:传统 CNI 的转发路径通常要穿过 iptables/Netfilter 层,而 Cilium 将 datapath 逻辑编译为 eBPF 程序直接挂载到内核网络栈,绕过了 iptables。仓库的基准测试文档对此有直接的量化证据(benchmark.rst):在单流 TCP 吞吐测试中,eBPF 方案甚至可以超过裸机节点间直连的基线——因为 eBPF 旁路了节点上仍然要穿越 iptables 的默认路径,尽管它额外做了容器命名空间转发和策略执行。

除此之外,迁移还带来三笔"隐性收益":

  • 替代 kube-proxy:Cilium 的 eBPF 负载均衡可以在数据面完成 Service 转发,集群可以逐步卸载 kube-proxy,减少一层 iptables 维护成本;
  • 策略内置:NetworkPolicy 与 CiliumNetworkPolicy 直接在数据面执行,无需依赖独立的策略代理;
  • 可观测性:Hubble 在内核数据面采集流量元数据,服务依赖图、TCP/DNS/HTTP 指标开箱即用。

1.2 盘点现状:四件事必须提前确认

迁移文档(k8s-install-migration.rst)明确指出,热迁移(live migration)有几个硬性前提,动手前必须逐项核对:

检查项要求说明
Pod CIDR为 Cilium 分配一套全新的、未被占用的 Cluster CIDR新旧 CNI 必须使用不同 IP 段,Linux 路由表才能自动隔离两套网络的流量
封装协议/端口与现有 CNI 使用不同的封装协议或端口若旧网络用 VXLAN,Cilium 要么改用 GENEVE,要么用不同的 VXLAN 端口
IPAM 模式使用 cluster-pool 模式这是官方强烈推荐的分配器,能最大程度保证无 IP 冲突
旧 CNI 类型必须基于 Linux 路由栈(Flannel、Calico、AWS-CNI 均可)BGP 路由方案暂不支持迁移

1.3 风险清单:哪些场景"此路不通"

官方文档明确列出了当前未测试/不支持的迁移场景,提前知晓可以避免踩坑:

  • BGP 路由方案:基于 BGP 的 CNI 尚未纳入迁移测试;
  • IP 协议族切换:例如从 IPv4 迁移到 IPv6 双栈;
  • 从 chained 模式(链式 CNI)迁移;
  • 已有 NetworkPolicy 提供方:迁移期间 Cilium 的策略执行会被禁用,否则非 Cilium Pod 的流量可能被错误丢弃。若集群已有策略提供方,官方建议先临时删除所有 NetworkPolicy。

另外需要特别强调:迁移过程高度依赖现有集群的具体配置,文档给出的警示是——强烈建议先在测试/实验集群上完整演练一遍(可用 Kind 复现,配置见 kind-config.yaml),再在生产环境执行。这也符合任何心脏手术都先做"体外循环演练"的原则。

二、滚动替换 CNI:数据面切换的分步实操

2.1 整体策略:双 Overlay 共存,逐节点接管

热迁移的核心思想是双 Overlay 共存:Cilium 先以"secondary mode"安装——只建立自己的 Overlay 网络、暂不接管任何 Pod 的 CNI 配置;随后通过CiliumNodeConfig按节点逐个"接管"CNI 配置。同一节点上的 Pod 只能附着于一个网络,但在迁移期间,Cilium 管理的 Pod 与旧 CNI 管理的 Pod可以互相访问——前提就是前面说的"独立 IP 段 + 独立封装端口",由 Linux 路由表自动完成流量分离。

整个流程官方总结为四步(k8s-install-migration.rst):

  1. 以"secondary"模式安装 Cilium(建立 Overlay,但不管理任何 Pod);
  2. 逐节点执行 cordon → drain → 迁移 → reboot;
  3. 全部节点迁移完成后,移除旧网络插件;
  4. (可选)再次滚动重启节点,清理 iptables 规则与残留网络接口等遗留资源。

2.2 第一阶段:以"影子模式"安装 Cilium

先准备一套values-migration.yaml,这份配置是迁移的关键,每一行都有明确目的:

operator: unmanagedPodWatcher: restart: false # 迁移期间不要自动重启未被 Cilium 管理的 Pod routingMode: tunnel tunnelProtocol: vxlan tunnelPort: 8473 # 与旧 CNI 使用不同的 VXLAN 端口 cni: customConf: true # 不安装 CNI 配置文件(暂不接管) uninstall: false # 关闭时不要删除 CNI 配置 ipam: mode: "cluster-pool" operator: clusterPoolIPv4PodCIDRList: ["10.245.0.0/16"] # 全新且未被占用的网段 policyEnforcementMode: "never" # 迁移期间禁用策略执行 bpf: hostLegacyRouting: true # 允许 Cilium 与现有 Overlay 之间的路由互通

接下来生成初始配置并安装。先用 cilium-cli 自动探测集群的典型 Helm 值(只生成清单、不直接应用),再通过 Helm 安装:

$ cilium install --version <版本号> --values values-migration.yaml --dry-run-helm-values > values-initial.yaml $ helm repo add cilium https://helm.cilium.io/ $ helm install cilium cilium/cilium --namespace kube-system --values values-initial.yaml

安装完成后验证 Cilium 已建立 Overlay 但尚未接管任何 Pod:

$ cilium status --wait ... Cluster Pods: 0/3 managed by Cilium

0/3 managed by Cilium正是"影子模式"已就绪的信号。

2.3 第二阶段:创建 per-node 接管配置

Cilium 支持按节点粒度覆盖配置,机制是CiliumNodeConfig对象(详见 per-node-config.rst):它由一组defaults配置项和一个nodeSelector标签选择器组成,只有命中标签的节点才会套用这些配置。这个特性最初就是为了渐进式灰度而设计的。

创建如下配置——初始不匹配任何节点,通过后续打标签来逐步放量:

cat <<EOF | kubectl apply --server-side -f - apiVersion: cilium.io/v2 kind: CiliumNodeConfig metadata: namespace: kube-system name: cilium-default spec: nodeSelector: matchLabels: io.cilium.migration/cilium-default: "true" defaults: write-cni-conf-when-ready: /host/etc/cni/net.d/05-cilium.conflist custom-cni-conf: "false" cni-chaining-mode: "none" cni-exclusive: "true" EOF

注意cni-exclusive: "true"——一旦接管,Cilium 将成为该节点的唯一CNI,这与cni-chaining-mode: "none"共同保证不会与旧 CNI 配置产生竞争。

2.4 第三阶段:单节点迁移的七个动作

迁移以单个节点为单位进行,官方明确建议不要先从控制面节点开始。对一个工作节点$NODE,完整流程如下:

① 封锁并(建议)排空节点

$ kubectl cordon $NODE $ kubectl drain --ignore-daemonsets $NODE

排空不是强制的,但不排空的话,节点重启期间 Pod 会经历短暂的连接中断。

② 打标签,触发 CiliumNodeConfig 生效

$ kubectl label node $NODE --overwrite "io.cilium.migration/cilium-default=true"

③ 重启该节点上的 Cilium Agent,让其写入 CNI 配置文件

$ kubectl -n kube-system delete pod --field-selector spec.nodeName=$NODE -l k8s-app=cilium $ kubectl -n kube-system rollout status ds/cilium -w

④ 重启节点,让 PodSandbox 全部重建、由新 CNI 接管:

# Kind 环境示例 $ docker restart $NODE

⑤ 验证迁移成功——检查 Pod IP 是否落在 Cilium 的 CIDR 内、API Server 是否可达:

$ cilium status --wait $ kubectl get -o wide node $NODE $ kubectl -n kube-system run --attach --rm --restart=Never verify-network \ --overrides='{"spec": {"nodeName": "'$NODE'", "tolerations": [{"operator": "Exists"}]}}' \ --image ghcr.io/nicolaka/netshoot:v0.8 -- /bin/bash -c 'ip -br addr && curl -s -k https://$KUBERNETES_SERVICE_HOST/healthz && echo'

⑥ 解除封锁

$ kubectl uncordon $NODE

⑦ 重复以上步骤,直到所有节点迁移完毕。每个节点完成后建议用cilium status确认Cluster Pods的受管数量在持续增长。

2.5 迁移期间为什么"不敢"重启未管理 Pod

这里有一个容易被忽略的细节:影子模式下,operator.unmanagedPodWatcher.restart被显式设为false。这是因为 Cilium Operator 里有一个专门的控制器(源码见 operator/unmanagedpods/controller.go),它会周期性地扫描那些"已存在但未被 Cilium 管理"的 Pod 并自动重启它们——平时这是新装 Cilium 时让存量 Pod 快速"入网"的贴心功能(cilium-cli 安装时输出的♻️ Restarted unmanaged pod ...就来自它)。但在迁移中途,如果让它放开手脚,就会把尚未迁移节点上的 Pod 提前重启,而这些节点还没有写入 Cilium CNI 配置,重启反而会造成无谓的流量中断。迁移期先按住它、迁移完成后重新放开,正是这份配置的用心之处。

三、迁移后的网络策略与可观测性对齐

3.1 配置"转正":从影子模式切换为主 CNI

当cilium status显示集群内所有 Pod 均已被 Cilium 管理后,进入收尾阶段。需要把当初为迁移准备的"临时配置"全部翻转回来:

$ cilium install --version <版本号> --values values-initial.yaml --dry-run-helm-values \ --set operator.unmanagedPodWatcher.restart=true --set cni.customConf=false \ --set policyEnforcementMode=default \ --set bpf.hostLegacyRouting=false > values-final.yaml $ diff values-initial.yaml values-final.yaml

确认差异无误后应用并滚动重启:

$ helm upgrade --namespace kube-system cilium cilium/cilium --values values-final.yaml $ kubectl -n kube-system rollout restart daemonset cilium $ cilium status --wait

然后删除 per-node 配置,让所有节点回归统一默认值:

$ kubectl delete -n kube-system ciliumnodeconfig cilium-default

bpf.hostLegacyRouting从true翻转为false值得单独说明:迁移期间它负责打通 Cilium 与旧 Overlay 之间的路由,是"新旧两套网络并存"的粘合剂;迁移完成后关闭它,可以让 Cilium 走更高效的 eBPF host routing 路径——官方文档提示,这一步会带来每次 Agent 重启时的短暂连接中断,但对网络性能有明显改善,相当于"拆掉临时心脏支架"。

3.2 移除旧 CNI:删插件容易,清理残留难

确认所有 Pod 都在 Cilium 网络中后,才允许删除旧网络插件。但官方文档特别提醒:大多数网络插件会在节点上留下残留资源——iptables 规则、网络接口等。这些残留会在节点下次重启时由系统自动清理。如果希望集群立刻"干净",可以对全集群再做一次滚动重启。

若你的集群还运行着 kube-proxy,并且准备用 Cilium 的 eBPF 负载均衡彻底替代它,可以参考 per-node 文档(per-node-config.rst)中给出的渐进式方案:先用CiliumNodeConfig让 kube-proxy-replacement 只在打了io.cilium.migration/kube-proxy-replacement: true标签的节点上生效,并给 kube-proxy DaemonSet 打上反亲和、将其调度限制在未迁移节点;逐节点验证cilium config get kube-proxy-replacement输出true后,再删掉 kube-proxy DaemonSet。注意前提:必须已配置k8sServiceHost与k8sServicePort,否则 kube-proxy 卸载后 Cilium 将无法访问 API Server。

3.3 策略对齐:从"禁用"到"精细化执行"

迁移期间policyEnforcementMode: "never"是为了避免误伤旧 CNI Pod 的流量,但迁移完成后,策略能力正是这次换芯的重要回报之一。policyEnforcementMode翻转为default后,Cilium 将按需执行策略:

  • 标准 KubernetesNetworkPolicy(L3/L4),与其他 CNI 生态兼容;
  • 更细粒度的CiliumNetworkPolicy,支持 L7 层(HTTP 方法、路径、头字段)策略,例如限制某个 Service 只允许GET /api被特定身份访问。

策略对齐的另一个关键动作是验证:迁移完成后应重新应用此前临时删除的 NetworkPolicy,并用cilium status观察策略执行状态,确认没有因 CNI 切换而产生丢包或拒绝。

3.4 可观测性对齐:让 Hubble 接管"监控心电"

迁移前,集群的流量观测往往依赖抓包或外部工具,被动且侵入。迁移到 Cilium 后,可观测性可以直接从数据面获得——Hubble 在内核 eBPF 层面采集流量,无需侵入应用。启用方式:

$ cilium hubble enable --ui

这条命令背后(源码见 cilium-cli/hubble/hubble.go)会拉起 hubble-relay 与 hubble-ui 组件;UI 则通过端口转发暴露(cilium-cli/hubble/ui.go):

$ cilium hubble ui

Hubble 提供的可观测性维度,恰好能补齐迁移前最缺的三块拼图:

  • 服务依赖图:自动绘制 Pod/Service 之间的实时流量拓扑,回答"谁在访问谁";
  • 协议级指标:TCP、DNS、HTTP 的分类流量与错误率,直接定位慢接口与 DNS 故障;
  • 网络策略视角:Hubble 能展示被策略允许/拒绝的流量分布,迁移后可以直观验证策略是否按预期生效。

对齐完成后,建议用cilium connectivity test做一轮全链路连通性测试(覆盖 Pod-to-Pod、Pod-to-Service、DNS 解析等场景),作为"换心手术"的最终验收。

结语:换心不是冒险,而是可控的手术

从 Calico/Flannel 迁移到 Cilium,本质是一次可编排、可回滚、可验证的滚动手术,而不是推倒重来的大冒险。官方迁移文档提供的关键支撑有三点:双 Overlay 共存让新旧网络在迁移期内"和平共处";CiliumNodeConfig的 per-node 机制让接管粒度精确到单个节点、随时可以暂停;迁移前后的 Helm 值翻转让"影子模式"与"主 CNI 模式"之间的切换有明确的完成信号。

真正值得投入精力的,永远是迁移前的盘点(IP 段隔离、封装端口、策略禁用、实验集群演练)和迁移后的对齐(策略恢复、Hubble 可观测性、kube-proxy 替代、残留清理)。把这两头做扎实,中间按节点的滚动替换,不过是按图索骥的机械动作。而当你看到cilium status显示全部 Pod 受管、Hubble 里流量拓扑清晰呈现的那一刻,会明白这次换心,值。

【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 20:34:56

C# WinForms飞机游戏源码解析:从运行到二次开发

简介&#xff1a;这是一份面向C#初学者与游戏开发入门者的飞行射击小游戏完整源码&#xff0c;以飞机、子弹、敌人等对象为核心&#xff0c;帮助读者在实战中理解游戏运行机制。源码覆盖C#基础语法、面向对象设计、Windows Forms界面绘制、游戏循环、定时器与帧率控制、碰撞检测…

作者头像 李华
网站建设 2026/10/15 15:28:14

嵌入式面试必问:UART、I2C、SPI三大串行协议底层原理与调试实战

上个星期我作为面试官面了一个做嵌入式Linux三年的候选人&#xff0c;前面聊项目都好好的&#xff0c;我问了一句“UART、I2C、SPI&#xff0c;你平时用哪个最多&#xff1f;”对方说I2C。然后我追问“那I2C为什么要开漏&#xff1f;”他愣了一下&#xff0c;说“因为协议规定要…

作者头像 李华
网站建设 2026/10/15 21:47:00

编程论坛关闭启示录:从C语言到PLC,技术交流生态如何重塑

老牌知名编程论坛&#xff0c;彻底倒下了。这句话我盯着屏幕看了很久&#xff0c;心里说不出是什么滋味。我入行那会儿&#xff0c;能在这种论坛上发一个精华帖&#xff0c;比现在发一篇爆文还让人兴奋。这几天后台也有人问我&#xff1a;论坛倒了&#xff0c;学编程的人该怎么…

作者头像 李华
网站建设 2026/10/14 10:42:08

BTCV腹部14器官分割:临床级三维标注与手术导航实践

简介&#xff1a;本资源是面向医学图像分割研究者与AI医疗方向初学者的高质量腹部多器官2D切片数据集&#xff0c;基于权威BTCV&#xff08;Abdominal Multi-Organ Segmentation&#xff09;基准构建&#xff0c;专为CT影像语义分割模型训练、验证与可视化分析提供支持。资源包…

作者头像 李华
网站建设 2026/10/14 20:42:32

Visual Studio 预览版 Agent 模式:把 MCP 配置改到 TaoToken 的完整验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/14 14:32:37

Python编写单元测试代码实例

前言 unittest 是 Python 标准库自带的测试框架&#xff0c;不需要安装任何第三方包。它的设计借鉴了 Java 的 JUnit&#xff0c;所以你会看到 TestCase、setUp、tearDown 这类命名。虽然现在很多人转向 pytest&#xff0c;但 unittest 依然值得学&#xff1a;一是零依赖&#…

作者头像 李华