K8s CNI 从 Calico 迁 Cilium 一个季度实录:eBPF 替 iptables

500 节点 5000 Pod K8s 集群从 Calico 迁 Cilium 一个季度实录:架构对比 + 性能压测 + chained 共存迁移 + kubeProxyReplacement + L7 NetworkPolicy + Hubble 可观测 + 6 大坑修法 + 决策清单。

2023 年初我们 K8s 集群从 Calico 迁到 Cilium,理由是想用 eBPF 替代 iptables,顺便上 NetworkPolicy 七层规则。迁移走了一个季度,有惊喜也有翻车。本文复盘对比 Calico 和 Cilium,讲透两个方案的真实差异、迁移流程、性能对比和踩过的坑。

迁移背景

现状:K8s 1.27,500 个节点,5000+ Pod,Calico v3.24 over BGP
痛点:
- iptables 规则数 10w+,新增 Pod 慢(秒级延迟)
- NetworkPolicy 只能 L3/L4,要做 L7 规则得加 Envoy
- 排查丢包靠 conntrack,体验差
- 跨 AZ 流量观测能力弱

期望:
- eBPF-based 数据面,绕开 iptables
- L7 NetworkPolicy(HTTP 方法 + Path)
- Hubble 网络可观测性
- ServiceMesh 能力(不依赖 Istio)

候选:Cilium v1.14

架构对比

关键能力对比

维度                   Calico                      Cilium
========================================================================
数据面                 iptables / eBPF dataplane   纯 eBPF(tc/xdp)
NetworkPolicy L4       支持                        支持
NetworkPolicy L7       不支持(要 Envoy)           原生支持(HTTP/Kafka/gRPC)
Service 实现           kube-proxy                  eBPF 替代 kube-proxy
Pod 间加密             WireGuard / IPsec           WireGuard / IPsec
BGP 支持               原生(BIRD)                v1.10+ 原生
观测能力               felix metrics + tcpdump      Hubble(原生)
ServiceMesh            无                          ClusterMesh(Cilium 自带)
默认 IP 分配           IPAM                        IPAM
跨集群                  Cluster Mesh(Calico EE)    ClusterMesh(开源)
学习成本               低(IPtables 大家都熟)       中(eBPF 概念多)
社区活跃度             高                          很高(CNCF Graduated)
内核要求                3.10+                       4.9+(推荐 5.4+)

性能压测

压测环境:K8s 1.27, 3 节点 × 16C 32G, Pod 间 iperf3

测试 1:Pod 间 throughput(同节点)
Calico iptables  : 22.5 Gbps
Calico eBPF data : 28.0 Gbps
Cilium           : 32.5 Gbps

测试 2:Pod 间 throughput(跨节点)
Calico iptables  : 9.2 Gbps
Calico eBPF data : 10.8 Gbps
Cilium           : 11.5 Gbps
Cilium native routing: 12.1 Gbps

测试 3:Service 转发延迟(p99)
kube-proxy iptables: 850us
kube-proxy ipvs    : 420us
Cilium eBPF        : 180us

测试 4:NetworkPolicy 多规则
1000 条 policy:
- Calico iptables:每个新 Pod 5-8 秒生效
- Cilium:每个新 Pod 1 秒内生效

CPU 占用(满负载):
- Calico iptables felix:每节点 1.2 core
- Cilium agent:每节点 0.5 core

迁移流程

不能直接卸 Calico 装 Cilium,会全集群断网

正确流程:
1. 准备:Cilium 部署在 chained CNI 模式,与 Calico 共存
2. 节点滚动:逐节点替换 CNI(cordon → drain → 改 CNI → uncordon)
3. 验证:每滚 10 个节点跑一遍业务验证
4. 切换 NetworkPolicy:Calico CRD → Cilium CRD
5. 清理:卸载 Calico DaemonSet 和 CRD

Cilium 部署

# 1. cilium CLI
$ curl -L --remote-name-all https://github.com/cilium/cilium-cli/releases/latest/download/cilium-linux-amd64.tar.gz
$ tar xzf cilium-linux-amd64.tar.gz && mv cilium /usr/local/bin/

# 2. 检查内核
$ uname -r        # 5.4+ 推荐
$ ./cilium status

