← 返回蜂巢洞察

Kubernetes网络机制解析:从ClusterIP到Cilium服务网格

以下是一些大多数Kubernetes教程都不会告诉你的内容:绝大多数工程师都能够使用 kubectl expose 命令,但其中不到10%的人真正了解这个命令执行后会带来什么效果。 我在超过10家公司中解决过与Kubernetes网络相关的问题,每次都会遇到同样的知识盲区。工程师们并不明白ClusterIP在底层是如何工作的,也不理解为什么不同命名空间中的Pod能够默认互相通信,更不清楚CNI插件在内核层究竟起到了什么作用。 本教程正是为了解决这些问题而设计的。你将从中系统地学习Kubernetes网络的工作原理:了解Pod的IP地址是如何分配的,以及这些地址为何能够在不同的节点之间正常使用;

以下是一些大多数Kubernetes教程都不会告诉你的内容:绝大多数工程师都能够使用kubectl expose命令,但其中不到10%的人真正了解这个命令执行后会带来什么效果。

我在超过10家公司中解决过与Kubernetes网络相关的问题,每次都会遇到同样的知识盲区。工程师们并不明白ClusterIP在底层是如何工作的,也不理解为什么不同命名空间中的Pod能够默认互相通信,更不清楚CNI插件在内核层究竟起到了什么作用。

本教程正是为了解决这些问题而设计的。你将从中系统地学习Kubernetes网络的工作原理:了解Pod的IP地址是如何分配的,以及这些地址为何能够在不同的节点之间正常使用;理解kube-proxy是如何利用iptables规则来实现ClusterIP功能的;明白Ingress控制器是如何通过单一负载均衡器来路由外部流量的;了解Network Policies是如何帮助实现微分割机制以满足SOC2安全标准的;最后还会学习Cilium是如何利用eBPF技术来替代这些传统机制,从而提供更快、更易于监控且更安全的解决方案。

读完本教程后,你将能够解决“为什么我的Pod无法与某个服务通信”这样的问题,能够配置符合SOC2 CC6.1标准的默认拒绝策略,也能够在选择适合自己集群的CNI插件时做出明智的决定。

目录

你将学到的内容

  • Pod的IP地址、容器网络模型,以及CNI插件是如何分配地址的

  • kube-proxy如何利用iptables实现ClusterIP功能,以及为什么eBPF技术更高效

  • Ingress控制器:如何通过单一负载均衡器来路由所有外部流量

  • Network Policies:零信任网络环境下的默认拒绝规则与针对特定服务的允许规则

  • CNI插件比较:Cilium、Calico与AWS VPC CNI,以及它们各自适用的场景

  • 服务网格:Cilium、Istio与Linkerd在TLS加密与可观测性方面的优势对比

让我们开始吧。

先决条件

在继续学习之前,您需要具备以下条件:

知识要求:

  • 对Kubernetes有基本的了解:能够部署Pod并创建Service

  • 掌握基本的Linux网络概念:知道IP地址和端口的含义

  • 大致了解负载均衡器的功能

