2. Kubernetes 网络基础回顾:Pod网络、Service、Ingress与网络策略(NetworkPolicy)核心概念

在深入多租户网络策略命中与隔离之前,必须重新夯实 Kubernetes 网络模型的四个核心支柱:Pod 网络、Service、Ingress 与 NetworkPolicy。这四个组件共同构成了应用交付的南北向与东西向通信骨架,也是 Helm Chart 在编排网络资源时的直接操作对象。

2.1 Pod 网络:扁平 IP 与容器间通信

Kubernetes 要求所有 Pod 在集群内拥有唯一的 IP 地址,且无需 NAT 即可直接通信。这一“扁平网络”模型由 CNI(Container Network Interface)插件实现,常见实现包括 Calico、Flannel、Cilium 等。

特性 说明
Pod IP 唯一性 每个 Pod 在集群范围内获得一个独立的 IP 地址,跨 Node 通信无需端口映射。
容器间通信 同一 Pod 内的多个容器共享网络命名空间(IP + 端口),通过 localhost 通信。
Pod 间通信 不同 Pod 通过各自 IP 直接通信,CNI 负责路由或 Overlay 封装。
Node 到 Pod Node 上的 kube-proxy 或 CNI 路由规则确保宿主机可访问任意 Pod IP。
多租户视角: 扁平网络意味着任何 Pod 默认可以访问任何其他 Pod。这正是网络策略(NetworkPolicy)必须介入的根源——没有隔离的扁平网络在多租户场景下是安全灾难。
CNI 选型影响: Calico 支持原生 BGP 路由与 NetworkPolicy 强制执行;Flannel 仅提供 Overlay 网络,不原生支持网络策略;Cilium 基于 eBPF 提供高性能策略与可观测性。Helm Chart 部署时需根据 CNI 能力调整网络策略的生效方式。

2.2 Service:稳定的访问抽象层

Pod 是脆弱的,IP 会随重建而变化。Service 通过标签选择器将一组 Pod 抽象为一个稳定的虚拟 IP(ClusterIP)或 DNS 名称,并提供负载均衡与服务发现能力。

  • ClusterIP: 默认类型,仅在集群内部可达,适合后端服务间调用。
  • NodePort: 在每个 Node 上开放一个静态端口,外部流量可通过 <NodeIP>:<NodePort> 访问。
  • LoadBalancer: 云厂商或裸金属 LB 集成,自动分配公网 IP,外部流量直接进入。
  • Headless Service: 不分配 ClusterIP,直接返回后端 Pod IP 列表,用于 StatefulSet 或自定义负载均衡。
# 一个典型的 ClusterIP Service 定义
apiVersion: v1
kind: Service
metadata:
  name: my-app-svc
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: ClusterIP
多租户陷阱: Service 默认不提供租户隔离。如果两个租户的 Pod 使用相同的标签选择器,Service 可能将流量路由到错误租户的 Pod。Helm Chart 设计时必须通过命名空间隔离 + 显式标签命名空间前缀来避免冲突。

2.3 Ingress:南北向流量的统一网关

Ingress 是 Kubernetes 原生的七层(HTTP/HTTPS)流量入口,将外部请求路由到集群内部的 Service。它通常由 Ingress Controller(如 Nginx、Traefik、HAProxy)实现,并支持 TLS 终止、虚拟主机路由、路径重写等高级功能。

Ingress 特性 多租户场景价值
基于 Host 路由 通过 spec.rules.host 区分不同租户的域名,如 tenant-a.example.com 与 tenant-b.example.com。
基于 Path 路由 同一域名下通过路径前缀隔离,如 /tenant-a/ 与 /tenant-b/。
TLS 证书管理 每个租户可绑定独立的 TLS 证书,通过 Secret 隔离。
注解(Annotations) Ingress Controller 通过注解实现限流、白名单、CORS 等租户级策略。
# 多租户 Ingress 示例:基于 Host 路由
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multi-tenant-ingress
  annotations:
    nginx.ingress.kubernetes.io/limit-rps: "100"
spec:
  rules:
    - host: tenant-a.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: tenant-a-svc
                port:
                  number: 80
    - host: tenant-b.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: tenant-b-svc
                port:
                  number: 80

2.4 NetworkPolicy:细粒度的流量防火墙

NetworkPolicy 是 Kubernetes 原生的网络隔离机制,基于标签选择器定义 Pod 级别的入站(Ingress)与出站(Egress)规则。它工作在 OSI 第三/四层(IP + 端口),部分 CNI 实现(如 Cilium)可扩展至七层。

核心原则: 默认情况下,Kubernetes 集群内所有 Pod 可以互相通信(全通模型)。一旦在命名空间中应用了任何 NetworkPolicy,该命名空间内未被显式允许的流量将被拒绝(白名单模型)。
NetworkPolicy 字段 作用
podSelector 选择策略生效的目标 Pod 集合(标签匹配)。
policyTypes 指定策略类型:Ingress(入站)、Egress(出站),或两者同时。
ingress.from 允许入站流量的来源:ipBlock、namespaceSelector、podSelector。
egress.to 允许出站流量的目标:同上。
ports 限制允许的端口与协议(TCP/UDP/SCTP)。
# 多租户隔离示例:仅允许同命名空间内的 Pod 访问
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-cross-namespace
  namespace: tenant-a