# 3. Helm 安装(参数最重要)
$ helm install cilium cilium/cilium \
    --namespace kube-system \
    --version 1.14.4 \
    --set kubeProxyReplacement=true \
    --set k8sServiceHost=k8s-api.internal \
    --set k8sServicePort=6443 \
    --set ipam.mode=kubernetes \
    --set routingMode=native \
    --set ipv4NativeRoutingCIDR=10.0.0.0/8 \
    --set bpf.masquerade=true \
    --set bandwidthManager.enabled=true \
    --set hubble.enabled=true \
    --set hubble.relay.enabled=true \
    --set hubble.ui.enabled=true \
    --set hubble.metrics.enabled='{dns,drop,tcp,flow,icmp,http}'

# 4. 验证
$ cilium status
$ cilium connectivity test
# 这个命令会跑一堆 Pod 测试连通性,跑通就 OK

替代 kube-proxy

# Cilium 完全替代 kube-proxy(不需要 kube-proxy DaemonSet)
$ helm upgrade cilium cilium/cilium \
    --reuse-values \
    --set kubeProxyReplacement=true

# 删掉 kube-proxy
$ kubectl -n kube-system delete ds kube-proxy
$ kubectl -n kube-system delete cm kube-proxy
$ for node in $(kubectl get node -o name); do
    kubectl annotate $node --overwrite k8s.example.com/kube-proxy-replaced=true
  done

# 节点执行(清理残留 iptables 规则)
$ iptables-save | grep -v KUBE | iptables-restore
$ ipvsadm -C

L7 NetworkPolicy

# 传统 NetworkPolicy(L3/L4)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-allow-frontend
spec:
  podSelector: {matchLabels: {app: backend}}
  policyTypes: [Ingress]
  ingress:
    - from:
        - podSelector: {matchLabels: {app: frontend}}
      ports:
        - port: 8080
          protocol: TCP

# Cilium L7 NetworkPolicy(HTTP)
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: backend-l7
spec:
  endpointSelector:
    matchLabels: {app: backend}
  ingress:
    - fromEndpoints:
        - matchLabels: {app: frontend}
      toPorts:
        - ports: [{port: "8080", protocol: TCP}]
          rules:
            http:
              - method: GET
                path: /api/v1/orders/.*
              - method: POST
                path: /api/v1/orders
                headers:
                  - "X-User-Role: admin"
              # 拒绝其他 HTTP

# Kafka L7 policy
- toPorts:
    - ports: [{port: "9092", protocol: TCP}]
      rules:
        kafka:
          - role: produce
            topic: events
          - role: consume
            topic: events
            consumerGroup: backend-consumer

Hubble 可观测性

# Hubble CLI
$ hubble observe --service productpage --since 1m

# Mar 15 14:23:01.123: default/frontend:42158 (ID:1234) -> default/backend:8080 (ID:5678) http-request FORWARDED (HTTP/1.1 GET /api/orders)
# Mar 15 14:23:01.180: default/backend:8080 (ID:5678) -> default/frontend:42158 (ID:1234) http-response FORWARDED (HTTP/1.1 200 57ms)

# 过滤特定问题
$ hubble observe --verdict DROPPED --since 5m
# 看所有被 NetworkPolicy 拒绝的流量

# Hubble UI(图形化)
$ kubectl port-forward -n kube-system svc/hubble-ui 8080:80

# Prometheus 指标
hubble_drop_total{reason="Policy denied"}
hubble_flows_processed_total
hubble_tcp_flags_total

踩过的坑

坑 1:kube-proxy 不能直接删,要先验证 service

直接删 kube-proxy 导致服务断流 5 分钟
正确步骤:先开 Cilium kubeProxyReplacement,验证 svc 都正常再删 kube-proxy
$ kubectl run test-svc --image=busybox --rm -it -- wget -O- http://kubernetes.default.svc

坑 2:LoadBalancer 类型 Service 不通

原因:云厂商 LB 通过 nodePort 转发,Cilium 替代 kube-proxy 后 nodePort 处理在 eBPF
       某些云 LB 健康检查走 iptables 规则,Cilium 看不到

修法:配置 nodePort.directRoutingDevice 或 nodePort.localRedirectPolicy
nodePort:
  enabled: true
  directRoutingDevice: eth0
  enableHealthCheck: true
  bindProtection: true

坑 3:Pod 重启后 IP 变了影响连接

业务长连接,Pod 滚动重启 IP 变,客户端没重连
原因:NetworkPolicy 按 label 选,IP 变其实不影响 policy
       问题在业务 client 端,不是 CNI 的锅

