Kubernetes网络模型深度解析:CNI、Service与Ingress的协同工作原理
2026/7/11 20:59:45 网站建设 项目流程

Kubernetes网络模型深度解析:CNI、Service与Ingress的协同工作原理

排查过 Pod 间网络不通的人都知道,Kubernetes 网络问题排查的难度不在于"不理解某一部分",而在于 CNI、Service、Ingress 三者各管一段,出问题时需要沿着数据包的路径从源头追到终点。本文把这条路径拆开来讲透。

一、Kubernetes 网络模型的基本约束

Kubernetes 的网络模型建立在三个基本前提之上,理解这三个前提是理解一切网络行为的基础:

  1. 每个 Pod 拥有独立 IP:Pod 内的容器共享同一个网络命名空间,通过 localhost 通信
  2. Pod 间可直接通信(无 NAT):同一集群中任意两个 Pod 可以直接通过对方的 IP 通信,无论它们是否在同一节点上
  3. 节点可与所有 Pod 直接通信:节点本身可以路由到集群内的任意 Pod IP

这三个前提将网络实现的复杂性下放到了 CNI 插件层。Kubernetes 自身只定义了接口和约束,不规定具体的数据面实现。

graph TB subgraph 控制面 API[API Server] --> SVC[Service Controller] SVC --> EP[Endpoints Controller] API --> ING[Ingress Controller] end subgraph 节点1 KPL1[Kube-Proxy] --> IPT1[iptables/IPVS规则] POD1A[Pod A<br/>10.244.1.10] --> ETH0_1A[eth0<br/>veth pair] POD1B[Pod B<br/>10.244.1.11] --> ETH0_1B[eth0<br/>veth pair] ETH0_1A --> BR1[cni0 网桥] ETH0_1B --> BR1 BR1 --> NODE1_ETH[节点网卡 eth0] end subgraph 节点2 KPL2[Kube-Proxy] --> IPT2[iptables/IPVS规则] POD2A[Pod C<br/>10.244.2.10] --> ETH0_2A[eth0<br/>veth pair] ETH0_2A --> BR2[cni0 网桥] BR2 --> NODE2_ETH[节点网卡 eth0] end subgraph Service层 SVC_OBJ[Service: my-svc<br/>ClusterIP: 10.96.0.1:8080] end subgraph 外部流量 LB[外部负载均衡] --> ING_CTRL[Ingress Controller Pod] ING_CTRL --> SVC_OBJ end NODE1_ETH <-->|VXLAN/BGP路由| NODE2_ETH API -.->|watch| KPL1 API -.->|watch| KPL2 style 控制面 fill:#e3f2fd style 节点1 fill:#fff3e0 style 节点2 fill:#fff3e0 style Service层 fill:#e8f5e9 style 外部流量 fill:#f3e5f5

二、Pod 网络通信路径拆解

2.1 同节点 Pod 间通信

同节点 Pod 间通信是最简单的场景。以 Flannel VXLAN 为例:

Pod A (10.244.1.10) → Pod B (10.244.1.11) 1. Pod A 的路由表将 10.244.1.0/24 指向 cni0 网桥 2. 数据包经过 veth pair 到达宿主机的 cni0 网桥 3. cni0 是二层网桥,直接查询 CAM 表,将帧转发到 Pod B 的 veth 接口 4. 数据包进入 Pod B 的网络命名空间

关键点在于 cni0 网桥充当了二层交换机,同节点流量无需经过任何隧道封装。

2.2 跨节点 Pod 间通信

跨节点通信依赖 CNI 插件的跨主机方案:

CNI 插件跨主机方案封装开销适用场景
Flannel (VXLAN)VXLAN 隧道封装~50 bytes 额外头部通用场景
Flannel (host-gw)主机路由表无额外开销二层互通的集群
Calico (IPIP)IP-in-IP 隧道~20 bytes跨子网部署
Calico (BGP)BGP 路由协议无额外开销同子网/支持 BGP 的网络
Cilium (eBPF)eBPF 直通极低高性能场景

以 Flannel VXLAN 为例,跨节点通信路径:

