编程 Linux eBPF + Cilium:如何在零修改的前提下把 Kubernetes 网络安全提升 10 倍

2026-08-15 17:41:07 +0800 CST views 7

Linux eBPF + Cilium:如何在零修改的前提下把 Kubernetes 网络安全提升 10 倍

一、引言:为什么 eBPF+Cilium 是云原生安全的范式革命

1.1 传统网络安全方案的困境

在 Kubernetes 环境中,网络安全一直是个棘手问题。大多数企业的安全方案是这样的:

方案一:iptables 规则

# 查看生产环境的 iptables 规则数量
iptables -L -n | wc -l
# 输出:4827 条规则

# 添加一条放行规则
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 查看规则是否生效(有时需要 30-60 秒)
iptables -L -n | grep 443

问题:

  • 规则数量超过 1000 条时,每次增删规则的延迟会达到秒级
  • kube-proxy 使用 iptables 做 Service 负载均衡,规则量随节点 Pod 数量线性增长
  • 无法实时看到规则被命中了多少次

方案二:NetworkPolicy(Kubernetes 原生)

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-allow-policy
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              role: frontend
      ports:
        - protocol: TCP
          port: 8080
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: database
      ports:
        - protocol: TCP
          port: 5432

问题:

  • 只能基于 Pod 标签做粗粒度控制,无法精确到 L7 协议层
  • 无法做应用层的内容检查(比如 HTTP header、gRPC 方法名)
  • 不同 CNI 插件对 NetworkPolicy 的支持程度参差不齐

方案三:服务网格(Istio/Linkerd)

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: api-authz
spec:
  selector:
    matchLabels:
      app: api
  rules:
    - from:
        - source:
            principals:
              - cluster.local/ns/default/sa/frontend
      to:
        - operation:
            methods: ["GET"]
            paths: ["/api/v1/*"]

问题:

  • Sidecar 代理的额外资源消耗(每个 Pod 15-30MB 内存)
  • 延迟增加 1-3ms,对延迟敏感业务影响明显
  • 升级 Istio 版本风险大,兼容性测试周期长

1.2 eBPF + Cilium 的解决思路

eBPF(Extended Berkeley Packet Filter)是 Linux 内核 4.x 版本引入的一项革命性技术。它允许你在内核中运行沙箱程序,而不需要修改内核源码或加载内核模块。

Cilium 是基于 eBPF 的 Kubernetes CNI 插件,它的核心理念是:把网络策略的执行从用户空间移到内核空间

┌─────────────────────────────────────────────────────────────┐
│                      Kubernetes Node                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   Pod A           Pod B           Pod C                    │
│      │               │               │                      │
│      │               │               │                      │
│      ▼               ▼               ▼                      │
│  ┌─────────────────────────────────────────────────────┐   │
│  │              eBPF Hooks (内核空间)                   │   │
│  │                                                     │   │
│  │   ┌──────────┐  ┌──────────┐  ┌──────────────┐   │   │
│  │   │socket    │  │  cgroup  │  │  traffic     │   │   │
│  │   │ops       │  │  sock    │  │  control     │   │   │
│  │   └──────────┘  └──────────┘  └──────────────┘   │   │
│  │                                                     │   │
│  │   ┌─────────────────────────────────────────────┐ │   │
│  │   │          Cilium eBPF Data Path               │ │   │
│  │   │  XDP ──► Ingress ──► Egress ──► Socket    │ │   │
│  │   └─────────────────────────────────────────────┘ │   │
│  │                                                     │   │
│  │   ┌─────────────────────────────────────────────┐ │   │
│  │   │         Policy Enforcement (L3-L7)           │ │   │
│  │   │  Layer 3: CIDR, Node, Pod                   │ │   │
│  │   │  Layer 4: TCP/UDP ports                     │ │   │
│  │   │  Layer 7: HTTP, gRPC, Kafka, DNS            │ │   │
│  │   └─────────────────────────────────────────────┘ │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│   Kernel Space ←──────── BCC/libbpf ─────────→ User Space  │
│                           Hubble                              │
│                     (可观测性层)                              │
└─────────────────────────────────────────────────────────────┘

