cailico 迁移到 cilium

76 阅读5分钟

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: 如果不禁用,两者立刻就会冲突(实际测试情况)

推荐先在测试集群验证。

image.png

一、迁移核心背景与原理

  1. CNI 工作基础:kubelet 创建 Pod Sandbox 时,会调用/etc/cni/net.d/中配置的 CNI 插件,负责 Pod 的 IP 分配、网卡配置及覆盖网络建立,Pod 网络配置生命周期与 Sandbox 一致。

  2. 传统迁移痛点:直接替换所有节点的 CNI 并重启节点,会导致“未迁移节点”与“已迁移节点”形成两个通信孤岛,Pod 间通信随机中断,直至迁移完全结束。

  3. Cilium 迁移核心方案——双覆盖网络(Dual Overlays)

    1. 原理:Cilium 与现有 CNI 分别使用独立的 IP 段和覆盖网络(协议或端口不同),Linux 路由表自动隔离两类流量,实现迁移中旧 CNI Pod 与 Cilium Pod 的正常通信。

    2. 优势:支持节点逐个迁移,无需集群整体停机,最大程度减少业务中断。

二、迁移前提与限制

类别具体内容关键说明
必备要求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/16
2. 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”模式
  1. (可选)搭建示例环境(Kind+Flannel)

    1. 创建 Kind 集群配置文件kind-config.yaml,禁用默认 CNI;
    2. 执行kind create cluster --config=kind-config.yaml创建集群;
    3. 安装参考 CNI 插件和 Flannel:kubectl apply -n kube-system --server-side -f https://raw.githubusercontent.com/cilium/cilium/HEAD/examples/misc/migration/install-reference-cni-plugins.yamlkubectl apply --server-side -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
    4. 等待所有节点就绪:kubectl wait --for=condition=Ready nodes --all
  2. 配置关键参数

    1. 选择 Cilium 专属资源:确定独立 CIDR(如10.245.0.0/16)和封装端口(如 VXLAN 8473);

    2. 编写 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  # 允许新旧覆盖网络间路由
        
  3. 生成初始配置并安装 Cilium

    1. 生成初始 Helm 配置:cilium install --chart-directory ./install/kubernetes/cilium --values values-migration.yaml --dry-run-helm-values > values-initial.yaml
    2. 添加 Cilium Helm仓 库并安装:helm repo add cilium https://helm.cilium.io/helm install cilium cilium/cilium --namespace kube-system --values values-initial.yaml
    3. 验证安装:cilium status --wait,此时“Cluster Pods”应显示“0/X managed by Cilium”(无 Pod 由 Cilium 管理)。
  4. 创建节点级配置(CiliumNodeConfig)

    1. 配置文件指定节点选择器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"
        
    2. 应用配置:kubectl apply --server-side -f -(上述配置通过标准输入传入)。

(二)节点迁移阶段:逐个迁移目标节点
  1. 选择并预处理节点

    1. 选择目标节点(推荐先 worker 节点,如 Kind 集群的kind-worker):NODE="kind-worker"
    2. 隔离节点(禁止新 Pod 调度):kubectl cordon $NODE
    3. (可选)排空节点(减少 Pod 重启中断):kubectl drain --ignore-daemonsets $NODE
  2. 触发节点 Cilium 迁移

    1. 为节点打标签(匹配 CiliumNodeConfig 的选择器):kubectl label node $NODE --overwrite "io.cilium.migration/cilium-default=true"
    2. 重启节点上的 Cilium Pod(使其加载CNI配置):kubectl -n kube-system delete pod --field-selector spec.nodeName=$NODE -l k8s-app=cilium
    3. 等待 Cilium DaemonSet 就绪:kubectl -n kube-system rollout status ds/cilium -w
    4. 重启节点( Kind 节点用 Docker 重启):docker restart $NODE
  3. 验证节点迁移结果

    1. 检查 Cilium 状态:cilium status --wait,确认目标节点的 Pod 开始由 Cilium 管理;

    2. 检查节点信息:kubectl get -o wide node $NODE

    3. 验证 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'
        
    4. 关键验证点:Pod IP 需在 Cilium CIDR(如10.245.0.0/16)内,且curl能成功返回APIServer 健康状态。

  4. 恢复节点调度kubectl uncordon $NODE,重复上述步骤迁移下一个节点。

(三)迁移后阶段:完成收尾与优化
  1. 验证整体迁移结果cilium status,确认所有节点的 Pod 均由 Cilium 管理。

  2. 更新 Cilium 配置(启用完整功能)

    1. 生成最终配置:启用策略 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
        
    2. 对比配置差异:diff values-initial.yaml values-final.yaml

    3. 应用配置并重启 Cilium:helm upgrade --namespace kube-system cilium cilium/cilium --values values-final.yamlkubectl -n kube-system rollout restart daemonset cilium

    4. 等待 Cilium 就绪:cilium status --wait

  3. 清理旧资源

    1. 删除 CiliumNodeConfig:kubectl delete -n kube-system ciliumnodeconfig cilium-default

    2. 删除旧 CNI 插件(如 Flannel);

    3. (可选)滚动重启所有节点:清理旧 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);

  1. 等待 Cilium 就绪后,cilium status 确认 “Policy Enforcement” 已恢复为 “default” 模式,此时 Cilium 将正常执行 NetworkPolicy 规则。

问题3:在节点迁移阶段,“排空节点(kubectl drain)”是必需操作吗?如果不执行排空,会对业务产生什么影响?如何验证节点迁移是否成功?

答案:排空节点不是严格必需操作,但属于推荐操作;若不执行排空,节点重启时,其上的 Pod 会因节点离线被K8s 重新调度或重启,导致短暂的业务中断(通常几秒到几十秒) ,而执行kubectl drain --ignore-daemonsets $NODE可提前将 Pod 安全迁移到其他未迁移节点,避免中断。

节点迁移成功的验证需包含三个核心步骤:

    1. 检查Cilium状态:cilium status --wait,确认目标节点的“Managed Pods”数量正常,无异常状态;
    1. 检查Pod IP归属:在目标节点创建测试Pod(如用netshoot镜像),通过ip -br addr确认Pod IP在Cilium专属CIDR内(如10.245.0.0/16);
    1. 验证网络连通性:测试 Pod 内执行curl -s -k https://$KUBERNETES_SERVICE_HOST/healthz,确保能成功访问 K8s APIServer,证明 Pod 网络正常。

参考:

  1. docs.cilium.io/en/latest/i…