在采用扁平网络的公有云 Kubernetes 集群里,Pod 直接拿 VPC 子网的私网 IP。只要集群没开网络策略,同一个 VPC 里的任意虚拟机都能绕过负载均衡器直连 Pod 端口;反过来,一旦某个带数据源代理或 Webhook 功能的 Pod(例如监控面板、低代码平台或带回调接口的业务服务)被拿下,它也能直接充当跳板,向集群内的 Vault(:8200)、节点 Kubelet(:10250)、同 VPC 的无密码 Redis(:6379)以及云主机元数据服务(169.254.169.254)发起探测。

给这类 Pod 加出入站限制时,很快会遇到一个选型问题:EKS 这类托管集群自带的 VPC CNI 已经内置了基于 eBPF 的原生 NetworkPolicy 支持,到底够不够用?如果团队同时维护多个云厂商的 Kubernetes 集群,还要配合 External Secrets Operator(ESO)和准入控制器做统一的 Policy as Code,要不要引入 Cilium?

答案取决于需求停在「封堵内网横向移动」,还是要进一步管住「按域名放行出站流量」与「跨云策略统一」。

标准 NetworkPolicy 能管住什么,管不住什么#

Kubernetes 原生的 networking.k8s.io/v1 NetworkPolicy 工作在三层和四层,选择器只有三种:podSelector、namespaceSelector 和 ipBlock(CIDR 网段),再配合协议与端口。

如果目标只是阻断 Pod 在内网横向探测,标准 NetworkPolicy 已经覆盖了主要场景:

  • 限制入站来源:例如只允许 monitoring 命名空间内部的组件访问 Prometheus(:9090)和 Alertmanager(:9093),阻断其他命名空间或同 VPC 虚拟机直连未加认证的管理接口(如 POST /-/quit 或 /api/v2/silences)。
  • 封禁私网出站与元数据地址:在 Egress 规则里用 ipBlock 放行 0.0.0.0/0,同时在 except 里排除 10.0.0.0/8、172.16.0.0/12、192.168.0.0/16 和 169.254.0.0/16。这样 Pod 仍然能发公网 HTTPS 请求,但无法触达集群内未显式放行的 Service、同 VPC 的数据库或节点 IMDS。

不过在托管集群里直接写标准 NetworkPolicy,有两类底层细节容易踩空,另有三件事是标准 API 本身做不到的。

云集群上用标准 NetworkPolicy 的两个细节#

第一个细节是 CNI 的策略开关默认可能是关着的。Kubernetes API Server 只负责把 NetworkPolicy 对象存进 etcd,不负责拦截流量;如果底层 CNI 没开策略控制器,kubectl apply 会正常返回成功,但规则不会生效。以 AWS EKS 的托管插件 vpc-cni 为例,虽然节点上的 aws-node DaemonSet 默认已经跑着 aws-eks-nodeagent 容器,但 kube-system/amazon-vpc-cni ConfigMap 里的 enable-network-policy-controller 默认是 "false",容器启动参数也是 --enable-network-policy=false,要在插件配置里显式打开才会开始下发 PolicyEndpoint。

第二个细节是 VPC 扁平网络里的源 IP 重叠与控制面代理路径:

  1. 当 Ingress 使用 AWS ALB 的 target-type: ip 模式时,ALB 的弹性网卡(ENI)落在公有子网里,直接向 Pod 端口发包。如果图省事在 NetworkPolicy 里用 ipBlock 放行整个公有子网 CIDR(例如 10.0.0.0/20),而同一个公有子网里恰好还跑着其他虚拟机,这些虚拟机照样能绕过 ALB 直连 Pod。此时要么只放行 ALB ENI 的 /32 地址,要么开启 VPC CNI 的 ENABLE_POD_ENI=true,用 SecurityGroupPolicy 按安全组 ID 放行。
  2. 日常运维如果习惯用 kubectl get --raw "/api/v1/namespaces/monitoring/services/prometheus-operated:9090/proxy/..." 查指标,请求包是由 EKS 控制面的跨账号 ENI 发往 Pod 的,不属于集群内任何 Namespace 的 Pod。入站策略如果只写了 podSelector,这条代理路径就会超时(改用走宿主机本机 Kubelet 的 kubectl port-forward 则不受影响,因为 VPC CNI 默认放行本节点宿主机与 Pod 的通信)。