spec:
  podSelector: {}  # 匹配该命名空间所有 Pod
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: tenant-a
      ports:
        - protocol: TCP
          port: 8080
关键限制: NetworkPolicy 不适用于跨命名空间的 Service 流量控制。如果租户 A 的 Pod 通过 ClusterIP 访问租户 B 的 Service,NetworkPolicy 仅检查 Pod 到 Pod 的原始 IP,而非 Service IP。这意味着策略必须基于后端 Pod 的标签来编写,而非 Service 名称。

2.5 四层网络模型关系图

下图展示了从外部流量到 Pod 容器的完整路径,以及 NetworkPolicy 在 Pod 边界施加的隔离点。

Kubernetes 四层网络模型与隔离点 外部用户 Ingress Service 目标 Pod 组 Pod A (app=v1) Pod B (app=v1) 容器: 8080 HTTPS HTTP ClusterIP NetworkPolicy 隔离边界 流量路径与隔离点说明 1. 外部用户 → Ingress:TLS 终止,基于 Host/Path 路由到对应 Service。 2. Ingress → Service:七层转发,Service 通过标签选择器找到后端 Pod。 3. Service → Pod:kube-proxy 或 CNI 将 ClusterIP 转换为 Pod IP。 4. NetworkPolicy 在 Pod 网络接口处强制执行:仅允许匹配 Ingress/Egress 规则的流量通过。 5. 多租户场景:每个租户的 Pod 组被 NetworkPolicy 隔离,跨命名空间流量默认被拒绝。

2.6 多租户网络策略命中逻辑

在多租户环境中,NetworkPolicy 的“命中”取决于三个关键因素的组合:Pod 标签、命名空间标签与策略顺序。Kubernetes 对 NetworkPolicy 采用“先允许后拒绝”的累加模型,即所有匹配的 Ingress/Egress 规则取并集。

命中判定流程:
  1. 检查目标 Pod 的命名空间是否包含任何 NetworkPolicy。
  2. 如果存在,则默认拒绝所有未显式允许的流量。
  3. 遍历所有 NetworkPolicy 的 podSelector,匹配目标 Pod 标签。
  4. 对于匹配的策略,检查 ingress.from 或 egress.to 中的来源/目标条件。
  5. 如果至少一条策略的规则匹配,则流量被允许;否则被拒绝。

下表总结了不同隔离策略的命中效果:

策略配置 允许流量来源 多租户隔离效果
podSelector: {} + 空 ingress 无 完全隔离该命名空间所有 Pod,拒绝所有入站流量。
namespaceSelector: {matchLabels: {team: a}} 标签为 team=a 的命名空间 仅允许同团队命名空间的 Pod 访问,实现租户级隔离。
ipBlock: {cidr: 10.0.0.0/8} 特定 IP 段 允许来自集群内部或特定 CIDR 的流量,适合混合云场景。
podSelector: {matchLabels: {role: frontend}} 同命名空间内特定标签的 Pod 微服务级别的细粒度隔离,适用于同一租户内的分层架构。
常见误区: NetworkPolicy 的 namespaceSelector 匹配的是命名空间本身的标签,而非命名空间内 Pod 的标签。要允许特定命名空间的所有 Pod 访问,必须确保目标命名空间具有正确的标签,并在策略中引用该标签。

2.7 多租户网络策略隔离架构图

下图展示了一个典型的多租户集群中,NetworkPolicy 如何在不同命名空间之间实施隔离,同时允许必要的跨租户通信(如共享监控服务)。

多租户 NetworkPolicy 隔离架构 租户 A 命名空间 labels: tenant=a Pod A1 Pod A2 Pod A3 租户 B 命名空间 labels: tenant=b Pod B1 Pod B2 共享服务命名空间 labels: shared=true 监控 Pod 日志 Pod 允许 策略允许: namespaceSelector {shared=true} 拒绝 策略配置与命中逻辑 • 租户 A 命名空间 NetworkPolicy:允许同命名空间所有 Pod 通信,允许访问标签 shared=true 的命名空间。 • 租户 B 命名空间 NetworkPolicy:允许同命名空间所有 Pod 通信,允许访问标签 shared=true 的命名空间。 • 共享服务命名空间 NetworkPolicy:仅允许来自 tenant=a 或 tenant=b 命名空间的流量,拒绝其他来源。 • 跨租户直接通信(A→B 或 B→A)被双方 NetworkPolicy 拒绝,实现租户级隔离。 • 所有策略通过 Helm Chart 的 values.yaml 参数化,实现不同环境的灵活配置。

2.8 本章小结

  • Pod 网络 提供扁平 IP 模型,是通信的基础,但默认无隔离。
  • Service 提供稳定的访问抽象,但多租户场景需注意标签冲突。
  • Ingress 控制南北向流量,通过 Host/Path 实现租户级路由。
  • NetworkPolicy 是东西向流量的核心隔离手段,基于标签选择器实现白名单模型。
  • 多租户网络策略的命中逻辑依赖于 Pod 标签、命名空间标签 与 策略累加 的精确组合。