编程 Cilium 深度拆解:当 eBPF 决定「干掉 iptables+kube-proxy」——从 22K Star 的云原生网络方案到 CNCF 毕业项目的全栈工程哲学

2026-08-04 03:43:47 +0800 CST views 9

Cilium 深度拆解:当 eBPF 决定「干掉 iptables+kube-proxy」——从 22K Star 的云原生网络方案到 CNCF 毕业项目的全栈工程哲学

引言:iptables 的黄昏

2026 年的 Kubernetes 集群规模已经突破 10 万节点大关。当你在这样的集群上用 kubectl logs 看到一条网络策略被触发的日志时,你可能不知道,这条规则的匹配路径穿过了 iptables 链表的线性遍历——在大规模集群中,这意味着每秒数百万次的无谓比较。

iptables 诞生于 1998 年,它的设计初衷是为单机防火墙服务。二十多年后,它却被推上了 Kubernetes 网络策略的核心位置。当规则数从几十条膨胀到数万条时,iptables 的 O(n) 线性匹配就从"够用"变成了"灾难"。更致命的是,iptables 的 conntrack 模块在高并发场景下的内存消耗可以轻松突破数 GB,而这些开销本可以被内核中更高效的数据结构完全规避。

Cilium 就是在这个背景下诞生的。 它不是又一个 Kubernetes CNI 插件——它是一次对 Linux 网络栈的重新设计。通过 eBPF(Extended Berkeley Packet Filter)技术,Cilium 将网络数据路径从 iptables 的线性链表迁移到了内核态的哈希表和红黑树上,实现了 O(1) 的策略匹配和接近零的内核态-用户态切换开销。

截至 2026 年 7 月,Cilium 在 GitHub 上拥有超过 22,000 颗 Star,是 CNCF(Cloud Native Computing Foundation)的毕业项目(Graduated Project),被 AWS EKS、Google GKE、Azure AKS 等主流云厂商深度集成。Google 在 2023 年将 Cilium 作为 GKE 数据平面的默认网络方案,这是对一个开源项目最极致的认可。

本文将从 eBPF 的底层原理出发,深入拆解 Cilium 的架构设计、数据路径、安全模型和可观测性体系,让你理解为什么"用 eBPF 重写网络栈"不是一个口号,而是一场正在发生的范式转移。


第一章:eBPF——内核里的安全沙箱

1.1 什么是 eBPF

eBPF 的全称是 Extended Berkeley Packet Filter,但这个名字已经无法准确描述它的能力。2026 年的 eBPF 已经远远超出了"包过滤"的范畴——它是一个在 Linux 内核中运行的、经过验证器安全检查的、可编程的虚拟机

简单来说,eBPF 允许你在不修改内核源码、不加载内核模块的前提下,将自定义程序注入到内核的各个钩子点(hook points)上执行。这些钩子点遍布内核的网络栈、系统调用、文件系统、调度器等几乎所有子系统。

// 一个最简单的 eBPF 程序:统计每个网络包的字节数
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

// 定义一个 BPF map,用于从内核态向用户态传递数据
struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 1024);
    __type(key, __u32);    // 进程 PID
    __type(value, __u64);  // 累计字节数
} byte_count SEC(".maps");

// 挂载到网络包处理的 tc(traffic control)钩子点
SEC("tc")
int count_bytes(struct __sk_buff *skb) {
    __u32 pid = bpf_get_current_pid_tgid() >> 32;
    __u64 *count = bpf_map_lookup_elem(&byte_count, &pid);
    
    if (count) {
        __sync_fetch_and_add(count, skb->len);
    } else {
        __u64 init = skb->len;
        bpf_map_update_elem(&byte_count, &pid, &init, BPF_ANY);
    }
    
    return TC_ACT_OK;  // 允许包继续通过
}

char LICENSE[] SEC("license") = "GPL";

这段代码展示了 eBPF 的核心工作模式:

  1. 编写 C 程序:使用受限的 eBPF 指令集
  2. 编译为 BPF 字节码:通过 clang/LLVM 编译
  3. 加载到内核:通过 bpf() 系统调用
  4. 验证器检查:内核验证器确保程序不会崩溃内核
  5. JIT 编译:字节码被即时编译为本地机器码
  6. 挂载到钩子:程序被附加到网络、系统调用等钩子点

1.2 验证器:eBPF 的安全基石

eBPF 程序运行在内核态,如果程序有 bug,可能导致内核崩溃甚至安全漏洞。为了解决这个问题,Linux 内核实现了一个静态验证器(Static Verifier),它在程序加载时对所有代码路径进行穷举分析:

// 验证器会拒绝这段代码——因为它可能导致无限循环
SEC("tc")
int bad_program(struct __sk_buff *skb) {
    while (1) {  // ❌ 验证器检测到无限循环
        // ...
    }
    return TC_ACT_OK;
}

// 验证器会拒绝这段代码——因为数组越界访问
SEC("tc")
int bad_array_access(struct __sk_buff *skb) {
    int arr[10];
    arr[100] = 1;  // ❌ 越界访问
    return TC_ACT_OK;
}

