WEBKT

Cilium eBPF 容器网络策略实战:从 L7 细粒度控制到 Hubble 流量排查

33 0 0 0

在 Kubernetes 默认的网络模型中,传统的网络安全策略(NetworkPolicy)主要依赖 iptables 或 IPVS。当集群规模达到数百个节点、数万个 Pod 时,iptables 规则链的线性匹配会导致网络延迟急剧上升,且动态更新时的刷表动作也会造成 CPU 抖动。

Cilium 通过 eBPF(Extended Berkeley Packet Filter)技术,直接在 Linux 内核沙盒中处理网络数据包,绕过了复杂的 iptables 协议栈。这不仅带来了近乎线性的性能表现,还提供了极其强大的 L7(应用层)感知能力和 Hubble 深度可观测性。

下面将结合生产环境实际需求,分享如何基于 Cilium 落地高效的网络策略,并利用 Hubble 进行流量可视化与故障排查。


一、 Cilium 核心网络策略设计实践

Kubernetes 原生的 NetworkPolicy 仅支持 L3/L4(IP、端口)级别的控制。而 Cilium 提供了扩展的自定义资源:CiliumNetworkPolicy(CNP,命名空间级)和 CiliumClusterwideNetworkPolicy(CCNP,集群级)。

1. 默认拒绝(Default Deny)与渐进式放行

在开启任何安全隔离之前,推荐先对特定命名空间实施“默认拒绝”。这是建立零信任网络的基础。

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: default-deny-all
  namespace: prod
spec:
  description: "默认拒绝 prod 命名空间下的所有入站和出站流量"
  endpointSelector: {}
  ingress:
  - {}
  egress:
  - {}

注意:endpointSelector: {} 代表选中该 Namespace 下的所有 Pod。在生产环境执行此操作前,务必确保已梳理完必要的服务依赖。

2. 落地 L7 应用层网络策略

在微服务架构中,仅限制 IP 和端口是不够的。例如,支付服务(payment)只能允许订单服务(order)调用其 /charge 接口,而不能调用 /admin 接口。Cilium 可以直接解析 HTTP 协议来实现这种细粒度的控制:

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: restrict-payment-api
  namespace: prod
spec:
  endpointSelector:
    matchLabels:
      app: payment
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: order
    toPorts:
    - ports:
      - port: "8080"
        protocol: TCP
      rules:
        http:
        - method: "POST"
          path: "/charge"

原理解析:当配置了 L7 策略时,Cilium 会自动在节点上启动一个轻量级的 Envoy 代理(由 eBPF 自动重定向流量),在不改变业务代码的前提下,实现应用层协议的深度过滤。

3. 集群维度的全局策略(CCNP)

对于企业级基础设施,通常需要定义一些全局适用的规则,比如“允许所有 Pod 访问集群内部的 DNS 服务”,这时应该使用 CiliumClusterwideNetworkPolicy

apiVersion: "cilium.io/v2"
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: global-allow-dns
spec:
  endpointSelector: {} # 选中集群内所有 Pod
  egress:
  - toEndpoints:
    - matchLabels:
        "k8s:io.kubernetes.pod.namespace": kube-system
        k8s-app: kube-dns
    toPorts:
    - ports:
      - port: "53"
        protocol: UDP
      rules:
        dns:
        - matchPattern: "*"

二、 借助 Hubble 实现网络流量深度观测

配置了网络策略后,最头疼的问题莫过于“流量被拦截了,但不知道是哪条规则拦截的”。Cilium 的 Hubble 组件正是为了解决这一痛点而生。

1. 快速启用 Hubble

在安装 Cilium 时或通过 Helm 可以轻松启用 Hubble 及其 UI:

cilium upgrade --set hubble.enabled=true --set hubble.ui.enabled=true

2. Hubble CLI 实战:实时流量分析

