2. Kubernetes网络模型精讲

Kubernetes 的网络模型不是一张“网络拓扑图”,而是一组对 CNI 插件提出的契约。理解这些契约,才能判断某个 CNI 实现是否满足集群需求,也才能在排障时快速定位问题出在 Pod 网络、Service 转发还是策略执行层。本节围绕四类核心对象——Pod、Service、Ingress、NetworkPolicy——逐一拆解它们对网络提出的要求,以及这些要求在实现层面的约束。

一、Pod:最小网络单元的三条硬性要求

Pod 是 Kubernetes 调度的最小单位,也是网络模型的基本单元。它对网络提出的要求可以归纳为三条:

  • 每个 Pod 拥有独立 IP:Pod 内的所有容器共享同一个网络命名空间,因此共享同一个 IP 和端口空间。容器之间通过 localhost 通信,不存在端口冲突问题。
  • Pod 之间可直接通信:任意两个 Pod,无论是否在同一节点,都应能在不经过 NAT 的情况下直接通过 Pod IP 互访。这是“扁平网络”的核心含义。
  • 节点与 Pod 可互访:节点上的进程(如 kubelet、kube-proxy)能够直接访问 Pod IP,反之亦然。

这三条要求看似简单,却直接决定了 CNI 插件的实现方式。例如,Overlay 方案(如 VXLAN)通过隧道封装满足“跨节点直连”的语义,但会带来 MTU 开销;Underlay 方案(如 Calico BGP 模式)通过路由通告实现原生互通,性能更好但对底层网络有要求。无论哪种方案,都必须保证 Pod IP 在集群内全局唯一且可路由。

判断一个 CNI 是否满足 Pod 网络要求,最直接的方法是:在两个不同节点的 Pod 中互相 ping 对方 Pod IP,并抓包确认没有发生源地址 NAT。

二、Service:虚拟 IP 与负载均衡的抽象

Pod IP 是易变的——Pod 重建后 IP 会变化。Service 的作用就是为一组 Pod 提供一个稳定的虚拟 IP(ClusterIP)和 DNS 名称。它对网络的要求体现在三个层面:

第一,ClusterIP 必须可被 Pod 访问。ClusterIP 是一个虚拟地址,不存在于任何网卡上。它的实现依赖节点上的转发规则:kube-proxy 在 iptables 模式下生成 DNAT 规则,将发往 ClusterIP 的包改写为某个后端 Pod IP;在 IPVS 模式下则使用内核 IPVS 虚拟服务器。无论哪种模式,都要求节点内核支持相应的转发机制。

第二,Service 需要知道哪些 Pod 是后端。这通过 EndpointSlice(或 Endpoints)对象实现。kube-controller-manager 根据 Service 的 selector 匹配 Pod,并将就绪(Ready)的 Pod IP 写入 EndpointSlice。只有通过 readinessProbe 的 Pod 才会被加入后端列表,这是流量不落入未就绪 Pod 的关键保障。

第三,Service 有多种类型,约束各不相同。ClusterIP 仅在集群内可达;NodePort 在每个节点上开放一个端口,要求节点端口范围(默认 30000-32767)未被占用;LoadBalancer 依赖云厂商或 MetalLB 等实现,要求底层具备外部 IP 分配能力。

# 查看 Service 的后端端点
kubectl get endpointslice -l kubernetes.io/service-name=my-svc

# 查看 kube-proxy 生成的 iptables 规则(iptables 模式)
iptables -t nat -L KUBE-SERVICES -n | grep my-svc

三、Ingress:七层入口的转发约束

Service 工作在四层(TCP/UDP),而 Ingress 工作在七层(HTTP/HTTPS),提供基于域名和路径的路由。Ingress 本身只是一个规则声明,真正生效需要 Ingress Controller(如 NGINX Ingress、Traefik)来监听并生成反向代理配置。