验证器的检查规则包括:

  • 无无限循环:所有循环必须有确定的上界
  • 无越界访问:数组和内存访问必须在边界内
  • 无悬空指针:所有指针在使用前必须有效
  • 栈大小限制:eBPF 程序的栈帧不超过 512 字节
  • 辅助函数白名单:只能调用内核允许的辅助函数

这种"先验证再执行"的模式,让 eBPF 程序拥有了接近原生内核模块的性能,同时保持了用户态程序的安全性。

1.3 eBPF 的钩子点矩阵

eBPF 程序可以挂载到内核的多个关键位置,形成了一个完整的可编程矩阵:

┌─────────────────────────────────────────────────────┐
│                    用户态进程                         │
├─────────────────────────────────────────────────────┤
│  系统调用入口 ──── tracepoint/syscalls/sys_enter_*   │
│  进程调度   ──── kprobe/sched_switch                 │
├─────────────────────────────────────────────────────┤
│                    VFS 层                            │
│  文件操作   ──── kprobe/vfs_read, vfs_write          │
├─────────────────────────────────────────────────────┤
│                    网络栈                            │
│  XDP        ──── 网卡驱动层(最早拦截点)             │
│  TC         ──── 流量控制层                          │
│  Socket     ──── sock_ops / sk_msg                   │
│  cgroup     ──── cgroup/connect4/6                   │
├─────────────────────────────────────────────────────┤
│                    内核核心                           │
│  kprobe     ──── 任意内核函数入口                     │
│  kretprobe  ──── 任意内核函数返回                     │
│  tracepoint ──── 静态追踪点                          │
│  perf_event ──── 性能计数器                          │
└─────────────────────────────────────────────────────┘

Cilium 主要使用的是网络栈层面的钩子,特别是 XDP、TC 和 cgroup 这三个关键位置。


第二章:Cilium 的架构全景

2.1 整体架构

Cilium 的架构可以分为三个层次:

┌──────────────────────────────────────────────────────────┐
│                    Kubernetes Control Plane               │
│  ┌─────────┐  ┌──────────┐  ┌─────────────────────────┐ │
│  │ kube-api │  │ Cilium   │  │ Cilium Operator         │ │
│  │ server   │──│ Daemon   │  │ (集群级协调)              │ │
│  └─────────┘  └──────────┘  └─────────────────────────┘ │
├──────────────────────────────────────────────────────────┤
│                    eBPF Data Plane                        │
│  ┌─────────────────────────────────────────────────────┐ │
│  │  XDP 程序     │  TC 程序     │  cgroup 程序          │ │
│  │  (L3/L4 过滤) │  (策略执行)  │  (Socket 连接管理)     │ │
│  └─────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────┤
│                    Linux Kernel                           │
│  ┌─────────────────────────────────────────────────────┐ │
│  │  网卡驱动  │  TCP/IP 协议栈  │  Conntrack  │  调度器  │ │
│  └─────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘

Cilium Daemon 是运行在每个 Kubernetes 节点上的核心组件,它负责:

  • 与 Kubernetes API Server 通信,监听 Pod、Service、NetworkPolicy 等资源变化
  • 编译和加载 eBPF 程序到内核
  • 管理 eBPF Map(内核态与用户态的数据共享结构)
  • 处理身份分配(Identity Allocation)

Cilium Operator 是集群级组件,负责:

  • 全局身份分配(Identity Allocation)的协调
  • 集群级别的健康检查
  • 与外部 KVStore(如 etcd)的同步

2.2 Identity:安全模型的核心抽象

Cilium 最精妙的设计之一是引入了 Identity(身份)这个抽象层。在传统的 Kubernetes 网络策略中,策略是基于 IP 地址的——Pod 的 IP 会随着调度、重启而变化,导致策略规则频繁失效。

Cilium 的 Identity 模型彻底解耦了"身份"和"网络地址":

# 传统 NetworkPolicy:基于 IP 和标签
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-web
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
---
# Cilium Identity 的工作方式:
# 1. 为具有相同标签集的 Pod 分配一个全局唯一的 Identity ID
# 2. 网络策略基于 Identity 而非 IP
# 3. Identity 通过 eBPF Map 在内核态直接传递和匹配

Identity 的分配过程:

Pod 创建
    │
    ▼
Cilium Daemon 监听到新 Pod
    │
    ▼
提取 Pod 的所有标签: {app=web, env=prod, team=backend}
    │
    ▼
计算标签的哈希值: hash("app=web,env=prod,team=backend") = 0xABCD1234
    │
    ▼
将 Identity ID 0xABCD1234 分配给这个 Pod
    │
    ▼
通过 eBPF Map 将 (Pod IP → Identity ID) 映射注入内核
    │
    ▼
内核态的 eBPF 程序直接读取 Identity ID 进行策略匹配
    │
    ▼
网络包的源/目标 IP 变化时,无需更新策略——Identity 不变