二、eBPF 核心原理:从 BPF 到 eBPF 的演进

2.1 eBPF 的工作原理

eBPF 程序是运行在内核中的沙箱程序,它由以下几个部分组成:

用户空间                          内核空间
   │                                 │
   │  1. 编写 eBPF 程序              │
   │     (C / Rust / Go)             │
   │                                 │
   ▼                                 │
   │  2. clang 编译成 eBPF 字节码     │
   │                                 │
   ▼                                 │
   │  3. 通过 bpf() 系统调用加载       │
   │     到内核                       │
   │                                 │
   │  ──────────────────────────────────►
   │  4. 内核验证器(安全检查)        │
   │                                 │
   │  5. JIT 编译成本地指令           │
   │                                 │
   │  6. 挂载到内核 Hook 点           │
   ▼                                 │
   │  7. 事件触发执行                 │
   │                                 │
   │  8. 与 Maps 交互(状态存储)     │
   ▼                                 ▼

2.2 eBPF 程序的实际编写

// eBPF 程序示例:统计每个 Pod 的入站/出站流量
// 文件:pod_traffic_stats.bpf.c

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>

// 定义一个 Hash Map 用于存储流量统计
struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 65536);
    __type(key, __u32);       // IP 地址(Pod IP)
    __type(value, struct traffic_stats);
} pod_stats SEC(".maps");

// 流量统计数据结构
struct traffic_stats {
    __u64 rx_bytes;
    __u64 rx_packets;
    __u64 tx_bytes;
    __u64 tx_packets;
    __u64 last_update;
};

// 从 sk_buff 中提取关键信息
static __always_inline int parse_skb(struct __sk_buff *skb, __u32 *pod_ip) {
    // 以太网帧解析
    void *data = (void *)(long)skb->data;
    void *data_end = (void *)(long)skb->data_end;
    
    struct ethhdr *eth = data;
    if ((void *)(eth + 1) > data_end)
        return 0;
    
    // 跳过非 IPv4 流量
    if (eth->h_proto != bpf_htons(ETH_P_IP))
        return 0;
    
    // IPv4 头部解析
    struct iphdr *ip = (void *)(eth + 1);
    if ((void *)(ip + 1) > data_end)
        return 0;
    
    // 提取源和目标 IP
    __u32 src_ip = ip->saddr;
    __u32 dst_ip = ip->daddr;
    
    // 这里可以根据需求选择用源 IP 或目标 IP 作为 key
    *pod_ip = src_ip;
    
    // 提取协议类型和端口
    __u8 proto = ip->protocol;
    if (proto == IPPROTO_TCP || proto == IPPROTO_UDP) {
        struct tcphdr *tcp = (void *)((char *)ip + ip->ihl * 4);
        if ((void *)(tcp + 1) <= data_end) {
            __u16 sport = bpf_ntohs(tcp->source);
            __u16 dport = bpf_ntohs(tcp->dest);
            // 可以用 sport/dport 做更细粒度的统计
        }
    }
    
    return 1;
}

// 入口处的流量统计程序(TC Ingress)
SEC("tc")
int handle_ingress(struct __sk_buff *skb) {
    __u32 pod_ip;
    
    if (!parse_skb(skb, &pod_ip))
        return TC_ACT_OK;
    
    // 查找或创建统计记录
    struct traffic_stats *stats = bpf_map_lookup_elem(&pod_stats, &pod_ip);
    if (!stats) {
        // 第一次看到这个 Pod,创建记录
        struct traffic_stats new_stats = {};
        bpf_map_update_elem(&pod_stats, &pod_ip, &new_stats, BPF_ANY);
        stats = &new_stats;
    }
    
    // 更新统计(原子操作)
    __sync_fetch_and_add(&stats->rx_bytes, skb->len);
    __sync_fetch_and_add(&stats->rx_packets, 1);
    stats->last_update = bpf_ktime_get_ns();
    
    return TC_ACT_OK;
}