标准 NetworkPolicy 管不住的三件事#

一旦需求超出固定 IP 和同集群 Label,标准 NetworkPolicy 就会触及边界:

  • 管不住动态 IP 的外部域名(FQDN Egress)。很多合法出站目标在 CDN 或云厂商动态负载均衡后面:监控面板要把告警发往 discord.com、从 Cloudflare 后面的 opensearch.example.com 查日志;ESO 要连 secretsmanager.ap-northeast-1.amazonaws.com 拉取密钥;业务 Pod 要调外部合作方的 HTTPS 接口。标准 NetworkPolicy 不认域名,一旦为了放行这些接口而打开公网 :443,攻击者就能借 httpbin.org 或自建公网 HTTPS 端点把容器里的数据带出去。
  • 没有原生的集群级兜底策略和 Audit 模式。标准 NetworkPolicy 是 Namespace 级别的,且只有强制执行(Enforce)一种状态。要想一条规则封死全集群所有 Namespace 访问 169.254.169.254,或者在上线前先观察一周「哪些合法流量会被误杀」,都得依赖各家 CNI 自己扩展的 CRD。
  • 各云厂商的扩展 CRD 互不通用。AWS VPC CNI 在 v1.21.0(2025-12-15 发布)引入了 ClusterNetworkPolicy(networking.k8s.aws/v1alpha1),GKE Dataplane V2 提供了 FQDNNetworkPolicy(networking.gke.io/v1alpha3),自建集群又是另一套。如果团队同时维护多个云的 Kubernetes 集群,试图做一套统一的 Policy as Code,策略模板就会按云厂商分叉。

四种方案逐项对照:云原生 CNI、Calico、出网代理与 Cilium#

把「云厂商原生 CNI」「独立出网代理」「Calico 开源版」和「Cilium 开源版」放在一起对比,各自的优缺点和能力边界如下:

对比维度 云厂商原生 CNI(以 AWS VPC CNI 为例) 原生 CNI + 显式出网代理(Envoy / Squid) Calico 开源版(Policy-only 或 CNI) Cilium 开源版(Chaining 或 CNI)
数据面实现 AWS 自研 eBPF(aws-eks-nodeagent,v1.14.0 于 2023-08-29 引入) 保持原生 CNI,集群内部署独立代理 Deployment iptables / nftables 或 eBPF(可挂在 VPC CNI 之上只跑 Felix) eBPF(TC / Socket 层挂载,加可选的节点级 DNS 与 Envoy 代理)
三四层隔离与防内网探测 支持标准 NetworkPolicy 支持标准 NetworkPolicy 支持标准 NetworkPolicy 与 NetworkPolicy 优先级 支持标准 NetworkPolicy 与身份感知策略
按域名放行出网(FQDN) 开源插件不支持(需买 AWS Network Firewall 等云服务) 支持(按 HTTP Host 或 TLS SNI 匹配域名白名单) 开源版不支持(域名策略属于商业版 Calico Enterprise / Cloud) 开源版原生支持(toFQDNs,通过内置 DNS 代理动态学习 IP)
集群级策略与优先级 ClusterNetworkPolicy(支持 Admin / Baseline 两级) 靠 Kyverno 为每个 Namespace 复制标准策略 GlobalNetworkPolicy(支持数值优先级与显式 Deny) CiliumClusterwideNetworkPolicy(支持显式 egressDeny / ingressDeny)
策略观察模式(Audit Mode) 原生支持 NETWORK_POLICY_ENFORCING_MODE=standard 与日志记录 代理层访问日志可单独做 dry-run 开源版仅支持 Log 动作,Staged Policy 属商业版 原生支持 Policy Audit Mode 与 Hubble 实时丢包流观测
七层协议过滤(HTTP 路径等) 不支持 仅对明文 HTTP 有效,HTTPS 需做 TLS 解密 开源版需配合 Istio / Dikastes 内置节点级 Envoy 支持 HTTP / gRPC / Kafka 规则
跨云 CRD 一致性 仅限单一云(绑定 networking.k8s.aws) 高(只用标准 K8s NetworkPolicy 加通用代理配置) 高(projectcalico.org/v3 跨云一致,但缺开源 FQDN) 高(cilium.io/v2 在 AWS、GCP、自建 K3s 通用)
存量集群引入与维护成本 最低(托管插件改一行参数即可) 低(普通业务 Pod,不动节点内核与 CNI) 中(需自己维护 DaemonSet 与版本升级) 中高(Chaining 模式需关注 CNI 升级兼容,替换模式需重建节点)