这意味着:当 Pod 被重新调度、IP 地址发生变化时,网络策略无需任何更新就能继续生效。这在大规模集群中是一个巨大的运维优势。

2.3 eBPF Map:内核态与用户态的桥梁

eBPF Map 是 eBPF 程序与用户态程序之间共享数据的核心机制。Cilium 大量使用了多种类型的 BPF Map:

// Cilium 中使用的几种关键 BPF Map 类型

// 1. Policy Map:存储网络策略规则
//    Key: (源 Identity, 目标 Identity, 协议, 端口)
//    Value: 动作 (ALLOW / DENY)
struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 65536);
    __type(key, struct policy_key);
    __type(value, struct policy_entry);
} cilium_policy SEC(".maps");

// 2. Connection Tracking Map:替代内核的 conntrack
struct {
    __uint(type, BPF_MAP_TYPE_LRU_HASH);
    __uint(max_entries, 1048576);
    __type(key, struct ct_entry_key);
    __type(value, struct ct_entry);
} cilium_ct TCP4 SEC(".maps");

// 3. LB Map:负载均衡映射
struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 65536);
    __type(key, struct lb4_key);
    __type(value, struct lb4_service);
} cilium_lb4_services SEC(".maps");

// 4. Tunnel Map:封装/解封装映射
struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 65536);
    __type(key, struct tunnel_key);
    __type(value, struct tunnel_value);
} cilium_tunnel_map SEC(".maps");

这些 Map 的设计体现了 Cilium 的核心理念:将原本在用户态(iptables/nftables 规则、conntrack 表、负载均衡表)管理的数据结构,全部下沉到内核态,消除用户态-内核态的数据拷贝和上下文切换开销。


第三章:数据路径深度剖析

3.1 传统路径 vs Cilium 路径

让我们对比一个 Pod 到 Pod 的网络包在传统 kube-proxy 路径和 Cilium 路径下的处理流程:

传统 kube-proxy 路径(iptables 模式):

Pod A 发送包到 Service VIP
    │
    ▼
iptables PREROUTING 链(线性遍历所有规则)
    │
    ▼
iptables KUBE-SERVICES 链(匹配 Service 规则)
    │  O(n) 复杂度,规则越多越慢
    ▼
iptables KUBE-SEP 链(选择后端 Pod)
    │  随机 masquerade
    ▼
iptables POSTROUTING 链
    │
    ▼
网卡发出

Cilium eBPF 路径:

Pod A 发送包到 Service VIP
    │
    ▼
TC eBPF 程序(挂载在 veth 设备上)
    │  1. 解析 L3/L4 头部
    │  2. 查找 Identity Map → 获取源 Identity
    │  3. 查找 Policy Map → 检查策略(O(1) 哈希查找)
    │  4. 查找 LB Map → 选择后端 Pod(O(1) 哈希查找)
    │  5. 更新 CT Map → 连接跟踪
    ▼
内核协议栈(TCP/IP 处理)
    │
    ▼
目标 veth 设备的 TC eBPF 程序
    │  1. 查找 Policy Map → 入站策略检查
    │  2. 传递给目标 Pod
    ▼
目标 Pod 收到包

关键差异在于:

维度iptables/kube-proxyCilium eBPF
策略匹配复杂度O(n) 线性遍历O(1) 哈希查找
连接跟踪内核 conntrack(内存大)自定义 CT Map(可控)
Service 负载均衡iptables 随机规则eBPF 哈希表直接查找
可观测性需要额外 tcpdump/floweBPF 原生采集
策略更新延迟iptables-restore 重建eBPF Map 原子更新

3.2 XDP:在网卡驱动层截获流量

XDP(eXpress Data Path)是 eBPF 最高效的网络钩子点,它在网络包进入内核协议栈之前就被截获。在 XDP 层,包还没有被分配 sk_buff 结构体,处理开销极小。

// Cilium 中 XDP 程序的核心逻辑(简化版)
SEC("xdp")
int cilium_xdp(struct xdp_md *ctx) {
    void *data = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;
    
    // 1. 解析以太网头
    struct ethhdr *eth = data;
    if (eth + 1 > data_end) return XDP_PASS;
    
    // 2. 只处理 IPv4
    if (eth->h_proto != __constant_htons(ETH_P_IP)) return XDP_PASS;
    
    // 3. 解析 IP 头
    struct iphdr *ip = (void *)(eth + 1);
    if (ip + 1 > data_end) return XDP_PASS;
    
    // 4. 查找 conntrack——使用自定义 BPF Map 替代内核 conntrack
    struct ct_entry_key key = {
        .daddr = ip->daddr,
        .saddr = ip->saddr,
        .protocol = ip->protocol,
    };
    struct ct_entry *entry = bpf_map_lookup_elem(&cilium_ct, &key);
    
    if (entry) {
        // 已有连接:更新统计,直接放行
        entry->packets++;
        entry->bytes += (data_end - data);
        return XDP_PASS;
    }
    
    // 5. 新连接:需要进一步处理(交给 TC 层)
    return XDP_PASS;
}