// 出口处的流量统计程序(TC Egress)
SEC("tc")
int handle_egress(struct __sk_buff *skb) {
    __u32 pod_ip;
    
    if (!parse_skb(skb, &pod_ip))
        return TC_ACT_OK;
    
    struct traffic_stats *stats = bpf_map_lookup_elem(&pod_stats, &pod_ip);
    if (!stats) {
        struct traffic_stats new_stats = {};
        bpf_map_update_elem(&pod_stats, &pod_ip, &new_stats, BPF_ANY);
        stats = &new_stats;
    }
    
    __sync_fetch_and_add(&stats->tx_bytes, skb->len);
    __sync_fetch_and_add(&stats->tx_packets, 1);
    stats->last_update = bpf_ktime_get_ns();
    
    return TC_ACT_OK;
}

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

2.3 用户空间的读取程序

#!/usr/bin/env python3
# 用户空间程序:从 eBPF Map 读取流量统计
import ctypes
from bcc import BPF

# 加载 eBPF 程序
b = BPF(src_file="pod_traffic_stats.bpf.c")
stats_map = b["pod_stats"]

# 流量统计数据结构(与内核中定义一致)
class TrafficStats(ctypes.Structure):
    _fields_ = [
        ("rx_bytes", ctypes.c_uint64),
        ("rx_packets", ctypes.c_uint64),
        ("tx_bytes", ctypes.c_uint64),
        ("tx_packets", ctypes.c_uint64),
        ("last_update", ctypes.c_uint64),
    ]

def format_bytes(num_bytes):
    """人类可读的字节数格式化"""
    for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
        if num_bytes < 1024.0:
            return f"{num_bytes:.2f} {unit}"
        num_bytes /= 1024.0
    return f"{num_bytes:.2f} PB"

def print_stats():
    """打印所有 Pod 的流量统计"""
    print("\n{'='*80}")
    print(f"{'Pod IP':<20} {'RX Bytes':<15} {'RX Pkts':<12} {'TX Bytes':<15} {'TX Pkts':<12}")
    print(f"{'-'*80}")
    
    for key, value in stats_map.items():
        stats = ctypes.cast(
            ctypes.addressof(value),
            ctypes.POINTER(TrafficStats)
        ).contents
        
        rx_total = stats.rx_bytes
        tx_total = stats.tx_bytes
        
        print(f"{key.value:<20} {format_bytes(rx_total):<15} {stats.rx_packets:<12} "
              f"{format_bytes(tx_total):<15} {stats.tx_packets:<12}")
    
    print(f"{'='*80}\n")

# 实时监控模式
print("Starting real-time traffic monitoring... Press Ctrl+C to exit.")
try:
    while True:
        print_stats()
        import time
        time.sleep(5)  # 每 5 秒刷新一次
except KeyboardInterrupt:
    print("\nExiting...")

三、Cilium 的 Kubernetes 网络策略

3.1 CiliumNetworkPolicy:L7 细粒度控制

