技术博客

Cilium 替换 Calico/Flannel 实战:基于 eBPF 的高性能 K8s 网络

完整讲解如何在 Kubernetes 集群中用 Cilium 替换 Calico 或 Flannel,包括 Helm 安装、kube-proxy 替换、Hubble 可观测性开启、以及与旧 CNI 迁移过程中的常见问题处理。

CiliumeBPFCNIKubernetes网络CalicoFlannel

Calico 和 Flannel 是 Kubernetes 最流行的 CNI 插件,但它们都依赖 iptables 来实现 Service 转发和网络策略。当集群 Service 超过 1000 个时,iptables 规则数量可达数十万条,每次更新需要全量刷新,延迟明显增加。Cilium 基于 eBPF 完全绕过 iptables,在大规模集群中性能优势显著。本文从实际操作角度讲解替换过程。

为什么换 Cilium

性能角度:

Calico/Flannel(iptables 路径):
  数据包 → 网卡 → 内核协议栈 → iptables 规则链(可能有 50000+ 条规则)
            → 路由 → 目标 Pod

Cilium(eBPF 路径):
  数据包 → 网卡 → XDP/TC eBPF 程序(直接查 Hash 表)→ 目标 Pod
            (绕过 iptables,Hash 查找 O(1))

在 5000 Service 的集群,iptables 版本 P99 连接建立延迟可达 300ms+,Cilium 稳定在 5ms 以下。

功能角度:

环境准备

内核版本要求

# 检查内核版本(Cilium 需要 5.10+,推荐 5.15+)
uname -r
# 5.15.0-118-generic  ← Ubuntu 22.04 LTS,满足

# 检查 eBPF 支持
ls /sys/fs/bpf
# 如果目录存在说明 BPF 文件系统已挂载

# Cilium 特性矩阵(按内核版本)
# 5.10:基础 eBPF 数据路径
# 5.15:完整 XDP、Wireguard 加密
# 6.1:eBPF 主机路由完整支持、Cilium Mesh

卸载旧 CNI(迁移前备份)

⚠️ 警告:CNI 迁移会造成短暂网络中断(通常 2-5 分钟),需在维护窗口进行。

# 备份当前网络配置
kubectl get networkpolicy -A -o yaml > networkpolicy-backup.yaml
kubectl get pods -A -o wide > pods-before-migration.txt

# 如果是 Calico:删除 Calico 组件
kubectl delete -f https://docs.projectcalico.org/manifests/calico.yaml
# 或通过 Operator 删除
kubectl delete -n tigera-operator installation default
kubectl delete ns tigera-operator

# 如果是 Flannel:
kubectl delete -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

# 清理各节点上的旧 CNI 配置
# 在每个节点执行:
sudo rm -f /etc/cni/net.d/10-calico.conflist
sudo rm -f /etc/cni/net.d/10-flannel.conflist
sudo rm -rf /var/lib/calico
sudo ip link delete flannel.1 2>/dev/null || true
sudo ip link delete vxlan.calico 2>/dev/null || true

安装 Cilium

方法一:Helm 安装(推荐生产)

# 添加 Cilium Helm 仓库
helm repo add cilium https://helm.cilium.io/
helm repo update

# 查看可用版本
helm search repo cilium/cilium --versions | head -5

# 安装 Cilium(替换 kube-proxy)
helm install cilium cilium/cilium \
  --version 1.16.5 \
  --namespace kube-system \
  --set kubeProxyReplacement=true \
  --set k8sServiceHost=<YOUR_API_SERVER_IP> \
  --set k8sServicePort=6443 \
  --set hubble.relay.enabled=true \
  --set hubble.ui.enabled=true \
  --set operator.replicas=1

# 参数说明:
# kubeProxyReplacement=true  完全替换 kube-proxy,无 iptables
# k8sServiceHost             API Server 地址(必填,用于 kube-proxy 替换)
# hubble.relay.enabled=true  开启 Hubble 流量可观测
# hubble.ui.enabled=true     开启 Hubble Web UI