这四种方案在落地时的具体优缺点如下:

云厂商原生 CNI(AWS VPC CNI)#

优点是零额外组件和托管维护。在 EKS 1.35 加 Amazon Linux 2023(内核 6.12)的环境下,aws-eks-nodeagent 容器本来就随 vpc-cni 部署在每台节点上,开启策略不需要装任何新 Operator,也不会改变现有的 VPC IP 分配方式。

缺点是能力停在三四层和单云边界。它解决不了动态域名出网白名单,扩展 CRD 也只能留在 AWS 用。

原生 CNI 加显式出网代理(Envoy 或 Squid)#

优点是不动底层网络数据面。做法是用标准 NetworkPolicy 把业务 Pod 的公网出站全部封死,只允许它们连集群内 egress-proxy 命名空间的 Envoy 或 Squid Pod;只有这个代理 Pod 允许访问公网 :443,并在代理配置里按 TLS SNI 或 HTTP Host 校验域名白名单(比如只放行 discord.com 和 *.amazonaws.com)。这套做法只用标准 Kubernetes API,跨云通用,升级集群时不存在 CNI 兼容性风险。

缺点是侵入应用配置。每个需要出网的组件都得支持并配置 HTTPS_PROXY / NO_PROXY 环境变量;遇到忽略系统代理环境变量的 SDK 或二进制工具,改造起来比较烦琐。

Calico 开源版#

优点是策略表达力成熟、支持显式 Deny 与数字优先级。Calico 的 GlobalNetworkPolicy 在写复杂的多租户隔离规则时很直观,而且在 EKS 上支持「只装 Felix 策略引擎、保留 AWS VPC CNI 分配 IP」的叠加装法。

缺点是开源版没有 toFQDNs。很多人选型时容易混淆 Calico 开源版和商业版:Calico 官方文档里基于域名的出站策略属于 Calico Enterprise / Calico Cloud 付费功能。如果核心诉求是开源方案下的域名级出站控制,装 Calico 开源版解决不了问题。

Cilium 开源版#

优点是把「跨云统一 CRD」「开源 toFQDNs 域名控制」「Hubble 可观测性」和「跨集群 ClusterMesh」合在了一起:

  1. 透明的域名级出站白名单:Cilium 在开源版里直接提供 toFQDNs。Pod 照常发起 DNS 请求和 HTTPS 连接,无需配 HTTPS_PROXY;Cilium 的 DNS Proxy 拦截 :53 响应,把域名解析出的 IP 动态写入该 Pod 的 eBPF 放行表。
  2. 跨云 Policy as Code 底座:不管是自建 K3s、AWS EKS 还是其他云集群,同一份 CiliumClusterwideNetworkPolicy 和 CiliumNetworkPolicy 都能用 GitOps 统一同步;而在 GCP GKE 上,官方的 GKE Dataplane V2 底层本来就是 Google 托管的 Cilium。
  3. 排障与审计体验好:配合 Hubble CLI 或 UI,可以直接按 Pod 或判决结果(DROPPED / AUDIT)实时看哪条连接被哪条策略拦了,省去了翻节点日志或抓包的麻烦。