Hubble CLI 是排查网络问题的利器。以下是几个最高频使用的命令:

  • 实时查看某个 Pod 的流量去向(类似分布式 tcpdump):

    hubble observe --pod prod/order-v1-5c8db9-abcde --follow
    
  • 过滤被网络策略丢弃(Dropped)的流量:

    hubble observe --pod prod/order-v1-5c8db9-abcde --type drop
    

    输出示例:

    Jan 22 10:14:02.123: prod/order-v1-5c8db9-abcde:43902 -> prod/payment-789f-xyz:8080 to-endpoint FORBIDDEN (Keys: policy-id=1003)
    

    通过 FORBIDDEN (Keys: policy-id=1003),你可以直接定位到是 ID 为 1003 的 Cilium 网络策略拦截了该流量。

  • 查看特定的 L7 HTTP 流量:

    hubble observe --http-path /charge --protocol http
    

3. Hubble UI 可视化拓扑

通过 cilium hubble port-forward 打开本地浏览器,Hubble UI 会以动态拓扑图的形式展现服务间的调用链。被网络策略拦截的请求会显式地标注为红色,并提供详细的丢包原因(如 Policy Denied),极大地降低了安全合规审计的门槛。


三、 Cilium eBPF 网络策略故障排查硬核指南

当网络发生异常,且 Hubble 无法给出直观解答时,我们需要深入 Cilium 代理(Cilium Agent)和 eBPF 映射表进行底层排查。

1. 确认 Pod 的 Endpoint 状态

Cilium 会为每个 Pod 分配一个唯一的 Endpoint ID。首先进入故障 Pod 所在的节点,查看 Cilium 维护的 Endpoint 状态:

# 获取 Cilium Agent Pod 名称
kubectl -n kube-system get pods -l k8s-app=cilium

# 进入指定节点的 Cilium Agent 执行诊断
kubectl -n kube-system exec -it cilium-xxxx -- cilium-dbg endpoint list

在输出的列表中,重点检查:

  • Identity(身份标识): Cilium 根据 Pod 标签计算出的安全身份(Security Identity)。如果标签不符合预期,Identity 就会出错。
  • Policy Ingress/Egress State(策略状态): 是否处于 Enabled(开启隔离)或 Disabled(放行所有)。

2. 检查底层的 eBPF Policy Map

Cilium 的底层策略决策并不是每次都去解析 YAML,而是编译成 eBPF 字节码并存放在内核的 Map 中。我们可以直接读取这些 Map 来确认策略是否真正下发到了内核。

# 查看指定 Endpoint 的 eBPF 策略规则
kubectl -n kube-system exec -it cilium-xxxx -- cilium-dbg monitor --type drop

上述命令会开启一个底层的事件监听器,直接捕获内核态丢弃的数据包。

如果需要查看具体的 Policy Map 内容,可以找到 Endpoint ID(假设为 1234),然后执行:

kubectl -n kube-system exec -it cilium-xxxx -- cilium-dbg map get cilium_policy_1234

这会输出当前内核中针对该 Pod 允许访问的对端 Identity 列表。如果该列表中没有目标服务的 Identity,说明策略配置有误或未成功同步。

3. 重建 BPF 规则与 Agent 重启

在极少数情况下,K8s API Server 与 Cilium Agent 的同步可能出现偶发性中断,导致内核 BPF Map 未能及时更新。通常,重启该节点上的 Cilium Agent 容器即可触发全量同步,且由于数据面(eBPF 字节码已驻留内核)与控制面分离,重启 Agent 不会中断现有的容器网络连接。

kubectl -n kube-system delete pod cilium-xxxx

四、 总结与最佳实践清单

  1. 先观测,后限制:在引入 CiliumNetworkPolicy 之前,先利用 Hubble 观察现有业务的流量拓扑,整理出白名单后再编写策略。
  2. 善用 Label 抽象:避免在网络策略中使用具体的 IP 地址,多利用 Kubernetes Labels 和 Namespace Selector,保持策略的弹性和动态扩展能力。
  3. 分层排查路径
    • 第一步:使用 hubble observe 定位流量是否被 Drop 以及对应的 Policy ID。
    • 第二步:使用 cilium-dbg endpoint list 检查 Pod 的安全身份(Identity)是否正确计算。
    • 第三步:使用 cilium-dbg monitor 观察内核态的数据包丢弃事件,确认底层 eBPF 行为。
云原生探路者 CiliumeBPFKubernetes

评论点评