方法二:cilium CLI 安装(测试/快速部署)

# 安装 cilium CLI
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
curl -L --fail --remote-name-all \
  https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-amd64.tar.gz
sudo tar xzvfC cilium-linux-amd64.tar.gz /usr/local/bin
rm cilium-linux-amd64.tar.gz

# 一键安装
cilium install --version 1.16.5

# 检查状态
cilium status

卸载 kube-proxy(如果存在)

# 如果集群有 kube-proxy DaemonSet,需要删除
kubectl -n kube-system delete daemonset kube-proxy

# 清理 kube-proxy iptables 规则(在每个节点执行)
sudo iptables-save | grep -v KUBE | sudo iptables-restore

# 验证 Cilium 接管 Service 流量
kubectl -n kube-system exec -it ds/cilium -- cilium status
# 应该看到:KubeProxyReplacement: True

验证 Cilium 安装

# 查看 Cilium Pod 状态(每个节点一个)
kubectl get pods -n kube-system -l k8s-app=cilium
# NAME           READY   STATUS    RESTARTS
# cilium-abc12   1/1     Running   0
# cilium-xyz34   1/1     Running   0

# 检查 Cilium 整体健康状态
cilium status --wait
# /¯¯\
# Cilium:             OK
# Operator:           OK
# Hubble Relay:       OK
# ClusterMesh:        disabled

# 运行连通性测试
cilium connectivity test
# ✅ [cilium-test] Test [no-policies]... ✅
# ✅ [cilium-test] Test [allow-all-except-world]... ✅
# ...所有测试通过

# 验证 kube-proxy 替换
kubectl -n kube-system exec ds/cilium -- cilium status | grep KubeProxyReplacement
# KubeProxyReplacement:   True

# 验证 eBPF 数据路径
kubectl -n kube-system exec ds/cilium -- cilium bpf tunnel list
# 应该显示节点间的 eBPF 隧道

Hubble 可观测性

Hubble 是 Cilium 内置的网络可观测平台,基于 eBPF 在内核层捕获所有网络流量,无需修改应用。

访问 Hubble UI

# 端口转发访问 Hubble UI
cilium hubble ui &
# 自动打开浏览器 http://localhost:12000

# 或手动端口转发
kubectl port-forward -n kube-system svc/hubble-ui 12000:80 &

Hubble CLI 查询流量

# 安装 Hubble CLI
HUBBLE_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/hubble/master/stable.txt)
curl -L --fail --remote-name-all \
  https://github.com/cilium/hubble/releases/download/$HUBBLE_VERSION/hubble-linux-amd64.tar.gz
sudo tar xzvfC hubble-linux-amd64.tar.gz /usr/local/bin

# 端口转发到 Hubble Relay
cilium hubble port-forward &

# 实时观察所有流量
hubble observe --follow

# 过滤特定命名空间的流量
hubble observe --namespace production --follow

# 过滤 HTTP 流量
hubble observe --protocol http --follow

# 查看被 NetworkPolicy 丢弃的流量(排查策略问题)
hubble observe --verdict DROPPED --follow
# 输出示例:
# TIMESTAMP    SOURCE            DESTINATION       TYPE       VERDICT
# 10:32:15     app/frontend      db/postgres:5432  policy-verdict   DROPPED
# ← 发现前端尝试直连 DB 但被策略拒绝

# 查看 DNS 解析追踪
hubble observe --protocol dns --follow
# 10:32:20  app/api  kube-dns:53  DNS Query: redis.prod.svc.cluster.local
# 10:32:20  kube-dns  app/api    DNS Answer: 10.96.45.123

Hubble 服务依赖图

# 生成服务依赖图(JSON 格式)
hubble observe --output json --last 1000 | \
  jq -r 'select(.flow.verdict == "FORWARDED") |
    "\(.flow.source.namespace)/\(.flow.source.pod_name) -> \(.flow.destination.namespace)/\(.flow.destination.pod_name)"' | \
  sort | uniq -c | sort -rn | head -20