XDP 的三种运行模式:

  1. Native XDP:在网卡驱动中直接执行,性能最高(需要网卡驱动支持)
  2. Offloaded XDP:在网卡硬件中执行(需要 SmartNIC 支持,如 NVIDIA/Mellanox)
  3. Generic XDP:在内核协议栈中模拟执行(兼容性最好,性能最低)

Cilium 在生产环境中通常推荐使用 Native XDP,可以实现每秒数千万包的处理能力。

3.3 TC 层:策略执行的主战场

虽然 XDP 性能最高,但它无法访问完整的 sk_buff 结构体,限制了复杂策略的执行。因此,Cilium 将主要的策略执行逻辑放在了 TC(Traffic Control)层:

// Cilium TC 程序的核心策略匹配逻辑(简化版)
SEC("tc")
int cilium_tc(struct __sk_buff *skb) {
    // 1. 获取当前包的网络元数据
    struct pkt_metadata md;
    pkt_metadata_init(skb, &md);
    
    // 2. 查找源 Identity
    struct endpoint_info *src_ep = lookup_endpoint(md.saddr);
    if (!src_ep) return TC_ACT_OK;  // 未知来源,放行
    
    // 3. 查找目标 Identity
    struct endpoint_info *dst_ep = lookup_endpoint(md.daddr);
    if (!dst_ep) return TC_ACT_OK;  // 本地流量,放行
    
    // 4. 策略匹配:O(1) 哈希查找
    struct policy_entry *policy = bpf_map_lookup_elem(
        &cilium_policy,
        &(struct policy_key){
            .src_identity = src_ep->identity,
            .dst_identity = dst_ep->identity,
            .protocol = md.protocol,
            .dport = md.dport,
        }
    );
    
    if (policy) {
        if (policy->action == ACTION_ALLOW) {
            // 允许:更新连接跟踪
            ct_update_entry(&md, CT_ENTRY_ESTABLISHED);
            return TC_ACT_OK;
        } else {
            // 拒绝:丢弃包并记录
            update_drop_metrics(src_ep->identity, DROP_POLICY_DENY);
            return TC_ACT_SHOT;  // 丢弃
        }
    }
    
    // 5. 无匹配策略:默认拒绝(零信任模型)
    update_drop_metrics(src_ep->identity, DROP_POLICY_DEFAULT);
    return TC_ACT_SHOT;
}

3.4 Conntrack:自建替代方案

Linux 内核的 conntrack(连接跟踪)模块是 iptables 的核心依赖,但也是性能瓶颈所在。conntrack 使用全局锁和链表结构,在高并发场景下锁竞争严重。

Cilium 用 eBPF Map 实现了自己的连接跟踪模块,彻底绕开了内核 conntrack:

// Cilium 自定义 CT 的优势
struct ct_entry {
    __u64 packets_rx;
    __u64 packets_tx;
    __u64 bytes_rx;
    __u64 bytes_tx;
    __u64 last_rx_report;
    __u64 last_tx_report;
    __u16 flags;
    __u8  state;
    __u8  service_flags;
    // ... 更多字段
};

// 使用 LRU Hash Map 替代链表
// LRU = Least Recently Used,自动淘汰最久未使用的连接
struct {
    __uint(type, BPF_MAP_TYPE_LRU_HASH);
    __uint(max_entries, 1048576);  // 100万并发连接
    __type(key, struct ct_entry_key);
    __type(value, struct ct_entry);
} cilium_ct TCP4 SEC(".maps");

性能对比:

指标内核 conntrackCilium CT
锁竞争全局锁,高并发严重无锁(per-CPU Map)
查找复杂度链表遍历 O(n)哈希查找 O(1)
内存开销固定分配,浪费大LRU 按需分配
GC 机制定时器扫描LRU 自动淘汰
100 万并发连接~2GB 内存~512MB 内存

第四章:Service Mesh 与负载均衡

4.1 替代 kube-proxy

Cilium 可以完全替代 kube-proxy,提供更高性能的 Service 负载均衡:

# Cilium 的 kube-proxy 替代配置
apiVersion: v1
kind: ConfigMap
metadata:
  name: cilium-config
  namespace: kube-system
data:
  # 启用 kube-proxy 替代
  kube-proxy-replacement: "strict"
  
  # 启用 XDP 加速
  enable-xdp: "true"
  
  # 启用 host routing(绕过内核路由表)
  enable-host-routing: "true"
  
  # 启用带宽管理器
  enable-bandwidth-manager: "true"

当 kube-proxy 替代模式启用时,Cilium 的 eBPF 程序会:

  1. 拦截所有发往 Service ClusterIP 的流量
  2. 在 eBPF Map 中查找 Service → Endpoints 映射
  3. 使用一致性哈希(Consistent Hashing)选择后端 Pod
  4. 直接修改包的 destination IP 并转发

整个过程完全在内核态完成,不经过用户态的 kube-proxy 进程,延迟从微秒级降低到纳秒级。