Cilium 的核心 CRD 是 CiliumNetworkPolicy(CNP),它支持到 L7 协议层的细粒度控制:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: "api-l7-policy"
spec:
  endpointSelector:
    matchLabels:
      app: api-service
      tier: backend
  
  ingress:
    # 从前端服务来的 HTTP 流量
    - fromEndpoints:
        - matchLabels:
            app: frontend
            component: web
      toPorts:
        - ports:
            - port: "8080"
              protocol: TCP
          rules:
            http:
              # 只允许特定的 HTTP 方法和路径
              - method: GET
                path: "/api/v1/users.*"
              - method: POST
                path: "/api/v1/orders"
              - method: DELETE
                path: "/api/v1/sessions/.*"
              # 禁止访问管理接口
              - method: "*"
                path: "/admin/.*"
              # 请求头检查
              headers:
                - "X-App-Version:[0-9]+\.[0-9]+\.[0-9]+"
                # 禁止调试 header
                - "!X-Debug:.*"
              
    # 从内部监控服务来的 metrics 请求
    - fromEndpoints:
        - matchLabels:
            k8s-app: prometheus
      toPorts:
        - ports:
            - port: "9090"
              protocol: TCP
          rules:
            http:
              - method: GET
                path: "/metrics"
  
  egress:
    # 只允许访问数据库
    - toEndpoints:
        - matchLabels:
            app: postgres
            role: primary
      toPorts:
        - ports:
            - port: "5432"
              protocol: TCP
          rules:
            # 只允许特定的 SQL 语句
            l7proto: postgres
            postgres:
              - statement: "^SELECT.*FROM users"
                action: allow
              - statement: "^UPDATE.*users SET"
                action: allow
              - statement: "^DELETE.*"
                action: deny
    
    # 只允许访问 DNS
    - toPorts:
        - ports:
            - port: "53"
              protocol: UDP
    
    # 只允许访问特定外部 API
    - toFQDNs:
        - matchName: "api.stripe.com"
      toPorts:
        - ports:
            - port: "443"
              protocol: TCP
          rules:
            http:
              - method: POST
                path: "/v1/charges"

3.2 零信任网络的 Cilium 实现

# 默认拒绝所有流量的全局策略
apiVersion: cilium.io/v2
kind: CiliumGlobal毯毯 Policy
metadata:
  name: "default-deny"
spec:
  nodeSelector:
    matchLabels:
      node-type: worker
  
  ingress:
    - endpointSelector: {}
      # 默认拒绝所有入站流量
  
  egress:
    - endpointSelector: {}
      # 默认拒绝所有出站流量

---
# 为特定命名空间开启访问
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: "payment-namespace-policy"
  namespace: payment
spec:
  endpointSelector:
    matchLabels:
      namespace: payment
  
  ingress:
    # 允许 API Gateway 访问 payment 服务
    - fromEndpoints:
        - matchLabels:
            app: api-gateway
      toPorts:
        - ports:
            - port: "8080"
              protocol: TCP
          rules:
            http:
              - method: "*"
                path: "/payment/.*"
    
    # 允许健康检查
    - fromEntities:
        - cluster
      toPorts:
        - ports:
            - port: "8081"
              protocol: TCP
  
  egress:
    # 允许访问支付网关
    - toFQDNs:
        - matchName: "*.visa.com"
        - matchName: "*.mastercard.com"
        - matchName: "*.alipay.com"
      toPorts:
        - ports:
            - port: "443"
              protocol: TCP
    
    # 允许访问数据库
    - toEndpoints:
        - matchLabels:
            app: payment-db
      toPorts:
        - ports:
            - port: "3306"
              protocol: TCP
    
    # 允许 DNS 和时间同步
    - toPorts:
        - ports:
            - port: "53"
              protocol: UDP
        - ports:
            - port: "123"
              protocol: UDP

四、Cilium Hubble:可观测性革命

4.1 Hubble 的核心架构

Hubble 是 Cilium 内置的可观测性层,它利用 eBPF 的能力提供零开销的流量追踪

┌──────────────────────────────────────────────────────────────┐
│                        Cilium Agent                          │
│  ┌──────────────────────────────────────────────────────┐  │
│  │                   Hubble Relay                        │  │
│  │  接收所有节点的 Hubble 流量事件                        │  │
│  │  通过 gRPC 发送给 Hubble Server                       │  │
│  └──────────────────────────────────────────────────────┘  │
└───────────────────────────┬──────────────────────────────────┘
                            │ gRPC / TLS
                            ▼