工具与访问权限:

  • 一个正在运行的Kubernetes集群(可以是EKS、GKE,或者通过kind搭建的本地集群)

  • 配置好并指向您的集群的kubectl

  • 已安装版本为3的helm(用于第4部分中Cilium的安装工作)

  • 从第4部分开始:需要在您的集群上安装Cilium(使用命令helm install cilium cilium/cilium

关于CNI的说明:第1至3部分的内容适用于任何Kubernetes集群,无论其是否使用了CNI;而第4至6部分则会用到与CILium相关的资源(如CiliumNetworkPolicy、Hubble)。如果您使用的CNI版本不同,这些概念本身是相同的,只有YAML语法会有所差异。

第1部分:Pod的IP地址与容器网络模型

1.1 为什么每个Pod都会拥有自己的IP地址

Kubernetes的网络模型有一条基本原则:每个Pod都会获得一个唯一的IP地址,而且所有Pod都可以使用这些IP地址相互通信——无需借助网络地址转换技术。

这与Docker的默认工作方式不同。在Docker中,容器会共享主机网络或通过端口映射进行通信;而在Kubernetes中,Pod之间并不会进行端口映射。例如,IP地址为10.244.1.2的Pod A可以直接与位于另一个节点上的IP地址为10.244.2.3的Pod B通信,而且源IP地址也会保持不变。

您可以亲自在您的集群上验证这一点:

# 列出所有命名空间中的Pod及其IP地址和所在节点
kubectl get pods -o wide --all-namespaces

预期输出结果如下:

NAMESPACE     NAME                                READY   STATUS    IP            NODE
production    payment-api-5d6b8d8c4f-abc12        1/1     Running   10.244.1.2    node-1
production    user-api-5d6b8d8c4f-def34           1/1     Running   10.244.2.3    node-2
production    redis-master-0                      1/1     Running   10.244.1.4    node-1

每个Pod都拥有唯一的IP地址。位于node-1上的payment-api和位于node-2上的user-api可以通过这些IP地址直接相互通信。请注意,这些IP地址属于10.244.0.0/16这个CIDR范围——这就是专门为Pod们设计的独立网络。

1.2 CNI插件到底起到了什么作用

容器网络接口(CNI)就是负责让Kubernetes的网络模型正常运行的插件。当一个新的Pod被调度到某个节点上时,Kubernetes的kubelet会调用CNI插件,而该插件会执行以下四项操作:

  1. 为Pod创建一个新的网络命名空间,从而为其提供一个隔离的网络环境。

  2. 创建一对虚拟以太网设备(`veth`):其中一端位于Pod的命名空间内,另一端连接在节点上。

  3. 从集群中的Pod CIDR地址范围内为这对虚拟以太网设备中的一端分配一个IP地址。

  4. 添加路由规则,使节点能够访问集群中其他所有Pod的IP地址。

如果没有CNI,Pod们将无法进行网络通信;而有了CNI,这种扁平化的Pod网络模型才能真正得以实现。

请检查您的集群上安装了哪些CNI插件:

# 列出节点上安装的CNI二进制文件
ls /opt/cni/bin/

以下是一些常见的CNI插件及其适用场景:

CNI插件 默认是否在集群中启用? 主要用途
AWS VPC CNI 是(适用于EKS环境) Pod能够获得真实的VPC IP地址,非常适合与AWS原生系统集成。
Calico 支持高级网络策略及BGP路由功能。
Cilium 基于eBPF的技术,支持第7层网络规则、服务网格功能,并符合SOC2安全标准。

1.3 验证Pod之间的通信能力

最基本的网络测试方法是:在一个Pod中执行命令,然后通过IP地址 ping另一个Pod。

# 步骤1:获取目标Pod的IP地址
TARGET_IP=$(kubectl get pod redis-master-0 -o jsonpath '{.status.podIP}')
echo "目标IP地址: $TARGET_IP"

# 步骤2:在另一个Pod中执行命令并ping目标Pod
kubectl exec -it payment-api-5d6b8d8c4f-abc12 -- ping -c 3 $TARGET_IP

预期的输出结果如下:

PING 10.244.1.4 (10.244.1.4): 56 data bytes
64 bytes from 10.244.1.4: icmp_seq=0 ttl=62 time=0.8ms
64 bytes from 10.244.1.4: icmp_seq=1 ttl=62 time=0.7ms
64 bytes from 10.244.1.4: icmp_seq=2 ttl=62 time=0.9ms

如果这个测试能够成功完成,说明CNI插件工作正常;如果失败,请检查是否有网络策略阻止了ICMP流量的传输(第4部分会介绍相关内容)。

需要记住的一点是:每个Pod都会被分配一个IP地址,Pod们可以使用这些IP地址直接进行通信。而CNI插件正是实现了这两点功能。

第2部分:服务——ClusterIP、NodePort与LoadBalancer

2.1 问题所在:Pod的IP地址不稳定

每当Pod重启时,它的IP地址都会发生变化。如果您部署了支付API的新版本,那么旧的Pod会被删除,新的Pod会使用新的IP地址重新创建。因此,那些原本配置为调用旧IP地址的服务现在就会出现无法正常工作的情况。

下面是一种错误的做法:在应用程序配置中直接硬编码Pod的IP地址。

# 错误的做法:在应用配置中直接使用Pod的IP地址
# 下次数据库Pod重启时,这个IP地址就会失效
apiVersion: v1
kind: Pod
metadata:
  name: payment-api
spec:
  containers:
  - name: api
    env:
    - name: DATABASE_HOST
      value: "10.244.1.4"  # 这个IP地址会在Pod重启后发生变化

在开发阶段,这种配置很容易出问题;而在生产环境中,它会导致严重的后果。任何将旧IP地址硬编码到应用程序中的情况,都会在Pod重启时引发问题——无论是由于节点资源耗尽、操作系统因内存不足而强制终止进程,还是部署过程中的变化。

2.2 服务是如何解决稳定性问题的

Kubernetes服务提供了Pod IP所无法实现的两点:一个稳定的IP地址(即ClusterIP),只要服务存在,这个IP地址就不会发生变化;以及一个稳定的DNS名称,其他Pod可以借助这个DNS名称来访问服务,而无需关心具体的IP地址是多少。

当你创建一个服务时,Kubernetes会从该服务的CIDR范围内为它分配一个虚拟的ClusterIP地址(例如10.100.0.0/16),同时会在CoreDNS中创建相应的DNS记录,其格式为..svc.cluster.local。此外,Kubernetes还会配置每个节点上的kube-proxy,使其添加相应的iptables规则,从而将来自ClusterIP的流量均匀分配到后端正常运行的Pod上。

正确的实现方式就是使用ClusterIP类型的服务。

# 正确的做法:使用ClusterIP服务
# 无论背后运行的是哪些Redis Pod,redis.production.svc.cluster.local始终会解析为10.100.0.1
apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: production
spec:
  selector:
    app: redis
    role: master   # 只有带有这些标签的Pod才会接收流量
  ports:
  - port: 6379        # 服务监听的端口
    targetPort: 6379  # Pod实际运行的端口
  type: ClusterIP     # 默认设置:仅能在集群内部访问

kube-proxy是如何通过iptables规则实现负载均衡的:当创建一个服务后,kube-proxy会在集群中的每个节点上添加相应的iptables规则。这些规则会拦截所有发往ClusterIP的流量,并将其重定向到后端正常运行的Pod上。你可以在某个节点上运行以下命令,查看这些规则的实际效果:

# 查看kube-proxy为redis服务创建的iptables规则
# 每一条KUBE-SEP记录代表一个Pod端点
sudo iptables -t nat -L KUBE-SERVICES | grep redis

预期的输出结果如下:

Chain KUBE-SVC-REDIS (1 references)
target          prot  source    destination
KUBE-SEP-AAA    all   anywhere  anywhere    /* production/redis */ statistic mode random probability 0.50
KUBE-SEP-BBB    all   anywhere  anywhere    /* production/redis */

通过这些iptables规则,发往Redis ClusterIP的流量会被平均分配到两个Pod端点上。当某个Pod重启并获得新的IP地址时,kube-proxy会自动更新相应的规则。

2.3 何时使用不同类型的服务

>
服务类型 DNS名称 可访问范围适用场景
ClusterIP redis.production.svc.cluster.local 仅限于集群内部 数据库、缓存服务、内部API
NodePort :30000–32767 节点IP地址加上端口号 本地开发、调试用途
LoadBalancer AWS ELB的DNS名称 互联网(通过云负载均衡器访问) 外部API、Web应用程序

验证服务是否正确地路由流量:

# 使用 kubectl describe service 命令查看服务的端点信息(即背后实际的 Pod IP 地址)
kubectl describe service redis -n production

预期输出结果如下:

名称:redis
命名空间:production
类型:ClusterIP
IP地址:10.100.0.1
端口:6379/TCP
目标端口:6379/TCP
端点信息:10.244.1.4:6379,10.244.2.5:6379
会话亲和性:无

如果“端点信息”中显示“”,说明该服务的选择器与任何正在运行的 Pod 都不匹配。这是 Kubernetes 中导致“连接被拒绝”错误的最常见原因。

需要记住的一点是:Pod 应始终通过服务的 DNS 名称进行连接,而 never 使用 Pod 的 IP 地址。服务会自动处理稳定性、负载均衡以及健康检查等相关任务。

第 3 部分:Ingress——外部流量路由

3.1 问题所在:为每个微服务配置负载均衡器成本高昂

每个LoadBalancer服务都会创建一个专用的云负载均衡器。在 AWS 上,每个应用负载均衡器的费用大约为 \(0.008/LCU小时 + 0.0225/小时的基本费用\),也就是说,每个负载均衡器每月的费用约为 16 至 27 美元。

如果有 20 个微服务,那么仅负载均衡器的费用就高达 320 至 540 美元/月,此外,每处理一个请求还需要额外支付 \(0.008/LCU\) 的费用。

以下是为每个微服务配置单独负载均衡器的错误做法:

# 错误做法:每次为新的微服务创建一个新的 AWS ALB
# 20 个微服务意味着需要创建 20 个 ALB,因此每月的费用至少为 300 至 500 美元
apiVersion: v1
kind: Service
metadata:
  name: payment-api
spec:
  type: LoadBalancer   # 会为每个微服务创建一个专用的 ALB
  ports:
  - port: 80
    targetPort: 8080

3.2 Ingress 控制器如何解决这个问题

Ingress 控制器是运行在集群内部的一个 Pod,它负责监控Ingress资源,并配置一个外部负载均衡器,以便根据主机名和 URL 路径将流量路由到不同的服务上。

例如,AWS 的 Load Balancer Controller 会为所有的 Ingress 资源创建一个统一的 ALB,然后通过设置监听规则,使得api.company.com/payments这个请求被路由到 payment 服务,而api.company.com/users这个请求则被路由到 user 服务,所有这些操作都是通过同一个负载均衡器来完成的。

正确的实现方式是:为所有的服务使用一个统一的 Ingress 资源。

# 正确做法:使用一个 Ingress 资源来路由所有外部流量
# 无论有多少个服务,都只需要创建一个 ALB
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shared-ingress
  namespace: production
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
    alb.ingress.kubernetes.io/ssl-redirect: "443"
spec:
  rules:
  - host: api.company.com
    http:
      paths:
      - path: /payments
        pathType: Prefix
        backend:
          service:
            name: payment-service
            port:
              number: 8080
      - path: /users
        pathType: Prefix
        backend:
          service:
            name: user-service
            port:
              number: 8080
  - host: dashboard.company.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: dashboard-service
            port:
              number: 3000
  tls:
  - hosts:
    - api.company.com
    - dashboard.company.com
    secretName: tls-wildcard-cert

请确认Ingress已配置完成,且ALB的DNS名称也已设置:

# 等待直到“ADDRESS”列显示ALB的DNS名称(通常需要2-3分钟)
kubectl get ingress shared-ingress -n production -w

预期输出结果如下:

NAME             CLASS   HOSTS                                    ADDRESS                                              PORTS
shared-ingress   alb     api.company.com,dashboard.company.com   k8s-prod-sharedin-abc123.us-east-1.elb.amazonaws.com   80, 443

成本对比如下:

方案 所需负载均衡器数量每月成本
每个微服务单独使用负载均衡器(共20个微服务) 20个ALB 约400美元/月
使用单个Ingress控制器 1个ALB 约27美元/月

需要记住的一点是:使用基于路径的路由机制,通过一个单独的负载均衡器为所有服务提供连接支持;而为每个微服务分别配置负载均衡器的方案仅适用于早期原型开发阶段。

第4部分:网络策略——微分段技术

4.1 默认设置:所有Pod之间都可以相互通信

Kubernetes在默认情况下不会对Pod之间的网络通信进行任何限制。前端Pod可以直接向数据库Pod发起API请求,分析服务也可以查询支付数据库的数据,甚至一个被入侵的Pod也可能扫描集群中的其他所有Pod。

这种设置显然不够安全。对于SOC2 CC6.1标准、HIPAA规范以及大多数企业级安全框架而言,必须确保网络流量仅限于必要的通信范围之内。

请确认当前环境中是否允许未经限制的跨Pod通信:

# 在没有网络策略配置的情况下,前端Pod与支付数据库之间的请求会成功执行
# 但在一个安全的环境中,这种行为是不被允许的
kubectl exec -it frontend-pod -n production -- \
  curl http://payment-postgres.production.svc.cluster.local:5432

如果您的集群中这一操作能够正常执行,那就说明当前没有实施任何网络分段措施。

4.2 解决方案:使用Cilium网络策略实施默认拒绝策略

正确的做法应该是采用“默认拒绝”策略:首先阻止所有Pod之间的通信,然后仅允许应用程序所需的特定通信路径被开放。

步骤1——应用默认拒绝策略:

# 该策略适用于命名空间中的所有Pod
# 默认情况下,它会阻止所有的入站和出站通信
# 注意:应用此策略后,所有Pod之间的通信都会立即被阻断
# 在在生产环境中应用此策略之前,请确保已经准备好了允许通行的规则
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  description: "默认情况下阻止所有Pod之间的通信——遵循零信任安全原则"
  endpointSelector: {}  # 适用于该命名空间中的所有Pod
  ingress:
  - {}                  # 空的入站规则表示拒绝所有入站请求
  egress:
  - {}                  # 空的出站规则表示拒绝所有出站请求

应用默认的“拒绝所有流量”策略会立即导致该命名空间内所有的Pod之间的通信中断。你可以在同一个`kubectl apply`命令中添加允许规则,或者先应用允许规则再进行后续操作。

步骤2——添加命名空间级别的隔离机制:

# 允许同一命名空间内的Pod之间进行通信
# 默认情况下禁止跨命名空间的流量传输
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-same-namespace
  namespace: production
spec:
  endpointSelector: {}
  ingress:
  - fromEndpoints:
    - matchLabels:
        io.kubernetes.pod.namespace: production
  egress:
  - toEndpoints:
    - matchLabels:
        io.kubernetes.pod.namespace: production

步骤3——为每个服务添加允许规则:

# 仅允许支付服务访问其所需的特定网络资源
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: payment-service-network-policy
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: payment-service
  egress:
  # 允许支付服务连接到postgres数据库的5432端口
  - toEndpoints:
    - matchLabels:
        app: postgres-db
    toPorts:
    - ports:
      - port: "5432"
        protocol: TCP
  # 允许支付服务外部访问Stripe API
  - toFQDNs:
    - matchName: "api.stripe.com"
    toPorts:
    - ports:
      - port: "443"
        protocol: TCP

4.3 使用Hubble验证策略并收集SOC2证据

Cilium内置了Hubble这一网络监控工具,它能准确显示哪些数据流被你的网络策略允许通过,哪些被拒绝。Hubble就是证明网络隔离机制正常运行的SOC2证据。

# 安装Hubble命令行工具
export HUBBLE_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/hubble/master/stable.txt)
curl -L --remote-name-all https://github.com/cilium/hubble/releases/download/$HUBBLE_VERSION/hubble-linux-amd64.tar.gz
tar xzvf hubble-linux-amd64.tar.gz
sudo mv hubble /usr/local/bin/