4.2 Cluster Mesh:跨集群服务发现

Cilium 的 Cluster Mesh 功能允许多个 Kubernetes 集群之间直接通信,无需 VPN 或复杂的网络配置:

# 启用 Cluster Mesh
cilium clustermesh enable --service-type NodePort

# 连接两个集群
cilium clustermesh connect --destination-context cluster-b

# 验证连接状态
cilium clustermesh status --wait

Cluster Mesh 的架构:

┌─────────────────────┐         ┌─────────────────────┐
│    Cluster A         │         │    Cluster B         │
│  ┌───────────────┐  │         │  ┌───────────────┐  │
│  │ Cilium Agent  │  │◄───────►│  │ Cilium Agent  │  │
│  │ (eBPF Data    │  │  VXLAN  │  │ (eBPF Data    │  │
│  │  Plane)       │  │  或     │  │  Plane)       │  │
│  └───────────────┘  │  Geneve │  └───────────────┘  │
│                     │  隧道    │                     │
│  ┌───────────────┐  │         │  ┌───────────────┐  │
│  │ clustermesh-  │  │         │  │ clustermesh-  │  │
│  │ apiserver     │  │         │  │ apiserver     │  │
│  └───────────────┘  │         │  └───────────────┘  │
└─────────────────────┘         └─────────────────────┘

关键特性:

  • 跨集群 Service 发现:Pod 可以通过 service-name.cluster-name.mesh 访问其他集群的服务
  • 全局负载均衡:eBPF 在内核态实现跨集群的负载均衡
  • 统一网络策略:NetworkPolicy 可以跨集群生效
  • 自动身份同步:Identity 在集群间自动同步

4.3 Gateway API 支持

Cilium 是 Kubernetes Gateway API 的参考实现之一。Gateway API 是 Ingress 的下一代替代方案,提供了更丰富的流量管理能力:

# Cilium Gateway API 配置示例
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: production-gw
  annotations:
    # 使用 Cilium 的 eBPF 加速
    io.cilium/proxy-protocol: "true"
spec:
  gatewayClassName: cilium
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    tls:
      mode: Terminate
      certificateRefs:
      - name: production-cert
    allowedRoutes:
      namespaces:
        from: All
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: api-route
spec:
  parentRefs:
  - name: production-gw
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /api/v2
    backendRefs:
    - name: api-service
      port: 8080
    # Cilium 特有的流量权重分配
    filters:
    - type: TrafficSplit
      trafficSplit:
      - backendRefs:
        - name: api-v2-canary
          port: 8080
          weight: 10
        - name: api-v2-stable
          port: 8080
          weight: 90

第五章:安全模型——零信任的内核级实现

5.1 L3/L4 网络策略

Cilium 的网络策略基于 Identity 而非 IP,这是它与 Calico、Weave 等 CNI 插件的核心差异:

# Cilium NetworkPolicy 示例
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: l3-l4-policy
spec:
  endpointSelector:
    matchLabels:
      app: database
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: backend
    toPorts:
    - ports:
      - port: "5432"
        protocol: TCP
  egress:
  - toEndpoints:
    - matchLabels:
        app: cache
    toPorts:
    - ports:
      - port: "6379"
        protocol: TCP

当这条策略被应用时,Cilium Daemon 会:

  1. 在 Kubernetes API 监听到策略变化
  2. 计算受影响的 Identity 集合
  3. 生成对应的 eBPF Map 条目
  4. 原子性地更新 eBPF Map——无需重启、无需重载

5.2 L7 应用层策略

Cilium 独特的能力之一是支持 L7(应用层)策略,这意味着你可以在 HTTP/gRPC/Kafka 层面控制流量:

# L7 HTTP 策略:只允许 GET /api/public/* 路径
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: l7-http-policy
spec:
  endpointSelector:
    matchLabels:
      app: web-api
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: frontend
    toPorts:
    - ports:
      - port: "8080"
        protocol: TCP
      rules:
        http:
        - method: GET
          path: "/api/public/.*"
        - method: POST
          path: "/api/login"
          headers:
          - 'Content-Type: application/json'

# L7 Kafka 策略:只允许消费特定 topic
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: l7-kafka-policy
spec:
  endpointSelector:
    matchLabels:
      app: kafka-consumer
  egress:
  - toEndpoints:
    - matchLabels:
        app: kafka-broker
    toPorts:
    - ports:
      - port: "9092"
        protocol: TCP
      rules:
        kafka:
        - apiKey: fetch
          topic: "orders.*"
        - apiKey: produce
          topic: "events.*"

L7 策略的实现原理:

  1. Cilium 在 Pod 的 veth 设备上插入一个 Envoy 代理(基于 Envoy Proxy 的 sidecar-less 模式)
  2. eBPF 程序在内核态识别出需要 L7 检查的流量
  3. 流量被透明地重定向到 Envoy 代理
  4. Envoy 执行 HTTP/Kafka 级别的策略检查
  5. 通过检查的流量被放行,未通过的被拒绝