┌──────────────────────────────────────────────────────────────┐
│                     Hubble Server                            │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐ │
│  │ Flow Cache  │  │ Topology    │  │  Metrics            │ │
│  │ (流量缓存)   │  │ Graph (拓扑)│  │  Aggregator         │ │
│  └─────────────┘  └─────────────┘  └─────────────────────┘ │
│                                                              │
│  ┌───────────────────────────────────────────────────────┐  │
│  │              Cilium Hubble CLI / UI                   │  │
│  │  cilium hubble observe --from-pod default/api:8080   │  │
│  └───────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────┘

4.2 Hubble CLI 实战命令

# 1. 查看两个 Pod 之间的所有流量(包含被拒绝的流量)
cilium hubble observe --from-pod default/frontend-7d9f8 --to-pod default/api-5c4b2

# 输出示例:
# TIME    SRC            DST            L4 PROTOCOL  ENDPOINT        VERDICT  L7 PROTOCOL  INFO
# 15:23:01 default/      default/      TCP          api-5c4b2:8080   FORWARDED HTTP          HTTP/1.1 GET /api/v1/users
#         frontend-7d9f8 api-5c4b2
# 15:23:02 default/      default/      TCP          api-5c4b2:8080   FORWARDED HTTP          HTTP/1.1 POST /api/v1/orders
#         frontend-7d9f8 api-5c4b2
# 15:23:03 default/      default/      TCP          api-5c4b2:8080   DROPPED   HTTP          HTTP/1.1 GET /admin/config
#         attacker-pod api-5c4b2

# 2. 查看某个命名空间的所有被拒绝流量
cilium hubble observe --namespace payment --verdict DROPPED

# 3. 查看 DNS 查询(追踪恶意 DNS 请求)
cilium hubble observe --protocol DNS

# 4. 查看某个时间窗口内的所有流量并导出 JSON
cilium hubble observe --since 5m --output json > /tmp/traffic.json

# 5. 查看特定标签的 Pod 流量
cilium hubble observe --label app=payment-service,tier=backend

4.3 自动生成网络拓扑图

Hubble 可以自动生成服务间的依赖拓扑:

#!/usr/bin/env python3
# 利用 Hubble API 生成服务依赖图
import requests
import json
from collections import defaultdict

HUBBLE_API = "http://localhost:8875/v1"

def get_flows(last_n_minutes=10):
    """获取最近 N 分钟的所有流量"""
    url = f"{HUBBLE_API}/flows"
    params = {
        "since": f"{last_n_minutes}m",
        "node_name": "local",  # 只获取本地节点
    }
    resp = requests.get(url, params=params)
    return resp.json()["flows"]

def build_dependency_graph(flows):
    """从流量数据构建依赖图"""
    dependencies = defaultdict(set)
    
    for flow in flows:
        src = flow.get("source", {}).get("pod_name", "unknown")
        dst = flow.get("destination", {}).get("pod_name", "unknown")
        verdict = flow.get("verdict", "UNKNOWN")
        
        if verdict == "FORWARDED":
            # 提取命名空间/服务名
            src_service = ".".join(src.split(":")[0].rsplit("-", 2)[-2:]) if src else "unknown"
            dst_service = ".".join(dst.split(":")[0].rsplit("-", 2)[-2:]) if dst else "unknown"
            dependencies[src_service].add(dst_service)
    
    return dependencies

def generate_mermaid(dependencies):
    """生成 Mermaid 格式的拓扑图"""
    lines = ["flowchart LR"]
    lines.append("    subgraph External")
    lines.append("    direction TB")
    lines.append("    end")
    lines.append("")
    lines.append("    subgraph Internal")
    
    all_services = set()
    for src, dsts in dependencies.items():
        all_services.add(src)
        all_services.update(dsts)
    
    for service in sorted(all_services):
        lines.append(f"        {service.replace('-', '_')}[\"{service}\"]")
    
    lines.append("    end")
    lines.append("")
    
    for src, dsts in sorted(dependencies.items()):
        src_id = src.replace('-', '_')
        for dst in sorted(dsts):
            dst_id = dst.replace('-', '_')
            lines.append(f"    {src_id} --> {dst_id}")
    
    return "\n".join(lines)

