Cilium 替换 Calico/Flannel 实战:基于 eBPF 的高性能 K8s 网络
完整讲解如何在 Kubernetes 集群中用 Cilium 替换 Calico 或 Flannel,包括 Helm 安装、kube-proxy 替换、Hubble 可观测性开启、以及与旧 CNI 迁移过程中的常见问题处理。
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 以下。
功能角度:
- L7 网络策略(HTTP path/method、gRPC method 级别控制)
- Hubble 内置可观测性(流量拓扑、DNS 追踪、HTTP 请求追踪)
- Cilium Mesh / Cluster Mesh 跨集群网络
- Tetragon 安全可观测(eBPF LSM)
- 替换 kube-proxy,完全无 iptables
环境准备
内核版本要求
# 检查内核版本(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 的零信任网络策略实战。