# 将Hubble代理端口映射到本地
kubectl port-forward -n kube-system svc/hubble-relay 4245:80 &

# 查看生产命名空间中过去一小时内的所有数据流
hubble observe --namespace production --since 1h

# 仅显示被拒绝的数据流——这能证明策略有效阻止了未经授权的访问
hubble observe --namespace production --verdict DROPPED --since 1h

以下是Hubble输出示例,展示了某个被阻止的连接尝试:

Apr 19 03:17:41.234   DROPPED   TCP   10.244.1.5:52341 → 10.244.1.4:5432   policy-deny
Apr 19 03:17:41.235   ALLOWED   TCP   10.244.1.2:43211 → 10.244.1.4:5432   allow-same-namespace

第一行显示了一个被阻止的未经授权的连接尝试,第二行则显示了一个被允许的合法连接。请每天将这类日志导出到你的SOC2证据存储桶中。

需要记住的一条规则是:默认拒绝原则才是零信任架构的基础。之后,为每条必要的通信路径添加明确的允许规则。Hubble能够为你提供这些规则是否有效运行的证据。

第5部分:CNI对比——Cilium vs Calico vs AWS VPC CNI

选择合适的CNI是一个难以改变的决定。在不同CNI之间进行迁移意味着需要清除集群中的所有节点并重新安装新的组件。因此,请务必基于正确的理由来做出这个决定。