5.3 透明加密

Cilium 支持基于 WireGuard 或 IPsec 的 Pod 间透明加密,无需修改应用代码:

# 启用 WireGuard 加密
apiVersion: v1
kind: ConfigMap
metadata:
  name: cilium-config
  namespace: kube-system
data:
  # 启用 WireGuard 透明加密
  enable-well-known-identities: "false"
  enable-wireguard: "true"
  
  # 或者使用 IPsec
  # enable-ipsec: "true"
  # ipsec-key-file: /etc/ipsec/keys

加密的工作流程:

  1. Cilium Daemon 在每个节点上生成 WireGuard 密钥对
  2. 节点间自动交换公钥
  3. eBPF 程序在发送端加密包,在接收端解密包
  4. 加密过程完全在内核态完成,对应用完全透明

第六章:可观测性——Hubble 体系

6.1 Hubble 架构

Cilium 的可观测性体系叫做 Hubble,它基于 eBPF 在内核态直接采集网络数据,无需任何旁路代理或 sidecar:

┌──────────────────────────────────────────────────┐
│              Hubble UI / CLI / Grafana            │
│    ┌────────────┐  ┌────────────┐  ┌──────────┐ │
│    │ Service Map│  │ Flow Logs  │  │ Metrics  │ │
│    └────────────┘  └────────────┘  └──────────┘ │
├──────────────────────────────────────────────────┤
│              Hubble Relay                        │
│    (聚合各节点的流数据,提供统一查询接口)          │
├──────────────────────────────────────────────────┤
│              Hubble Server (per node)            │
│    ┌─────────────────────────────────────────┐   │
│    │  eBPF Events → gRPC Stream → Relay      │   │
│    └─────────────────────────────────────────┘   │
├──────────────────────────────────────────────────┤
│              eBPF Programs (kernel)              │
│    ┌──────────┐  ┌──────────┐  ┌────────────┐  │
│    │ Socket   │  │ Trace    │  │ Policy     │  │
│    │ Filter   │  │ Point    │  │ Verdict    │  │
│    └──────────┘  └──────────┘  └────────────┘  │
└──────────────────────────────────────────────────┘

6.2 实时流量可视化

# 使用 Hubble CLI 观察实时流量
$ hubble observe --namespace production --to-pod database

TIMESTAMP          SOURCE                    DESTINATION           TYPE    VERDICT   SUMMARY
Aug  4 03:15:01.123  default/backend-abc123   default/database-def  L3/L4   FORWARDED TCP Flags: SYN
Aug  4 03:15:01.125  default/database-def     default/cache-ghi456  L3/L4   FORWARDED TCP Flags: SYN
Aug  4 03:15:01.200  default/backend-abc123   default/database-def  L3/L4   FORWARDED TCP Flags: ACK
Aug  4 03:15:01.300  default/backend-abc123   default/database-def  L7      FORWARDED HTTP/1.1 GET /api/users
Aug  4 03:15:01.450  default/database-def     default/cache-ghi456  L7      FORWARDED Redis GET user:12345

# 查看被策略拒绝的流量
$ hubble observe --namespace production --verdict DROPPED

TIMESTAMP          SOURCE                    DESTINATION           TYPE    VERDICT   SUMMARY
Aug  4 03:15:02.100  default/frontend-xyz789  default/database-def  L3/L4   DROPPED  Policy denied: missing L3/L4 allow rule

6.3 Service Map:自动生成的拓扑图

Hubble 可以根据实时流量自动生成服务依赖拓扑图:

# 在 Hubble UI 中查看 Service Map
$ hubble ui

# 或者导出为 JSON 用于自定义可视化
$ hubble observe --output json | \
  jq -r 'select(.event_type == 4) | 
    {source: .source.pod_name, 
     destination: .destination.pod_name, 
     verdict: .verdict}'

Service Map 的独特之处在于它是基于真实流量生成的,而非基于配置文件。这意味着:

  • 你可以发现配置文件中没有记录的隐式依赖
  • 你可以验证策略是否真正生效
  • 你可以监控流量模式的变化

6.4 Prometheus 指标集成

Cilium 原生支持 Prometheus 指标导出:

# Cilium 指标配置
apiVersion: v1
kind: ConfigMap
metadata:
  name: cilium-config
  namespace: kube-system
data:
  # 启用 Prometheus 指标
  prometheus-serve-addr: ":9962"
  
  # 启用 Hubble 指标
  enable-hubble: "true"
  hubble-metrics-server: ":9965"
  hubble-metrics:
    - dns
    - drop
    - tcp
    - flow
    - icmp
    - http
    - kafka
    - policy

关键指标:

# 网络包丢弃率
cilium_drop_total{reason="Policy denied",protocol="tcp"}

# 策略判定延迟(纳秒级)
cilium_policy_verdict_latency_seconds_bucket{verdict="forwarded"}

# 连接跟踪条目数
cilium_conntrack_entries{protocol="tcp"}

# Service 负载均衡命中率
cilium_service_count{type="ClusterIP"}