# 输出示例:
# 1542  production/frontend -> production/api
#  891  production/api -> production/redis
#  445  production/api -> production/postgres

网络策略迁移

Cilium 兼容 Kubernetes 原生 NetworkPolicy,原有策略无需修改:

# 应用备份的网络策略(直接兼容)
kubectl apply -f networkpolicy-backup.yaml

# 验证策略生效
kubectl get networkpolicy -A

同时,Cilium 提供功能更强的 CiliumNetworkPolicy CRD,支持 L7 策略:

# 示例:只允许 frontend 访问 api 的 /api/ 路径(L7 HTTP 策略)
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-frontend-to-api
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: api
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: frontend
    toPorts:
    - ports:
      - port: "8080"
        protocol: TCP
      rules:
        http:
        - method: "GET"
          path: "^/api/"
        - method: "POST"
          path: "^/api/"

常见问题

问题 1:Pod 无法跨节点通信

# 检查 Cilium 日志
kubectl -n kube-system logs ds/cilium | grep -i error | tail -20

# 检查 eBPF 程序是否加载
kubectl -n kube-system exec ds/cilium -- cilium bpf endpoint list

# 检查节点间路由
kubectl -n kube-system exec ds/cilium -- ip route show
# 正常应该有到每个节点 PodCIDR 的路由

问题 2:kube-proxy 替换后 Service 不通

# 确认 k8sServiceHost 参数正确
kubectl -n kube-system get configmap cilium-config -o yaml | grep k8sServiceHost

# 检查 BPF LB 表(Service 转发表)
kubectl -n kube-system exec ds/cilium -- cilium bpf lb list
# 应该能看到所有 Service 的 VIP 和 Endpoint 映射

# 如果某个 Service 缺失
kubectl -n kube-system exec ds/cilium -- cilium service list

问题 3:Hubble 观测到大量 DROP

# 导出所有 DROP 事件
hubble observe --verdict DROPPED --last 100 --output json > dropped.json

# 分析丢弃原因
cat dropped.json | jq -r '.flow.drop_reason_desc' | sort | uniq -c | sort -rn
# 常见原因:
# Policy denied       → NetworkPolicy 拒绝(正常行为)
# Stale or unroutable → 目标 Pod 已删除(短暂,正常)
# CT: Can't create    → 连接追踪表满,需增加 ct-global-max-entries

性能调优

# values.yaml 生产调优配置
cat << 'EOF' > cilium-values-prod.yaml
# 启用 eBPF Host Routing(最高性能,需要内核 5.10+)
bpf:
  hostLegacyRouting: false

# 连接追踪表大小(默认 4MB,大集群需要增大)
bpfConntrackGlobal: true
bpf:
  ctGlobalMaxEntries: 2048000   # 200万连接

# NAT 表大小
bpf:
  natGlobalMaxEntries: 1024000

# 开启 Maglev 一致性哈希(Service 负载均衡更均匀)
loadBalancer:
  algorithm: maglev

# WireGuard 透明加密(可选,有一定性能开销)
encryption:
  enabled: false
  type: wireguard

# 带宽管理(限速)
bandwidthManager:
  enabled: true
EOF

helm upgrade cilium cilium/cilium \
  --namespace kube-system \
  -f cilium-values-prod.yaml

小结

Cilium 替换 Calico/Flannel 的主要收益是:大规模集群下 Service 转发延迟从 O(n) 降到 O(1)、内置 Hubble 可观测性省去额外监控组件、L7 网络策略提供更精细的流量控制。迁移成本主要在维护窗口的短暂中断和内核版本要求(5.10+)。对于新建集群,Cilium 是 2026 年的首选 CNI;对于旧集群,建议在 5000 Service 或性能问题明显时再评估迁移。下一篇将讲解 Cilium 的零信任网络策略实战。