Ingress 对网络的要求包括:Controller 自身必须以 Pod 形式运行并能被外部访问(通常通过 NodePort 或 LoadBalancer 类型的 Service 暴露);Controller 需要能访问后端 Service 的 ClusterIP 或直接访问 Pod IP;TLS 终止需要证书以 Secret 形式挂载。此外,Ingress 规则中的 host 和 path 匹配依赖 Controller 的实现,不同 Controller 对注解(annotation)的支持差异较大,这是实际使用中最容易踩坑的地方。

四、NetworkPolicy:从“能通”到“该不该通”

前面三类对象解决的是“能不能通”的问题,NetworkPolicy 解决的是“该不该通”的问题。它是一组 Pod 级别的防火墙规则,通过 label selector 选中目标 Pod,然后定义允许的入站(Ingress)和出站(Egress)流量。

关键约束有三点:其一,NetworkPolicy 是白名单模型——一旦某个 Pod 被某条策略选中,未被明确允许的流量默认被拒绝。其二,策略是命名空间隔离的——默认只能选中同命名空间的 Pod,跨命名空间需要显式使用 namespaceSelector。其三,策略能否生效取决于 CNI 是否支持——Calico、Cilium、Weave 等支持,而 Flannel 默认不支持。如果集群使用 Flannel 且未叠加策略引擎,创建 NetworkPolicy 对象不会报错,但也不会有任何效果,这是排障中极易被忽略的陷阱。

外部客户端 HTTP/HTTPS Ingress Controller 七层路由 / TLS 终止 host + path 匹配 Service ClusterIP / NodePort kube-proxy 转发 Pod 集合(EndpointSlice) Pod A 10.244.1.5:8080 Ready ✓ Pod B 10.244.2.7:8080 Ready ✓ Pod C 10.244.3.9:8080 NotReady ✗ 不加入后端 NetworkPolicy 白名单模型:未允许即拒绝 需 CNI 支持(Calico/Cilium) Flannel 默认不生效 请求 转发 不转发 策略约束 核心约束链: Pod IP 全局唯一可路由 → Service 虚拟 IP 经 kube-proxy 转发 → Ingress 七层路由 → NetworkPolicy 白名单管控 任一环节的 CNI 实现不满足契约,都会导致对应对象“创建成功但功能失效”

五、四类对象的约束关系与排障思路

把四类对象放在一起看,它们构成了一条从“身份”到“入口”再到“管控”的链路:Pod 提供可路由的身份,Service 提供稳定的访问入口,Ingress 提供七层路由能力,NetworkPolicy 提供访问管控。每一层都依赖 CNI 或控制器满足特定契约。

实际排障时,可以按这条链路逐层验证:先确认 Pod IP 是否可跨节点直连(排除 CNI 基础问题),再确认 Service 的 EndpointSlice 是否有就绪后端(排除 readinessProbe 或 selector 问题),然后确认 Ingress Controller 是否生成了正确的上游配置(排除注解或路径匹配问题),最后确认 NetworkPolicy 是否意外拦截了流量(排除策略选择器或 CNI 不支持问题)。这条链路的价值在于:它把“网络不通”这个模糊描述,拆解成了四个可独立验证的环节。

常见误区:认为创建了 NetworkPolicy 就一定生效。如果集群 CNI 是 Flannel 且未部署 Calico 等策略引擎,NetworkPolicy 对象会被 API Server 接受,但数据面不会有任何规则下发。验证方法是进入 Pod 执行 curl 测试被策略禁止的流量,观察是否真的被拒绝。

理解这些约束的最终目的,是在选型和排障时有据可依。选 CNI 时,先问“是否需要 NetworkPolicy”“是否需要跨节点直连的低延迟”“底层网络是否支持 BGP”,再决定用 Overlay 还是 Underlay、用 Calico 还是 Cilium。排障时,先定位问题出在哪一层契约,再深入该层的实现细节,而不是盲目重启组件。