# Hubble 流量指标
hubble_flows_processed_total{verdict="dropped",protocol="tcp"}

第七章:性能基准与实战对比

7.1 kube-proxy 替代的性能提升

根据 Cilium 官方和社区的基准测试,在 1000 个 Service 的场景下:

Service 负载均衡延迟(P99):
┌─────────────────────────────────────────┐
│ iptables/kube-proxy  ████████████ 280μs │
│ IPVS/kube-proxy      ███████     150μs  │
│ Cilium eBPF           ███         45μs  │
│ Cilium eBPF + XDP     █          12μs  │
└─────────────────────────────────────────┘

Service 负载均衡吞吐量:
┌─────────────────────────────────────────┐
│ iptables/kube-proxy  ████         80K   │
│ IPVS/kube-proxy      ██████      120K   │
│ Cilium eBPF           █████████   200K  │
│ Cilium eBPF + XDP     ██████████████ 350K │
└─────────────────────────────────────────┘

内存开销(1000 Service, 10000 Pod):
┌─────────────────────────────────────────┐
│ iptables/kube-proxy  ████████████ 1.2GB │
│ IPVS/kube-proxy      ████████     800MB │
│ Cilium eBPF           ████         350MB│
│ Cilium eBPF (优化)    ██           200MB│
└─────────────────────────────────────────┘

7.2 网络策略匹配性能

在 10,000 条网络策略的场景下:

策略匹配延迟(单包):
┌─────────────────────────────────────────────┐
│ iptables (10K rules)  ████████████████ 58μs │
│ nftables (10K rules)  ██████████       35μs │
│ Calico (eBPF)         ██████           18μs │
│ Cilium (eBPF)         ██                6μs │
└─────────────────────────────────────────────┘

原因分析:
- iptables/nftables: O(n) 线性遍历,规则越多越慢
- Calico eBPF: 使用 eBPF 但 Map 设计较保守
- Cilium eBPF: 优化的 Map 布局 + 预编译策略

7.3 连接跟踪性能

并发连接数与内存消耗:
┌─────────────────────────────────────────────────┐
│ 连接数      │ 内核conntrack │ Cilium CT         │
│ 10,000      │ 50MB          │ 15MB              │
│ 100,000     │ 500MB         │ 120MB             │
│ 1,000,000   │ 5GB (接近极限)│ 900MB             │
│ 5,000,000   │ OOM           │ 3.5GB             │
└─────────────────────────────────────────────────┘

Cilium CT 使用 LRU Hash,自动淘汰过期连接
内核 conntrack 使用固定分配,内存浪费严重

第八章:生产环境部署实战

8.1 快速安装

# 使用 Cilium CLI 安装(推荐方式)
# 1. 安装 Cilium CLI
curl -sS -L https://raw.githubusercontent.com/cilium/cilium-cli/main/install.sh | \
  sudo tar xzC /usr/local/bin

# 2. 安装 Cilium(启用 kube-proxy 替代 + Hubble)
cilium install \
  --set kubeProxyReplacement=strict \
  --set hubble.enabled=true \
  --set hubble.relay.enabled=true \
  --set hubble.ui.enabled=true \
  --set prometheus.enabled=true \
  --set operator.prometheus.enabled=true

# 3. 验证安装状态
cilium status --wait

# 4. 启用 Hubble UI
cilium hubble enable --ui

# 5. 打开 Hubble UI
cilium hubble ui

8.2 生产级配置

# 生产环境推荐配置
apiVersion: v1
kind: ConfigMap
metadata:
  name: cilium-config
  namespace: kube-system
data:
  # kube-proxy 替代
  kube-proxy-replacement: "strict"
  
  # 网络模式
  tunnel: "vxlan"  # 或 "geneve", "disabled"(原生路由)
  
  # 性能优化
  enable-endpoint-routes: "true"
  enable-bandwidth-manager: "true"
  enable-host-routing: "true"
  enable-xdp: "true"
  
  # 安全
  enable-well-known-identities: "false"
  enable-encryption: "true"
  encryption-type: "wireguard"
  
  # 可观测性
  enable-hubble: "true"
  hubble-listen-address: ":4244"
  hubble-metrics-server: ":9965"
  hubble-metrics:
    - dns
    - drop
    - tcp
    - flow
    - http
    - policy
    - kafka
    - icmp
  
  # 连接跟踪优化
  ct-timeout-credentials: "3600"
  
  # 日志
  debug: "false"
  debug-verbose: ""

8.3 故障排查

# 检查 eBPF 程序加载状态
cilium-dbg bpf list

# 查看 eBPF Map 内容
cilium-dbg bpf policy get
cilium-dbg bpf ct list tcp4
cilium-dbg bpf service list

# 检查身份分配
cilium-dbg identity list
cilium-dbg identity get <identity-id>

# 检查连通性
cilium-dbg connectivity test

# 查看 Hubble 流量
hubble observe --namespace <ns> --to-pod <pod>
hubble observe --verdict DROPPED
hubble observe --l7-type http