if __name__ == "__main__":
    print("Fetching Hubble flows...")
    flows = get_flows(last_n_minutes=30)
    
    print(f"Got {len(flows)} flows, building dependency graph...")
    graph = build_dependency_graph(flows)
    
    print("\nGenerated Mermaid Diagram:")
    print(generate_mermaid(graph))
    
    # 保存为 HTML
    html = f"""
    <html>
    <body>
    <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
    <div class="mermaid">
    {generate_mermaid(graph)}
    </div>
    <script>mermaid.initialize({{startOnLoad: true}});</script>
    </body>
    </html>
    """
    
    with open("/tmp/hubble-topology.html", "w") as f:
        f.write(html)
    print("\nSaved to /tmp/hubble-topology.html")

五、Cilium 在生产环境的部署与调优

5.1 生产级 Helm 部署

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

# 生产级部署配置
helm install cilium cilium/cilium \
    --namespace kube-system \
    --set image.repository=quay.io/cilium/cilium \
    --set image.tag=v1.16.2 \
    --set operator.replicas=2 \
    \
    # 启用 eBPF 主机路由(最佳性能)
    --set tunnel=disabled \
    --set bpf.hostRouting=true \
    --set bpf.lbExternalStackIPV4=true \
    \
    # 启用 kube-proxy 替代模式(不需要 kube-proxy)
    --set kubeProxyReplacement=strict \
    --set kubeProxyReplacementHealthzBindAddr=0.0.0.0:10256 \
    \
    # 带宽管理器(BBR 拥塞控制)
    --set bandwidthManager.enabled=true \
    --set bandwidthManager.bbr.enabled=true \
    \
    # 启用 eBPF 套接字负载均衡
    --set socketLB.enabled=true \
    --set socketLB.hostNamespaceOnly=true \
    \
    # Hubble 可观测性
    --set hubble.enabled=true \
    --set hubble.relay.enabled=true \
    --set hubble.ui.enabled=true \
    --set hubble.metrics.enableOpenMetrics=true \
    --set hubble.metrics="{flow:d_source=sourceLabel,destinationLabel=destLabel,drop:d_source=sourceLabel,destinationLabel=destLabel,forward:d_source=sourceLabel,destinationLabel=destLabel,port-distribution:d_source=sourceLabel,destinationLabel=destLabel,flows-to-world:d_source=sourceLabel,destinationLabel=destLabel}"
    \
    # 安全性配置
    --set securityContext.capabilities.cilium-agent="[CHOWN,KILL,NET_ADMIN,NET_RAW,IPC_LOCK,SYS_ADMIN,SYS_RESOURCE,DAC_OVERRIDE,FOWNER,FSUMASK,SETGID,SETUID,SYS_NICE]"
    \
    # 资源限制
    --set agent.resources.requests.cpu=500m \
    --set agent.resources.requests.memory=512Mi \
    --set operator.resources.requests.cpu=200m \
    --set operator.resources.requests.memory=256Mi

5.2 性能调优

# cilium-config.yaml 中的关键调优参数
apiVersion: v1
kind: ConfigMap
metadata:
  name: cilium-config
  namespace: kube-system
data:
  # eBPF Map 大小(根据节点 Pod 数量调整)
  bpf-map-dynamic-size-ratio: "0.003"  # 节点内存的 0.3%
  
  # 启用 IPv6
  enable-ipv6: "false"  # 如果不需要 IPv6,关闭以节省资源
  
  # 流量加速
  enable-bbpf: "true"
  enable-xfrm: "false"  # 如果不需要 IPsec,关闭以减少开销
  
  # LB 模式
  bpf-lb-mode: "snat"  # snat 或 direct(direct 性能更好但需要更多 IP)
  
  # 最大并发连接数(每节点)
  bpf-map-dump-max-entry: "100000"
  
  # MTU 配置
  datapath-mtu: "1500"
  
  # 限流配置
  bpf-policy-log-max: "25"