Node1 Pod A (10.244.1.10) → Node2 Pod C (10.244.2.10) 1. Pod A 查路由表:10.244.2.0/24 通过 flannel.1 接口 2. flannel.1 是 VXLAN 隧道端点(VTEP),它需要知道: - 目标 VTEP 的 MAC 地址(通过 ARP 或 flannel 守护进程学习) - 目标 VTEP 所在节点的 IP(通过 etcd 存储的节点子网映射) 3. 原始以太网帧被封装在 VXLAN UDP 包中 4. Node1 物理网卡通过 underlay 网络将 VXLAN 包发送到 Node2 5. Node2 flannel.1 解封装,取出原始帧,通过 cni0 转发给 Pod C

2.3 网络策略与流量隔离

NetworkPolicy 提供了 Pod 级别的防火墙规则。关键是理解它是通过 CNI 插件实现的(Kubernetes 只是定义了 API 对象):

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: backend-network-policy namespace: production spec: podSelector: matchLabels: app: payment-service # 目标:支付服务 Pod policyTypes: - Ingress - Egress ingress: - from: - podSelector: matchLabels: app: api-gateway # 仅允许 API 网关访问 - namespaceSelector: matchLabels: name: production # 仅允许同命名空间的流量 ports: - protocol: TCP port: 8080 egress: - to: - podSelector: matchLabels: app: database-proxy # 仅允许访问数据库代理 ports: - protocol: TCP port: 5432 - to: - namespaceSelector: {} podSelector: matchLabels: app: dns-server # 允许 DNS 查询 ports: - protocol: UDP port: 53

NetworkPolicy 的"默认拒绝"策略需要在每个命名空间显式创建:

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-all namespace: production spec: podSelector: {} # 选中所有 Pod policyTypes: - Ingress - Egress # 不定义任何 ingress/egress 规则 = 拒绝所有

三、Service 的 iptables 与 IPVS 模式对比

Service 是 Kubernetes 中最容易被"用对但不理解"的对象。它的底层实现有两种模式:

3.1 iptables 模式

graph LR subgraph 请求流转 CLIENT[客户端 Pod] -->|dip: 10.96.0.1:8080| PREROUTING[iptables PREROUTING] PREROUTING --> KUBE_SVC[KUBE-SVC Chain] KUBE_SVC -->|random概率选择| SEP1[KUBE-SEP-1<br/>DNAT → 10.244.1.10:8080] KUBE_SVC -->|random概率选择| SEP2[KUBE-SEP-2<br/>DNAT → 10.244.2.10:8080] KUBE_SVC -->|random概率选择| SEP3[KUBE-SEP-3<br/>DNAT → 10.244.1.11:8080] SEP1 --> BACKEND1[Pod Backend A] SEP2 --> BACKEND2[Pod Backend B] SEP3 --> BACKEND3[Pod Backend C] end

iptables 模式的核心特征是:kube-proxy 将每个 Service 和 Endpoint 翻译为一条条 iptables 规则。其行为特征是:

  • 随机负载均衡:通过statistic --mode random --probability实现
  • 规则数量膨胀:每个 Endpoint 对应一条 KUBE-SEP 链,大规模集群中 iptables 规则可能达到数万条
  • 规则匹配是 O(n) 的:数据包需要逐条匹配规则,规则越多,延迟越大

3.2 IPVS 模式

IPVS(IP Virtual Server)是 Linux 内核的传输层负载均衡器。kube-proxy 在 IPVS 模式下,将 Service 直接映射为 IPVS 虚拟服务器:

# 查看 IPVS 规则 ipvsadm -Ln # 输出示例: # TCP 10.96.0.1:8080 rr # -> 10.244.1.10:8080 Masq 1 0 0 # -> 10.244.2.10:8080 Masq 1 0 0 # -> 10.244.1.11:8080 Masq 1 0 0

IPVS 相较于 iptables 的关键优势:

维度iptablesIPVS
负载均衡算法随机(round-robin 近似)rr/wrr/lc/wlc/lblc/dh/sh 等 8 种
规则匹配复杂度O(n) 逐条匹配O(1) 哈希查找
大规模 Service 性能5000+ Service 时明显下降10000+ Service 性能稳定
连接追踪依赖 conntrack自身维护连接表
健康检查依赖 Endpoint 更新支持主動健康检查

生产环境建议:当集群 Service 数超过 1000 时,优先使用 IPVS 模式。配置方式:

# kube-proxy ConfigMap apiVersion: v1 kind: ConfigMap metadata: name: kube-proxy namespace: kube-system data: config.conf: | apiVersion: kubeproxy.config.k8s.io/v1alpha1 kind: KubeProxyConfiguration mode: ipvs ipvs: scheduler: "wrr" # 加权轮询 strictARP: true tcpTimeout: 0 tcpFinTimeout: 0 udpTimeout: 0

3.3 ClusterIP 不存在的数据面

一个常见的误区是认为 ClusterIP 绑定在某个网络接口上。实际上,ClusterIP 仅存在于 iptables/IPVS 规则中——它就是一条 DNAT 规则的匹配条件。当你 ping 一个 Service 的 ClusterIP 时,ping 包会被 iptables 规则匹配并做 DNAT,但 ICMP 协议不在规则匹配范围内,所以 ping 不通是正常的。

四、Ingress Controller 选型对比

Ingress Controller 承担着"从外部世界到集群内部服务"的最后一跳。主流选型有两类:

/** * Ingress Controller 健康检查端点 * 用于外部负载均衡器的后端健康探测 */ @RestController public class IngressHealthController { private final HealthChecker healthChecker; private final MeterRegistry meterRegistry; public IngressHealthController(HealthChecker healthChecker, MeterRegistry meterRegistry) { this.healthChecker = healthChecker; this.meterRegistry = meterRegistry; } /** * 深度健康检查:验证所有关键依赖是否可用 * 用于外部 LB 的健康探测,返回 200/503 */ @GetMapping("/healthz") public ResponseEntity<Map<String, Object>> healthCheck() { Map<String, HealthChecker.ComponentStatus> statuses = healthChecker.checkAll(List.of("database", "redis", "message-queue")); boolean allHealthy = statuses.values().stream() .allMatch(s -> s == HealthChecker.ComponentStatus.HEALTHY); // 记录健康检查指标 statuses.forEach((component, status) -> { meterRegistry.counter("health.check", "component", component, "status", status.name().toLowerCase() ).increment(); }); Map<String, Object> body = new LinkedHashMap<>(); body.put("status", allHealthy ? "UP" : "DOWN"); body.put("timestamp", Instant.now().toString()); body.put("components", statuses); return allHealthy ? ResponseEntity.ok(body) : ResponseEntity.status(503).body(body); } }

选型对比矩阵:

特性Nginx IngressTraefikIstio GatewayKong
成熟度★★★★★★★★★☆★★★★☆★★★★☆
性能(QPS)最高较高中等(有 Sidecar 开销)较高
动态配置需 reload原生支持原生支持原生支持
插件生态Lua 脚本中间件链EnvoyFilter丰富插件
服务网格集成需额外配置可集成原生一体需额外配置
学习曲线
适用规模中小型中小型大型/微服务中型/API管理

选型建议:如果你的主要需求是"把外部 HTTP 流量引进来做路由分发",Nginx Ingress 是最稳妥的选择。如果需要 API 网关级别的能力(限流、认证、日志),Kong 更合适。如果已经或计划部署服务网格,Istio Gateway 是自然的选择。

五、总结

Kubernetes 网络模型的核心设计思路是"关注点分离":CNI 管 Pod 网络(L2-L3),Service 管服务发现(L3-L4),Ingress 管外部流量(L7)。三层之间通过标准化的接口解耦,每层可以独立选型。

在实际运维中,有三个容易踩的坑值得特别注意:

一是不要把 ClusterIP 当成真实 IP。它只是 iptables/IPVS 规则中的匹配条件,ping 不通不是故障。

二是大规模集群优先考虑 IPVS。iptables 的 O(n) 规则匹配在服务数量超过 1000 时性能退化明显,IPVS 通过内核级的哈希表将查找降到 O(1)。

三是NetworkPolicy 需要 CNI 支持。不是所有 CNI 都实现了 NetworkPolicy(Flannel 默认不支持,需配合 Calico 做 policy-only 模式),选型时务必确认。

排查网络问题时,建议按照"Pod 内 → 同节点 Pod → 跨节点 Pod → Service → 外部访问"的顺序逐层验证。每一层都有对应的调试命令:ip netns exec进入 Pod 网络命名空间、conntrack -L查看连接追踪表、iptables-save | grep <service-name>查看 Service 规则、tcpdump -i flannel.1抓取跨节点封装包。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询