缺点也很实在,主要集中在存量集群的接入复杂度和七层代理开销:

  1. 存量云集群的接入模式有取舍:新建集群从第一天就用 Cilium 最干净;但对于已经在跑业务的存量 EKS 集群,如果用 Cilium 替换 vpc-cni,需要重规划 Pod IP 管理并全量滚动重建节点;如果用 CNI Chaining 模式(cni.chainingMode=aws-cni,让 vpc-cni 管 IP、Cilium 管策略),虽然不用换 IP,但每次升级 EKS 控制面或 vpc-cni 插件前,都得先在测试集群验证链式挂载有没有兼容性问题。
  2. 开启七层 HTTP 策略会拉起节点级 Envoy:一旦在 CiliumNetworkPolicy 里写了 rules.http(按 URL Path 或 Method 过滤),Cilium 会把对应流量透明劫持到节点上的 Envoy 进程。这不仅增加每台节点的常驻内存开销,一旦 Envoy 重载或异常,经过它的长连接(如 WebSocket、gRPC)还会跟着抖动;而且对外访问的 HTTPS 流量本身是加密的,节点 Envoy 在不配证书解密的前提下也看不到加密包里的 HTTP 路径。
  3. DNS 代理与 TTL 边界:toFQDNs 要配合显式放行 :53 的 rules.dns 才能工作,因为只有挂了 rules.dns 的端口规则,Cilium 才会把 DNS 请求导进内置的 DNS Proxy 记录域名与 IP 的映射。如果应用绕过集群 DNS(比如直连外部 DoH 或写死 IP),或者上游 CDN 极短 TTL 切换 IP 时连接刚好跨过缓存过期窗口,偶尔需要调大 toFQDNs.minTTL。

什么时候该留在原生 CNI,什么时候值得引入 Cilium#

把上面的权衡收拢成一条决策路径:

flowchart TB Q1["是否需要跨多云统一 CRD
或大量使用动态域名出站白名单"] -->|"否:单云且只需三四层隔离"| A1["留在云厂商原生 CNI
(如开启 VPC CNI NetworkPolicy)"] Q1 -->|"是"| Q2["需要出网的组件是否只有一两个
且都支持配置 HTTPS_PROXY"] Q2 -->|"是,不想动节点 CNI"| A2["原生 CNI + 集群内 Envoy/Squid 出网代理"] Q2 -->|"否,组件多或要求透明拦截"| Q3["集群是新建还是存量生产"] Q3 -->|"新建集群 / K3s"| A3["直接用 Cilium 作为主 CNI"] Q3 -->|"存量 EKS 集群"| A4["Cilium Chaining 模式(aws-cni)
仅开 L3/L4 + toFQDNs + Audit"]

留在云厂商原生 CNI 的场景#

如果集群都在同一家云上(例如全在 AWS EKS),且眼前的任务只是「把监控组件和业务 Namespace 隔开、禁止 Pod 访问私网和 IMDS」,直接启用 vpc-cni 自带的网络策略就够了。

在 Terraform 里给 aws_eks_addon 加上 configuration_values 即可开启:

resource "aws_eks_addon" "vpc_cni" {
  cluster_name                = module.eks.cluster_name
  addon_name                  = "vpc-cni"
  resolve_conflicts_on_create = "OVERWRITE"
  resolve_conflicts_on_update = "OVERWRITE"

  configuration_values = jsonencode({
    enableNetworkPolicy = "true"
    nodeAgent = {
      enablePolicyEventLogs = "true"
    }
  })
}

开启后,一条标准的 NetworkPolicy 就能把 Grafana 这类面板的出站锁在集群内 Prometheus 和公网 HTTPS 上,封死它去探测内网 Vault(:8200)、节点 Kubelet(:10250)或内网 Redis 的路径:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: restrict-grafana-egress
  namespace: monitoring
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: grafana
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53
    - to:
        - podSelector:
            matchExpressions:
              - key: app.kubernetes.io/name
                operator: In
                values: ["prometheus", "alertmanager"]
      ports:
        - protocol: TCP
          port: 9090
        - protocol: TCP
          port: 9093
    - to:
        - ipBlock:
            cidr: 0.0.0.0/0
            except:
              - 10.0.0.0/8
              - 172.16.0.0/12
              - 192.168.0.0/16
              - 169.254.0.0/16
      ports:
        - protocol: TCP
          port: 443

值得引入 Cilium 的三个条件#

当架构演进触及下面三个条件中的任意两个时,继续用「标准 NetworkPolicy 加手工打补丁」会比引入 Cilium 更累:

  1. 多云 Kubernetes 集群需要同一套 Policy as Code。团队同时管着 AWS EKS、其他公有云 Kubernetes 和自建 K3s,希望在同一个 GitOps 仓库里用 Kyverno 或 OPA 配合同一套网络策略 CRD 管理所有集群的基线,而不是为每个云写一套专属 CRD。
  2. 多个组件需要透明的域名级出站白名单(toFQDNs)。除了监控告警发往 discord.com、查 opensearch.example.com,集群里的 ESO 还要连云厂商的 Secrets Manager 域名同步密钥,业务服务还要调几十个外部合作方域名,且不希望到处维护 HTTPS_PROXY。
  3. 需要全局策略观察期(Audit Mode)和可视化排障(Hubble)。存量业务之前没有网络策略,直接切默认拒绝风险太高,需要先开 Audit 模式跑完至少一次完整发布周期,看着 Hubble 的丢包统计确认没有误伤再切强制执行。

两种落地做法对比:CNI Chaining 模式与完全替换 CNI#

决定引入 Cilium 之后,立刻会面临第二个分水岭:是用它**完全替换(Standalone)集群原有的 CNI,还是以链式调用(Chaining)**模式挂在现有 CNI 后面?

两者在职责边界、数据面性能与运维风险上的对比如下:

对比维度 CNI Chaining 模式(以 AWS VPC CNI 为例) 完全替换 CNI 模式(云 ENI IPAM 或 Overlay)
网络生命周期与 IPAM 云厂商 CNI 负责申请 IP、建 veth 网卡并配路由;Cilium 仅在网卡就绪后挂载 eBPF Cilium 独占整个生命周期:自主申请 IP、创建 veth、配置路由
kube-proxy 替代 保留 kube-proxy(链式模式下通常关闭 kubeProxyReplacement) 可彻底关闭并卸载 kube-proxy(开启 kubeProxyReplacement=true)
eBPF 性能加成 依赖主 CNI 的网络栈,无法使用激进的 eBPF Host Routing 直接转发 纯净 eBPF 数据面,支持 Host Routing 绕过 iptables,支持 XDP 加速
云平台 IAM 权限 Cilium 无需任何云平台 VPC 或 EC2 管理权限 云 ENI 模式下 Cilium Operator 必须持有申请和挂载 ENI 的高权限
存量集群迁移成本 较低(存量节点无需排水,下发 DaemonSet 即可对后续 Pod 生效) 较高(存量节点无法平滑热切,需新建节点池逐步排水迁移)
长期升级与维护隐患 存在两套 CNI 插件打架风险(如升级时 conflist 配置文件被覆盖) 单一网络责任主体,无插件链冲突,但需自理底层 CNI 的所有运维

Chaining 模式的运行机制与潜在隐患#

在 Chaining 模式下,节点上的 /etc/cni/net.d/ 会维护一个插件列表文件(如 10-aws.conflist)。Kubelet 创建 Pod 时,先调用主 CNI(如 aws-cni)在宿主机和容器之间建立 veth 对并分配 VPC IP;主 CNI 返回成功后,紧接着调用 cilium-cni。Cilium 此时不碰 IPAM,只负责把预编译好的 eBPF 程序挂载到该 veth 网卡上,从而实现网络策略检查与流量采集。

这种模式在存量集群上落地的代价最小,但有两个长期隐患需要关注:

  1. 配置覆盖引发的创建卡顿:当托管集群升级控制面或升级主 CNI 插件版本时,云厂商的自动化控制器有时会重新下发默认的 CNI 配置文件,把包含 Cilium 的 .conflist 覆盖回单插件的 .conf。一旦发生覆盖,新创建的 Pod 就不会挂载 Cilium 的 eBPF 程序,甚至出现 Pod 停留在 ContainerCreating 状态。
  2. eBPF 极致性能无法解锁:由于网卡拓扑和内核路由由主 CNI 决定,Cilium 无法启用 bpf.masquerade=true 或 bypass 宿主机网络栈的 Host Routing 快速路径,所有出入站流量依然要老老实实走一遍内核 netfilter 和路由查找。

完全替换模式的适用边界#

在完全替换模式下,Cilium 成为集群内唯一的 CNI。如果是在 AWS 环境并采用 ipam: eni 模式,Cilium Operator 会直接通过 AWS SDK 调用 EC2 接口为节点申请辅助 ENI 和私网 IP,直接给 Pod 分配 VPC 原生地址。

这种模式架构清晰,能完整享受 eBPF 替代 kube-proxy、Socket 层负载均衡和绕过内核栈直接转发的性能优势,也不会发生多插件配置覆盖的事故。但它的落地门槛很高:对于已有业务在跑的生产集群,无法原地换掉正在分配 IP 的 CNI,必须通过新建独立节点组、逐批驱逐工作负载的方式滚动迁移;同时 Cilium Operator 需要配置独立的云厂商 IAM Role,授予 ec2:CreateNetworkInterface、ec2:AttachNetworkInterface 等一系列高权限。

云上使用 Cilium ENI 模式的四个生产配置细节#

如果决定从第一天起就完全替换原生 CNI(使用 ipam: mode: eni),根据 Isovalent 官方指南 以及业界在大规模生产集群上的落地经验,有四个关键配置直接决定了后续的稳定性和运维成本:

  1. 开启前缀委派(Prefix Delegation)避免 API 限流:在默认的二级 IP 模式下,每个 Pod 都需要独立申请一个私网 IP,这会导致 Cilium Operator 高频调用 AWS EC2 API,在集群突发扩容时极易触发 RequestLimitExceeded 限流错误。配置 eni.awsEnablePrefixDelegation: true 后,Cilium 会一次性向 AWS 申请 /28 规格的 IPv4 前缀(每段包含 16 个 IP),大幅降低 API 调用频率,同时显著提高单个节点的 Pod 容纳密度(参考 AWS 官方前缀配置指南)。
  2. 开启空闲 IP 自动释放(awsReleaseExcessIPs)防止子网耗尽:如果不打开 eni.awsReleaseExcessIPs: true,在业务高峰扩容、随后缩容后,节点已经释放的前缀不会自动退还给 VPC 子网,导致少量节点长期霸占大量子网 IP,甚至引发 VPC IP 枯竭。
  3. 给节点配置初始化污点防 Pod 抢跑:在节点加入集群时,Kubelet 会先启动,而 Cilium Agent 挂载 eBPF 与配置 IPAM 需要短暂时间。在节点引导参数中配置污点 node.cilium.io/agent-not-ready:NoSchedule,由 Cilium 初始化就绪后自动移除,防止业务 Pod 在网络就绪前被调度上去导致崩溃。
  4. 存量集群采用 Blue/Green 节点池平滑迁移:对于已有业务在跑的集群,不要尝试在存量节点上原地切换 CNI。成熟的迁移方式是给原有节点打上标签并给旧 CNI(如 aws-node)设置节点亲和性,新建独立的节点组部署 Cilium,通过分批驱逐工作负载平滑过渡。

另一个常见分歧:要不要直接上 Istio 或 Linkerd 这类 Service Mesh?#

在讨论出网控制和网络隔离时,另一个经常被拿出来比较的选项是 Service Mesh。之所以很多团队会在 Cilium 和 Istio / Linkerd 之间犹豫,是因为 Cilium 官方也在主推「Cilium Service Mesh(无 Sidecar 模式)」,两者在「出网域名白名单」、「mTLS 加密」和「L7 访问控制」上看起来功能非常相似。

把它们放在一起对比,底层分工和代价模型其实有很大差异:

维度 Cilium(CNI / 内核层) 传统 Sidecar 模式(Istio / Linkerd) 新一代 Sidecarless 模式(Istio Ambient)
控制点与主战场 内核与网络层(L3/L4 + eBPF),可选拉起节点级 Envoy 应用网络层(L7 为主),每个 Pod 强制注入 Sidecar 容器 分层网络:节点级 ztunnel(L4)+ 按需独立 Waypoint Pod(L7)
域名出站管控(防 SSRF) toFQDNs 拦截 DNS :53,动态放行 IP,应用完全无感 依赖 ServiceEntry + Egress Gateway,依赖 iptables 劫持到 Envoy 类似传统 Istio,但四层拦截由 ztunnel 统一处理
mTLS 与身份粒度 WireGuard/IPsec 透明加密;Mutual Auth 主要做握手鉴权 原生 X.509 证书绑定 SPIFFE ID,每条连接应用层鉴权与加密 ztunnel 原生处理应用间 mTLS,证书由控制面按需轮换
资源与性能损耗 极低(不进用户态代理);开七层策略时每节点常驻一个 Envoy 较高,Pod 数量多时存在显著的内存放大(每个 Pod 几十上百 MB) 低到中等,节点 ztunnel 常驻内存小,按需拉起 Waypoint
微服务高级治理 支持基础路由与 Ingress,但非核心强项 行业标杆(权重切流、故障注入、分布式追踪头注入) 继承传统 Istio 完整的微服务治理能力

选型侧重点:出站管控 vs 深度应用治理#

如果团队的核心痛点只是「封堵内网横向探测(SSRF)」和「透明放行特定外部域名(如各类外部 API、云端密钥管理服务或通知服务)」,优先选 Cilium 会轻松得多:

  • 没有 Sidecar 内存税:无需在每个业务 Pod 里常驻一个 Envoy 容器,集群即便有几千个 Pod 也不用承受巨大的内存开销放大。
  • 协议透明无侵入:Cilium 的 toFQDNs 本质上还是在内核层根据 DNS 响应动态维护 IP 过滤规则,不会破坏非 HTTP 协议或长连接(如数据库长连接、Redis、gRPC 等)的原本语义。

什么时候必须引入 Istio 或 Linkerd?只有当业务需求进入了深水区的应用层治理:

  1. 严格的端到端应用身份鉴权:要求调用链上的每一跳都必须由 X.509 证书携带 SPIFFE ID,在七层严格校验「只有服务 A 的身份才能调服务 B 的特定 URL 路径」;
  2. 复杂的微服务流量调度:需要根据 HTTP Header 灰度切流、做跨集群金丝雀发布、或者主动注入故障与请求重试;
  3. 分布式链路追踪上下文透传:希望在不需要应用代码配合的前提下,由代理层自动串联 Trace ID。

两者在现代云原生架构中并不互斥。业界非常多的大规模实践是让 Cilium 负责底座(跨云网络打平、高性能 eBPF 路由、节点级防 SSRF 与 toFQDNs 域名出网),在上层核心业务链路上按需挂载 Istio Ambient 或 Linkerd 负责应用级 mTLS 与流量治理。

存量云集群引入 Cilium 的两个避坑选择#

如果评估下来决定引入 Cilium,落地时克制使用它的功能范围,能避开绝大部分稳定性隐患。

存量 EKS 用 Chaining 模式,关掉原生 CNI 的策略开关#

在存量 EKS 集群上,按 Cilium 官方的 AWS CNI Chaining 指南部署 cni.chainingMode=aws-cni 时,Pod 的网卡创建和 VPC IP 分配仍然归 AWS vpc-cni 管,Cilium 只往容器的 veth 网卡上挂 eBPF 程序。

这里有一条硬前提:保持 AWS vpc-cni 自己的 enableNetworkPolicy = "false"。不要同时打开 vpc-cni 的 aws-eks-nodeagent 策略执行和 Cilium 的策略执行,两个 eBPF 策略引擎同时挂在同一张网卡上会让排障变得非常困难。

只用三四层加 toFQDNs,不拿节点 Envoy 做七层 SSRF 防护#

用 Cilium 防 SSRF 和数据外带时,把范围控制在 L3/L4 加 DNS Proxy(toFQDNs) 这一层性价比最高:

  • 应用层自身的白名单(例如 Grafana 的 [security] data_source_proxy_whitelist、禁止在线安装非预期插件、收紧 ServiceAccount RBAC)照常在应用配置里做;
  • 网络层用 CiliumClusterwideNetworkPolicy 的 egressDeny 一行封死所有非系统 Pod 访问 169.254.169.254/32 和节点 Kubelet 端口;
  • 对需要出公网的组件,用 CiliumNetworkPolicy 的 toFQDNs 精确锁死目标域名,不开启 rules.http 七层路径过滤,从而避开节点级 Envoy 代理的内存与连接开销:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: grafana-egress-fqdn
  namespace: monitoring
spec:
  endpointSelector:
    matchLabels:
      app.kubernetes.io/name: grafana
  egress:
    - toEndpoints:
        - matchLabels:
            io.kubernetes.pod.namespace: kube-system
            k8s-app: kube-dns
      toPorts:
        - ports:
            - port: "53"
              protocol: ANY
          rules:
            dns:
              - matchPattern: "*"
    - toEndpoints:
        - matchExpressions:
            - key: app.kubernetes.io/name
              operator: In
              values: ["prometheus", "alertmanager"]
      toPorts:
        - ports:
            - port: "9090"
            - port: "9093"
    - toFQDNs:
        - matchName: "discord.com"
        - matchName: "opensearch.example.com"
        - matchName: "hc-ping.com"
      toPorts:
        - ports:
            - port: "443"
              protocol: TCP

配合 Kyverno 或 OPA 做 Policy as Code 时,两边的职责边界也很清楚:准入控制器负责校验静态声明(例如镜像签名、runAsNonRoot、限制业务 Namespace 的 ESO ExternalSecret 只能引用对应环境的 SecretStore),并在新建 Namespace 时自动生成基线 CiliumNetworkPolicy;Cilium 负责在运行时按身份和域名执行出入站拦截。

小结#

只在一个云厂商的集群里做基础的三四层隔离和防内网探测时,开启云厂商原生 CNI 的 NetworkPolicy 开关(如 AWS VPC CNI 的 enableNetworkPolicy)就能拦住 Pod 扫集群内部服务、同 VPC 私网和云主机元数据,不需要为此引入 Cilium。等到团队面对跨多云集群的 Policy as Code 统一治理、需要用 toFQDNs 透明管控大量动态域名出站(如 ESO 拉云端密钥、监控发外部通知、业务调第三方接口),或者需要 Audit 模式与 Hubble 流量观测时,Cilium 才真正省事。在存量云集群落地时,优先采用 CNI Chaining 模式并只启用三四层加 toFQDNs,把应用层路径收敛交给应用自身配置和准入控制,能兼顾安全边界与运行稳定性。

相关文章#

参考资料#