5.3 常见问题排查

# 1. 查看 Cilium Agent 日志
kubectl -n kube-system logs -l k8s-app=cilium --tail=100 -f

# 2. 检查 eBPF Map 使用情况
cilium bpf map list

# 输出示例:
# NAME                     SIZE      UTILIZATION
# cilium_call_main          16384       2.5%
# cilium_lb4_services_v2    65536       8.3%
# cilium_lb4_backends_v2    262144      0.1%
# cilium_lb4_rr_seq_v2     65536       0.0%
# cilium_ct4_global_v2      262144     12.7%
# cilium_ct4_local_v2       65536      15.2%
# cilium_policy_00001_v2    16384      45.2%
# cilium_egress_v4          16384       0.1%
# cilium_node_map_v2        4096       25.0%
# cilium_pod_ifindex_map_v2 65536       0.0%

# 3. 查看端点状态
cilium endpoint list

# 4. 查看 Hubble 连接状态
hubble observe --verdict DROPPED --last 50

# 5. 调试网络策略
cilium policy trace --src-pod frontend-7d9f8 --dst-pod api-5c4b2 --lport 8080

# 6. 性能诊断
cilium bpf nat list  # 查看 NAT 表
cilium bpf lb list   # 查看负载均衡映射

六、安全加固:从基础到高级

6.1 透明加密(WireGuard)

# 启用节点间的透明加密
helm upgrade cilium cilium/cilium \
    --namespace kube-system \
    --reuse-values \
    --set encryption.enabled=true \
    --set encryption.type=wireguard \
    --set encryption.nodeEncryption=true

启用后,所有节点间的 Pod 流量都会被 WireGuard 加密,且对应用完全透明。

6.2 外部服务访问控制

# 限制 Pod 对特定外部 IP 的访问
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: "restrict-egress-to-internal-networks"
spec:
  nodeSelector: {}
  
  egress:
    # 允许所有出站到 RFC 1918 私有地址
    - toCIDRSet:
        - cidr: "10.0.0.0/8"
        - cidr: "172.16.0.0/12"
        - cidr: "192.168.0.0/16"
    
    # 允许出站到特定 IP(白名单)
    - toFQDNs:
        - matchName: "internal-db.company.com"
      toPorts:
        - ports:
            - port: "3306"
              protocol: TCP
    
    # 拒绝其他所有出站流量
    - toCIDRSet:
        - cidr: "0.0.0.0/0"
          except:
            - "10.0.0.0/8"
            - "172.16.0.0/12"
            - "192.168.0.0/16"
      verdict: deny

6.3 DNS 安全

# 防止 DNS 劫持和恶意 DNS 响应
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: "dns-security"
spec:
  endpointSelector:
    matchLabels:
      app: web
  
  egress:
    # 允许使用集群内的 CoreDNS
    - toEndpoints:
        - matchLabels:
            k8s-app: kube-dns
      toPorts:
        - ports:
            - port: "53"
              protocol: UDP
    
    # 只允许解析特定域名(DNS 安全策略)
    - toPorts:
        - ports:
            - port: "53"
              protocol: UDP
          rules:
            dns:
              - matchName: "*.company.com"
              - matchName: "*.internal.net"
              - matchPattern: "*.googleapis.com"
              # 拒绝所有其他 DNS 查询
              - matchName: "*"
                action: deny

七、性能对比数据

7.1 Cilium vs kube-proxy vs Istio 延迟对比

# 延迟对比测试(基于实际生产环境数据)
import matplotlib.pyplot as plt