# 导出诊断信息
cilium-dbg bugtool

第九章:Cilium 与竞品对比

9.1 CNI 插件全景

┌────────────┬──────────┬──────────┬──────────┬──────────┐
│ 特性        │ Cilium   │ Calico   │ Flannel  │ Weave    │
├────────────┼──────────┼──────────┼──────────┼──────────┤
│ 数据平面    │ eBPF     │ eBPF/    │ VXLAN/   │ VXLAN    │
│            │          │ iptables │ host-gw  │          │
├────────────┼──────────┼──────────┼──────────┼──────────┤
│ 网络策略    │ L3/L4/L7 │ L3/L4    │ 无       │ L3       │
├────────────┼──────────┼──────────┼──────────┼──────────┤
│ kube-proxy │ ✅        │ ✅        │ ❌        │ ❌        │
│ 替代       │          │          │          │          │
├────────────┼──────────┼──────────┼──────────┼──────────┤
│ 加密       │ WireGuard│ IPsec    │ 无       │ NaCl     │
│            │ /IPsec   │          │          │          │
├────────────┼──────────┼──────────┼──────────┼──────────┤
│ 可观测性    │ Hubble   │ Calico   │ 无       │ Weave    │
│            │ (原生)   │ (Kibana) │          │ Scope    │
├────────────┼──────────┼──────────┼──────────┼──────────┤
│ Service    │ ✅ 原生   │ ✅        │ ❌        │ ❌        │
│ Mesh       │          │          │          │          │
├────────────┼──────────┼──────────┼──────────┼──────────┤
│ 跨集群     │ Cluster  │ Federation│ ❌       │ ❌        │
│            │ Mesh     │          │          │          │
├────────────┼──────────┼──────────┼──────────┼──────────┤
│ CNCF 状态  │ 毕业项目  │ 毕业项目  │ 沙箱     │ 沙箱     │
└────────────┴──────────┴──────────┴──────────┴──────────┘

9.2 为什么选 Cilium

选 Cilium 的理由:

  • 你有大规模集群(1000+ 节点),iptables 性能成为瓶颈
  • 你需要 L7 级别的网络策略
  • 你需要原生的可观测性(不需要额外部署 Prometheus + Grafana 全家桶)
  • 你有多集群场景,需要 Cluster Mesh
  • 你追求极致性能,愿意接受更高的运维复杂度

不选 Cilium 的理由:

  • 小规模集群(<100 节点),iptables 的性能影响可以忽略
  • 团队没有 eBPF 相关经验,学习曲线陡峭
  • 需要支持非常老的 Linux 内核(<4.19)
  • 已有成熟的 Calico/Flannel 运维体系

第十章:总结与展望

10.1 Cilium 的核心哲学

回顾 Cilium 的设计,我们可以提炼出几个核心哲学:

  1. 内核态优先:将网络逻辑从用户态下沉到内核态,消除不必要的上下文切换
  2. 身份解耦:用 Identity 抽象取代 IP 地址绑定,适应容器的动态性
  3. 可编程一切:用 eBPF 将网络栈的每个环节都变成可编程的
  4. 零信任安全:默认拒绝,显式允许,策略在内核态强制执行
  5. 可观测性即基础设施:将可观测性作为网络方案的内在能力,而非外挂组件

10.2 未来趋势

eBPF 正在重塑 Linux 内核的编程模型。Cilium 作为 eBPF 在网络领域的标杆项目,正在引领几个重要趋势:

  1. eBPF 的泛化:从网络扩展到安全(Tetragon)、可观测性(Pixie)、存储(SIG)等更多领域
  2. SmartNIC 卸载:将 eBPF 程序卸载到网卡硬件,实现线速处理
  3. 多平台支持:eBPF 不再局限于 Linux——Windows eBPF 正在开发中
  4. eBPF 与 AI 的结合:用 eBPF 采集的内核级数据训练 AI 模型,实现智能运维

10.3 写在最后

Cilium 的故事告诉我们:有时候,最好的创新不是发明新东西,而是重新审视那些我们习以为常的基础组件。iptables 在 1998 年是天才设计,但在 2026 年的云原生时代,它已经成为性能和安全的瓶颈。eBPF 提供了一种在不破坏兼容性的前提下,渐进式地重写内核网络栈的可能。

如果你正在运行 Kubernetes 集群,如果你正在为网络性能或安全策略头疼,Cilium 值得你认真评估。它不仅仅是一个 CNI 插件——它是云原生网络的未来。


参考资料:

推荐文章

PHP 允许跨域的终极解决办法
2024-11-19 08:12:52 +0800 CST
JavaScript 异步编程入门
2024-11-19 07:07:43 +0800 CST
在Rust项目中使用SQLite数据库
2024-11-19 08:48:00 +0800 CST
使用 node-ssh 实现自动化部署
2024-11-18 20:06:21 +0800 CST
Vue3中如何进行错误处理?
2024-11-18 05:17:47 +0800 CST
程序员茄子在线接单