以下是对那些对生产环境中的EKS集群来说至关重要的功能的实际对比:

功能 AWS VPC CNI Calico Cilium
能否使用VPC CIDR范围为Pod分配IP地址 ✅ 可以 ❌ 不可以(采用覆盖网络架构) ❌ 不可以(采用覆盖网络架构)
基本的网络策略功能 ✅ 可以(符合Kubernetes标准) ✅ 可以 ✅ 可以
第7层网络策略(如HTTP路径、gRPC方法等) ❌ 不支持 ❌ 不支持 ✅ 支持
eBPF数据平面功能 ❌ 不支持 ❌ 不支持 ✅ 支持
Hubble流量监控功能 ❌ 不支持 ❌ 不支持 ✅ 支持
服务网格功能(无需使用sidecar代理) ❌ 不支持 ❌ 不支持 ✅ 支持
内置SOC2网络合规性验证功能 ❌ 不支持 ❌ 不支持 ✅ 支持(Hubble具备此功能)
性能开销 较低 中等 非常低(eBPF技术可绕过iptables机制)
与AWS的原生集成程度 ✅ 最佳 中等 中等

推荐方案如下:

你的使用场景 推荐的CNI
简单的EKS集群,使用AWS原生工具,无需高级网络策略 AWS VPC CNI
需要网络策略,但不需要第7层功能或流量监控功能 Calico
需要满足SOC2合规性要求,并且需要Pod级别的隔离验证功能 Cilium
需要服务网格功能,且不希望产生sidecar代理带来的性能开销 Cilium
需要第7层网络策略(允许GET /health请求,拒绝POST /admin请求) Cilium