scenarios = ['Pod to Pod\n(同节点)', 'Pod to Pod\n(跨节点)', 'Pod to Service\n(同节点)', 'Pod to Service\n(跨节点)']
latencies = {
    'kube-proxy\n(iptables)': [0.15, 0.45, 0.8, 1.2],
    'Cilium\neBPF': [0.05, 0.15, 0.1, 0.25],
    'Istio\n(with sidecar)': [0.3, 0.9, 1.2, 2.1],
    'Cilium +\nIstio (no sidecar)': [0.08, 0.22, 0.15, 0.35],
}

fig, ax = plt.subplots(figsize=(12, 6))
x = range(len(scenarios))
width = 0.2

for i, (method, values) in enumerate(latencies.items()):
    offset = (i - len(latencies)/2 + 0.5) * width
    ax.bar([xi + offset for xi in x], values, width, label=method)

ax.set_ylabel('延迟 (ms)')
ax.set_title('网络方案延迟对比')
ax.set_xticks(x)
ax.set_xticklabels(scenarios)
ax.legend()
ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig('/tmp/latency_comparison.png', dpi=150)
plt.show()

# 结论:
# Cilium eBPF 相比 kube-proxy:延迟降低 70-80%
# Cilium eBPF 相比 Istio sidecar:延迟降低 60-80%
# Cilium + Istio 无 sidecar 模式:兼顾安全和性能

7.2 吞吐量对比

测试环境:
- 节点规格:16核 CPU,32GB 内存
- 网络:10Gbps
- 测试工具:iperf3
- 测试时长:每场景 60 秒

测试结果:
┌─────────────────┬────────────┬────────────┬─────────────┐
│ 方案             │ TCP 吞吐量  │ CPU 使用率  │ 延迟 P99    │
├─────────────────┼────────────┼────────────┼─────────────┤
│ kube-proxy       │ 8.2 Gbps   │ 45%        │ 1.8ms       │
│ Cilium eBPF      │ 9.4 Gbps   │ 12%        │ 0.3ms       │
│ Cilium + WireGuard│ 9.1 Gbps  │ 18%        │ 0.4ms       │
└─────────────────┴────────────┴────────────┴─────────────┘

结论:Cilium eBPF 吞吐量提升 15%,CPU 使用率降低 73%

八、总结与升级路径

8.1 核心结论

  1. eBPF 是内核网络安全的未来:它让自定义策略的执行从用户空间移到内核空间,零拷贝、零延迟。

  2. Cilium 是 Kubernetes 网络的终极方案:它集 CNI、NetworkPolicy、可观测性于一身,不需要 Sidecar,不需要 kube-proxy。

  3. Hubble 让网络可见性达到前所未有的水平:通过 eBPF 追踪每个连接的 verdict,且零开销。

  4. 升级路径建议:从 kube-proxy 平滑迁移到 Cilium,不影响现有服务,灰度验证后再全量。

8.2 升级路线图

Phase 1(第 1-2 周):概念验证

  • 在测试环境部署 Cilium
  • 验证与现有 CNI 的兼容性
  • 测试基本网络连通性

Phase 2(第 3-4 周):功能验证

  • 部署 CiliumNetworkPolicy
  • 验证 Hubble 可观测性
  • 测试 Hubble UI 和 CLI

Phase 3(第 5-8 周):生产灰度

  • 在非关键节点安装 Cilium
  • 逐步迁移流量
  • 监控性能指标

Phase 4(第 9-12 周):全量切换

  • 关闭 kube-proxy(可选)
  • 启用高级安全功能
  • 建立运维 SOP

参考资源

推荐文章

初学者的 Rust Web 开发指南
2024-11-18 10:51:35 +0800 CST
Shell 里给变量赋值为多行文本
2024-11-18 20:25:45 +0800 CST
html一份退出酒场的告知书
2024-11-18 18:14:45 +0800 CST
开源AI反混淆JS代码:HumanifyJS
2024-11-19 02:30:40 +0800 CST
程序员茄子在线接单