修复:client 加自动重连 + DNS TTL 调短

坑 4:DNS 流量被 L7 policy 干扰

# 默认 deny all 把 DNS 也 deny 了
# 必须显式放开 DNS
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-dns
spec:
  endpointSelector:
    matchLabels:
      io.kubernetes.pod.namespace: default
  egress:
    - toEndpoints:
        - matchLabels:
            io.kubernetes.pod.namespace: kube-system
            k8s-app: kube-dns
      toPorts:
        - ports: [{port: "53", protocol: UDP}]
          rules:
            dns:
              - matchPattern: "*"

坑 5:Cilium agent OOM

现象:节点 Cilium agent 占用 4GB 内存
原因:endpoint 太多(每节点 80+ Pod),eBPF map 占用大
       默认 map 大小可能撑不住

修复:调大 map 大小
bpf:
  ctTcpMax: 524288
  ctAnyMax: 262144
  natMax: 524288
  policyMapMax: 32768
  authMapMax: 524288
resources:
  limits:
    memory: 8Gi
  requests:
    memory: 2Gi

坑 6:NetworkPolicy 调试难

# Pod 间不通,policy 是不是干扰?
$ cilium policy trace --src-pod default/frontend --dst-pod default/backend --dport 8080

# Verdict: DENIED
# Resolving ingress policy for [{app=backend}]
# Final verdict: DENIED
# Reason: No allowed rules

# 看具体被哪条规则拒绝
$ hubble observe --pod default/frontend --verdict DROPPED -f

迁移完后的实际收益

指标                           Calico        Cilium       变化
=============================================================
Pod 启动时延(NetworkPolicy 多)  5-8s          1s           -85%
Service p99 延迟(集群内)        850us         180us        -79%
节点 CPU 占用(网络组件)        1.2 core       0.5 core    -58%
观测能力(诊断时长)             查 iptables 30min  hubble 5min  -83%
L7 policy 支持                  无            原生
排障体验                        翻 conntrack  Hubble UI

新增能力:
- Hubble 实时流量观测
- ClusterMesh 跨集群通信
- BGP 原生(替代外部 MetalLB)
- WireGuard 透明加密(开启一行配置)
- ServiceMesh 能力(Cilium ServiceMesh)

什么时候不要换 Cilium

1. 内核 < 4.9 — 不支持
2. 团队对 eBPF 完全陌生 — 排障期会很痛苦
3. 现有 Calico 跑得很好 — 不要为换而换
4. 集群规模 < 50 节点 — 收益不明显
5. 用 Calico Enterprise 商业功能 — 商业支持是关键
6. 严重依赖 Calico Felix metric 报警 — 迁移要重写

避坑清单

  1. 迁移前升级内核到 5.4+,新特性 + BTF 支持
  2. 不能直接卸 Calico 装 Cilium,中间要共存阶段
  3. kubeProxyReplacement 开启前测试所有 Service 类型
  4. NetworkPolicy 默认 deny 模式下要放开 DNS
  5. Cilium agent 内存按 endpoint 数算,大集群调大 map
  6. Hubble 看流量很爽,但生产关掉 hubble.metrics 全开(高基数)
  7. L7 policy 性能比 L4 差,只对关键链路用
  8. BGP 模式注意 ASN 不冲突,跨集群规划好
  9. 升级 Cilium 跨 minor 版本要看 changelog,有 breaking change
  10. cilium connectivity test 是迁移完最值得跑的命令

总结

Calico 是 K8s 网络的"老朋友",成熟稳定文档全。Cilium 是新一代基于 eBPF 的方案,性能 + 观测 + L7 能力都更现代。但 eBPF 不是银弹:学习成本高,排障思路得换。我们换了一个季度,收益最明显的是 Hubble — 以前查"为什么 Pod 间不通"要翻 iptables + conntrack + tcpdump,现在 hubble observe 一行命令搞定。如果你的集群规模上千节点 + 团队愿意投入学习,Cilium 是明确推荐;如果只是几十节点的小集群,Calico 仍然是稳妥选择。

—— 别看了 · 2026
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理 邮箱1846861578@qq.com。
技术教程

eBPF 性能诊断实战:Go 服务 sys 60% 的隐藏 fsync 案

2026-5-19 12:13:08

技术教程

KEDA 自动扩缩落地实战:K8s 从 cron 扩缩到事件驱动

2026-5-19 12:18:44

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索