需要记住的一条规则是:对于满足SOC2合规性要求以及在EKS上实现零信任网络架构来说,Cilium是最佳选择。它能够提供Pod级别的隔离功能、第7层网络策略,同时还具备可用于审计的Hubble流量日志记录功能。这些功能是其他任何CNI都无法同时提供的。

第6部分:服务网格——Cilium vs Istio vs Linkerd

6.1 服务网格能提供什么

服务网格为你的集群网络架构增添了Kubernetes本身并不提供的三项功能。

mTLS技术能够对每对服务之间的通信进行加密处理,并验证双方的身份。如果没有mTLS,那么支付服务和数据库之间的通信数据在集群内部就会以明文形式传输。

流量观测功能能够实时监测每项服务间调用请求量、延迟百分比以及错误率,从而帮助您全面了解应用程序的性能状况。

流量管理机制则负责调控数据流的流动方式:在发生故障时会进行重试处理;设置超时时间;当下游服务出现性能下降时会立即切断连接;而在进行 Canary 部署时还会对流量进行分配调整。

6.2 边车代理问题

传统的服务网格方案(如 Istio 和 Linkerd)会在每个 Pod 中插入一个边车代理容器。这个边车代理会拦截所有网络流量,并根据预设的规则来处理这些数据。然而,这种设计会带来额外的资源开销:Istio 的 Envoy 边车代理会使每个 Pod 的内存使用量增加约 128MB,同时还会导致 5%–10%的延迟。

