1. 一段话总结
Cilium 支持从其他 CNI(如Flannel、Calico 等)向自身迁移 K8s 集群,采用节点逐个迁移模式,无需集群整体 outage;
核心通过双覆盖网络(dual overlays) 实现,要求 Cilium 使用独立的 Cluster CIDR(如示例中的10.245.0.0/16)和封装端口(如 VXLAN 的 8473 端口),依赖 Linux 路由表隔离流量,确保迁移中新旧 CNI 下 的 Pod可通信;
迁移流程分为:
- 准备(安装 Cilium 至 “secondary” 模式、创建节点配置)、
- 节点迁移(隔离、排空、打标签、重启 Cilium 与节点、验证)、
- 迁移后(更新 Cilium 配置、删除旧 CNI 等)三阶段,
且迁移期间需禁用 Cilium 的网络策略 enforcement: 如果不禁用,两者立刻就会冲突(实际测试情况)
推荐先在测试集群验证。
一、迁移核心背景与原理
-
CNI 工作基础:kubelet 创建 Pod Sandbox 时,会调用
/etc/cni/net.d/中配置的 CNI 插件,负责 Pod 的 IP 分配、网卡配置及覆盖网络建立,Pod 网络配置生命周期与 Sandbox 一致。 -
传统迁移痛点:直接替换所有节点的 CNI 并重启节点,会导致“未迁移节点”与“已迁移节点”形成两个通信孤岛,Pod 间通信随机中断,直至迁移完全结束。
-
Cilium 迁移核心方案——双覆盖网络(Dual Overlays)
-
原理:Cilium 与现有 CNI 分别使用独立的 IP 段和覆盖网络(协议或端口不同),Linux 路由表自动隔离两类流量,实现迁移中旧 CNI Pod 与 Cilium Pod 的正常通信。
-
优势:支持节点逐个迁移,无需集群整体停机,最大程度减少业务中断。
-
二、迁移前提与限制
| 类别 | 具体内容 | 关键说明 |
|---|---|---|
| 必备要求 | 1. 独立的 Cilium Cluster CIDR 2. 启用 Cluster Pool IPAM 模式 3. 独立的覆盖网络(协议/端口不同) 4. 现有 CNI 基于 Linux 路由栈(如 Flannel、Calico、AWS-CNI) | 1. 示例中 Kind 集群默认 CNI 用10.244.0.0/16,Cilium 选择 10.245.0.0/162. Cluster Pool 模式可避免 IP 冲突,是迁移的强推荐配置 3. 如现有 CNI 用 VXLAN,Cilium 可改用 GENEVE 或VXLAN 非默认端口(示例用 8473) |
| 当前限制 | 1. 不支持 BGP-based 路由 2. 不支持 IP 家族切换(如 IPv4→IPv6) 3. 不支持从 Cilium 链式模式(chained mode)迁移 4. 不支持现有 NetworkPolicy 提供商 | 迁移期间需禁用 Cilium 的 NetworkPolicy 和 CiliumNetworkPolicy enforcement,否则可能误删旧CNI Pod 流量;建议迁移前临时删除所有现有 NetworkPolicy |
| 重要警告 | 迁移依赖现有集群的具体配置,必须先在测试/实验室集群验证,再应用于生产环境 | - |
三、完整迁移流程
(一)准备阶段:部署Cilium至“Secondary”模式
-
(可选)搭建示例环境(Kind+Flannel)
- 创建 Kind 集群配置文件
kind-config.yaml,禁用默认 CNI; - 执行
kind create cluster --config=kind-config.yaml创建集群; - 安装参考 CNI 插件和 Flannel:
kubectl apply -n kube-system --server-side -f https://raw.githubusercontent.com/cilium/cilium/HEAD/examples/misc/migration/install-reference-cni-plugins.yaml、kubectl apply --server-side -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml; - 等待所有节点就绪:
kubectl wait --for=condition=Ready nodes --all。
- 创建 Kind 集群配置文件
-
配置关键参数
-
选择 Cilium 专属资源:确定独立 CIDR(如
10.245.0.0/16)和封装端口(如 VXLAN 8473); -
编写 Helm 配置文件
values-migration.yaml,核心配置如下:-
operator: unmanagedPodWatcher: restart: false # 迁移期间不重启未管理的 Pod routingMode: tunnel # 覆盖网络模式,默认 tunnel tunnelProtocol: vxlan # 覆盖网络协议,默认 VXLAN tunnelPort: 8473 # 自定义 VXLAN 端口,避免与旧 CNI 冲突 cni: customConf: true # 不安装 Cilium CNI 配置文件 uninstall: false # 关闭时不删除 CNI 配置 ipam: mode: "cluster-pool" # 启用 Cluster Pool IPAM operator: clusterPoolIPv4PodCIDRList: ["10.245.0.0/16"] # Cilium专属CIDR policyEnforcementMode: "never" # 禁用策略enforcement bpf: hostLegacyRouting: true # 允许新旧覆盖网络间路由
-
-
-
生成初始配置并安装 Cilium
- 生成初始 Helm 配置:
cilium install --chart-directory ./install/kubernetes/cilium --values values-migration.yaml --dry-run-helm-values > values-initial.yaml; - 添加 Cilium Helm仓 库并安装:
helm repo add cilium https://helm.cilium.io/、helm install cilium cilium/cilium --namespace kube-system --values values-initial.yaml; - 验证安装:
cilium status --wait,此时“Cluster Pods”应显示“0/X managed by Cilium”(无 Pod 由 Cilium 管理)。
- 生成初始 Helm 配置:
-
创建节点级配置(CiliumNodeConfig)
-
配置文件指定节点选择器
io.cilium.migration/cilium-default: "true",初始不应用于任何节点,后续通过打标签控制迁移范围:-
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"
-
-
应用配置:
kubectl apply --server-side -f -(上述配置通过标准输入传入)。
-
(二)节点迁移阶段:逐个迁移目标节点
-
选择并预处理节点
- 选择目标节点(推荐先 worker 节点,如 Kind 集群的
kind-worker):NODE="kind-worker"; - 隔离节点(禁止新 Pod 调度):
kubectl cordon $NODE; - (可选)排空节点(减少 Pod 重启中断):
kubectl drain --ignore-daemonsets $NODE。
- 选择目标节点(推荐先 worker 节点,如 Kind 集群的
-
触发节点 Cilium 迁移
- 为节点打标签(匹配 CiliumNodeConfig 的选择器):
kubectl label node $NODE --overwrite "io.cilium.migration/cilium-default=true"; - 重启节点上的 Cilium Pod(使其加载CNI配置):
kubectl -n kube-system delete pod --field-selector spec.nodeName=$NODE -l k8s-app=cilium; - 等待 Cilium DaemonSet 就绪:
kubectl -n kube-system rollout status ds/cilium -w; - 重启节点( Kind 节点用 Docker 重启):
docker restart $NODE。
- 为节点打标签(匹配 CiliumNodeConfig 的选择器):
-
验证节点迁移结果
-
检查 Cilium 状态:
cilium status --wait,确认目标节点的 Pod 开始由 Cilium 管理; -
检查节点信息:
kubectl get -o wide node $NODE; -
验证 Pod 网络:创建测试 Pod 并检查 IP 归属和 APIServer 连通性:
-
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'
-
-
关键验证点:Pod IP 需在 Cilium CIDR(如
10.245.0.0/16)内,且curl能成功返回APIServer 健康状态。
-
-
恢复节点调度:
kubectl uncordon $NODE,重复上述步骤迁移下一个节点。
(三)迁移后阶段:完成收尾与优化
-
验证整体迁移结果:
cilium status,确认所有节点的 Pod 均由 Cilium 管理。 -
更新 Cilium 配置(启用完整功能)
-
生成最终配置:启用策略 enforcement、允许 Operator 重启未管理 Pod,可选启用 eBPF Host-Routing(提升性能,但会导致短暂中断):
-
cilium install --chart-directory ./install/kubernetes/cilium --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; -
应用配置并重启 Cilium:
helm upgrade --namespace kube-system cilium cilium/cilium --values values-final.yaml、kubectl -n kube-system rollout restart daemonset cilium; -
等待 Cilium 就绪:
cilium status --wait。
-
-
清理旧资源
-
删除 CiliumNodeConfig:
kubectl delete -n kube-system ciliumnodeconfig cilium-default; -
删除旧 CNI 插件(如 Flannel);
-
(可选)滚动重启所有节点:清理旧 CNI 残留的 iptables 规则和网卡(旧资源需节点重启后完全清除)。
-
4. 关键问题
问题1:Cilium 双覆盖网络(Dual Overlays)迁移的核心设计是什么?如何确保迁移中旧 CNI Pod 与Cilium Pod 的通信?
答案:核心设计是让 Cilium 与现有 CNI 分别使用独立的IP段和独立的覆盖网络(协议或端口不同) ,依赖 Linux 路由表自动隔离两类流量,避免 IP 冲突和通信干扰;具体实现需满足两个关键条件:1. Cilium 使用与现有 CNI 完全不同的 Cluster CIDR(如现有用10.244.0.0/16,Cilium 用10.245.0.0/16);2. 覆盖网络不重叠(如现有 CNI 用 VXLAN 默认端口 8472,Cilium 可改用 VXLAN 端口 8473 或 GENEVE 协议);同时需在 Cilium 配置中启用bpf.hostLegacyRouting: true,允许节点层面的路由转发,最终实现迁移期间旧 CNI Pod 与 Cilium Pod 的正常通信。
问题2:迁移期间为何必须禁用 Cilium 的 NetworkPolicy enforcement?迁移完成后如何恢复策略功能?
答案:禁用的原因是迁移期间集群存在旧 CNI Pod 和 Cilium Pod 两类 workload,Cilium 的NetworkPolicy/CiliumNetworkPolicy 规则仅针对 Cilium 管理的 Pod 生效,若不禁用,Cilium 可能误将旧 CNI Pod 的流量判定为“不符合策略”并丢弃,导致通信异常;此外,若集群原有其他 NetworkPolicy 提供商,建议迁移前临时删除所有 NetworkPolicy,避免规则冲突。
恢复步骤:1. 所有节点迁移完成后,生成最终 Helm 配置时设置policyEnforcementMode=default(初始迁移时为never);
2. 通过helm upgrade应用配置,并重启 Cilium DaemonSet(kubectl -n kube-system rollout restart daemonset cilium);
- 等待 Cilium 就绪后,
cilium status确认 “Policy Enforcement” 已恢复为 “default” 模式,此时 Cilium 将正常执行 NetworkPolicy 规则。
问题3:在节点迁移阶段,“排空节点(kubectl drain)”是必需操作吗?如果不执行排空,会对业务产生什么影响?如何验证节点迁移是否成功?
答案:排空节点不是严格必需操作,但属于推荐操作;若不执行排空,节点重启时,其上的 Pod 会因节点离线被K8s 重新调度或重启,导致短暂的业务中断(通常几秒到几十秒) ,而执行kubectl drain --ignore-daemonsets $NODE可提前将 Pod 安全迁移到其他未迁移节点,避免中断。
节点迁移成功的验证需包含三个核心步骤:
-
- 检查Cilium状态:
cilium status --wait,确认目标节点的“Managed Pods”数量正常,无异常状态;
- 检查Cilium状态:
-
- 检查Pod IP归属:在目标节点创建测试Pod(如用netshoot镜像),通过
ip -br addr确认Pod IP在Cilium专属CIDR内(如10.245.0.0/16);
- 检查Pod IP归属:在目标节点创建测试Pod(如用netshoot镜像),通过
-
- 验证网络连通性:测试 Pod 内执行
curl -s -k https://$KUBERNETES_SERVICE_HOST/healthz,确保能成功访问 K8s APIServer,证明 Pod 网络正常。
- 验证网络连通性:测试 Pod 内执行