在一个拥有 200 个 Pod 的集群中,Istio 边车代理会为每项服务调用增加 25.6GB 的内存开销,并导致可测量的延迟现象。

Cilium 的解决方式截然不同。它利用 eBPF 在内核层实现服务网格功能,因此完全不需要使用边车代理容器。

6.3 完整对比

功能特性 Cilium Istio Linkerd
是否需要边车代理 ❌ 不需要(基于 eBPF 的内核机制) ✅ 需要(Envoy 边车代理,每个 Pod 需占用约 128MB 内存) ✅ 需要(Rust 编写的代理组件,每个 Pod 需占用约 10MB 内存)
每个 Pod 的内存开销 0 MB 约 128 MB 约 10 MB
延迟开销 <1% 5%–10% 2%–3%
是否支持 mTLS 协议 ✅ 支持 ✅ 支持 ✅ 支持
是否具备流量管理功能(如 Canary 部署、电路断路保护等) 功能有限 ✅ 全面支持 ✅ 全面支持
是否内置流量观测工具 ✅ 支持 ❌ 需要额外安装 Kiali 工具 ❌ 需要 Buoyant Cloud 平台的支持
是否能够直接满足 SOC2 标准要求 ✅ 能够满足 ❌ 需要额外的工具辅助 ❌ 需要额外的工具辅助
配置难度 较低 较高 中等

推荐方案如下:

您的实际需求 推荐的服务网格方案
需要支持 mTLS 协议且资源开销要尽可能低 Cilium
需要高级流量管理功能:Canary 部署、电路断路保护、加权路由等 Istio
需要轻量级的 mTLS 支持,同时避免 Istio 带来的运营复杂性 Linkerd
正在运行一个包含数百个 Pod 的集群,且非常关注边车代理带来的开销问题 Cilium

要启用 Cilium 的服务网格模式(无需使用边车代理),请执行以下命令:

# 升级 Cilium 安装版本以激活服务网格功能
helm upgrade cilium cilium/cilium \
  --namespace kube-system \
  --reuse-values \
  --set envoy.enabled=true \
  --set ingressController.enabled=true

# 验证服务网格是否已启用
cilium status | grep "Service Mesh"

需要记住的一条规则是:Cilium能够为你提供MTLS认证机制以及符合SOC2标准的审计证据,而且完全不会增加任何额外的运营开销。对于那些需要高级流量管理功能或复杂部署模式的团队来说,Istio虽然能提供更强的控制能力,但也会导致操作复杂性增加。

Kubernetes网络的最佳实践

建议这样做:使用Service而不是Pod的IP地址。因为Pod的IP地址在每次重启后都会发生变化,而Service的DNS名称则始终保持不变。

建议这样做:使用基于路径路由的单个Ingress控制器。通过使用一个ALB为所有服务提供路由支持,相比为每个服务单独配置LoadBalancer,每月可以节省300到400美元的成本。

建议这样做:利用Cilium实施默认拒绝策略型网络规则。这是SOC2 CC6.1标准所要求的技术措施。

建议这样做:将Hubble生成的流量日志作为符合SOC2标准的审计证据。请每天将这些日志导出到指定的存储桶中。

建议这样做:使用Cilium启用MTLS机制,以实现服务之间的加密通信。这种方式完全不需要额外的辅助组件。

建议这样做:采用能够识别网络拓扑结构的路由机制,确保流量始终在同一个可用区内传输,从而降低跨可用区的数据传输成本。

不要这样做:不要为每一个微服务都创建一个LoadBalancer Service。应该使用Ingress来进行外部路由配置。

不要这样做:不能仅依赖安全组来实现Pod级别的隔离功能。因为安全组的隔离作用是在节点层面发挥的,同一个节点上的所有Pod都会共享该节点的安全组设置。而网络规则则是在Pod层面起作用的。

不要这样做:千万不要认为默认的“允许所有流量通过”的配置就是安全的。在第一位企业客户要求查看你的网络隔离方案之前,一定要先实施默认拒绝策略。

资源链接

相关文章

技术实践

构建包将容器加固控制的重点从 Dockerfile 中分离出来

“Cloud Native Buildpacks”于2026年7月正式成为CNCF的官方项目。这一变更将各服务所使用的Dockerfile中关于基础镜像的选择机制,统一到了由平台工程团队管理的单一构建系统中,从而实现了对所有服务的统一补丁管理。BellSoft开发的优化版Paketo构建系统,进一步证明了如今供应商们已经将这种构建系统,而非Dockerfile本身,视为保障容器安全的关键环节。 作者:马克·西尔维斯特

阅读全文
技术实践

将容器视为工作节点而非代理程序:重新审视Kubernetes上AI代理程序的部署单元模型

在Kubernetes平台上运行AI代理时,会遇到一个关键问题:是否应该为每个代理分配一个单独的Pod?kagent项目认为不需要这样做——这些代理的活动频率较高、生命周期较短,有时还会生成子代理,并且可能需要等待人类的批准才能执行某些操作,因此为每个代理分配一个Pod会造成资源浪费。Agent-Substrate方案则通过添加一个控制层,来将逻辑“演员”调度到那些寿命较长的工作节点Pod上。 作者:马克·西尔维斯特

阅读全文