K8s学习笔记:03-辅助讲义-Service网络深度解析

对应章节:第三章 Service 网络 / 3.1~3.7
定位:讲透 Service 底层原理——虚拟 IP 的真相、流量转发机制、DNS 解析链路
日期:2026年7月13日
前置:已完成第二章 Deployment,理解了 Pod IP 不稳定的问题


一、一句话总结 Service

Service 给一组 Pod 一个固定不变的虚拟 IP + DNS 名字,kube-proxy 在每台节点上把流量转发到后端 Pod。

三层关键角色:

1
2
3
4
5
6
7
你访问 Service (ClusterIP / DNS)
│
▼
kube-proxy(每台节点上都有,负责转发)
│
▼
后端 Pod(真实容器,IP 随便变)

二、Service 的 ClusterIP 到底是什么?

2.1 它不是一个”网卡”

如果你登录到任何一台节点执行 ip addr,你找不到 ClusterIP。它不绑定在任何网络接口上。

ClusterIP 是一个仅存在于 kube-proxy 规则表中的虚拟地址:

1
2
真实 IP(如 Pod 的 10.244.0.5)→ 绑定在 veth 网卡上 → ip addr 看得到
ClusterIP(如 10.96.0.50) → 仅存在于 iptables/IPVS 规则中 → ip addr 看不到

2.2 那数据包是怎么到达 Pod 的?

流程图(以 iptables 模式为例):

1
2
3
4
5
6
7
8
9
10
11
客户端 Pod 发出请求
│ 目标: 10.96.0.50:80 (Service ClusterIP)
▼
客户端所在节点的内核网络栈
│ iptables PREROUTING 链命中规则:
│ "目标地址是 10.96.0.50:80 的包,DNAT 到 <某个后端 Pod IP>"
▼
数据包目标地址被改写为真实 Pod IP(如 10.244.0.5:80)
│
▼
包被路由到 Pod 所在节点 → Pod 容器的网络命名空间 → nginx 收到请求

关键认知:Service 不做代理,不经过任何用户态进程转发。iptables 在内核层面直接改写数据包的目标地址(DNAT),性能开销极小。


三、kube-proxy 的三种转发模式

kube-proxy 是运行在每台节点上的 DaemonSet Pod(或系统进程),它 watch API server 监听 Service 和 Endpoints 的变化,然后改写本机规则。

3.1 三种模式对比

模式 规则位置 性能 负载均衡算法 适用规模
userspace(旧) kube-proxy 进程自己转发 最差(用户态↔内核态来回切) 轮询 已被淘汰
iptables(默认) iptables 规则链 好(内核态,O(n) 规则匹配) 随机(statistic 模块) 中小集群
IPVS(推荐) IPVS 内核模块 最好(内核态,O(1) 哈希查找) rr / lc / sh 等多种 1000+ Service

3.2 iptables 模式(Kind 默认)

每增加一个 Service + 后端 Pod 组合,kube-proxy 就往 iptables 里写规则:

1
2
3
4
5
Service my-svc (10.96.0.50:80) → 3 个后端 Pod
iptables 规则:
-A KUBE-SVC-XXXX -m statistic --mode random --probability 0.333 -j KUBE-SEP-YYYY (→ Pod A)
-A KUBE-SVC-XXXX -m statistic --mode random --probability 0.500 -j KUBE-SEP-ZZZZ (→ Pod B)
-A KUBE-SVC-XXXX -j KUBE-SEP-WWWW (→ Pod C)

规律:N 个后端 → N 条规则串成链,匹配是 O(n) 的。所以 iptables 模式下 Service + Pod 多了之后规则爆炸,影响性能。

3.3 IPVS 模式

IPVS 是 Linux 内核的传输层负载均衡模块(LVS 项目的核心)。kube-proxy 在 IPVS 模式下创建一个虚拟服务 + 多个真实后端,哈希 O(1) 查找,支持多种调度算法:

算法缩写 全称 含义
rr Round Robin 轮询
lc Least Connection 最少连接数
sh Source Hashing 源地址哈希(同一客户端固定到同一后端)

生产环境 Service 超过 100 个就应考虑切 IPVS。但 Kind 环境 iptables 完全够用。

3.4 为什么理解这个有用?

  • 排障时:Pod 明明活着但 Service 访问不通 → 可能是本地 iptables 规则没更新
  • 性能调优:大规模集群 iptables 规则爆炸 → 切 IPVS
  • 你访问 ClusterIP,包不会经过 kube-proxy 进程——它在控制面写规则,数据面是内核

四、Endpoints:Service 和 Pod 之间的”动态电话本”

4.1 Endpoints 是什么

Endpoints 是一个 API 对象,记录”当前匹配 Service selector 的所有 Pod IP + 端口”。它不是转发路径中的一跳,而是 kube-proxy 用来生成转发规则的数据源。

1
2
3
4
5
6
7
8
9
10
用户创建 Service (selector: app=nginx)
│
▼
Endpoints Controller 持续 watch Pod 的变化
│ Pod 创建/删除 → 检查标签是否匹配
▼
更新 Endpoints 对象:{ 10.244.0.5:80, 10.244.0.6:80, 10.244.0.7:80 }
│
▼
kube-proxy watch Endpoints → 重新生成 iptables/IPVS 规则

4.2 Endpoints vs EndpointSlice

对象 版本 特点
Endpoints 老 单个对象存所有后端 IP,后端超多时对象过大,更新慢
EndpointSlice 新(1.21 GA) 每个 Service 拆成多个 Slice(每个最多 100 条),增量更新

新集群默认用 EndpointSlice,kubectl get endpoints 看到的其实是 EndpointSlice 的汇总视图。

4.3 没了 selector 的 Service(手动 Endpoints)

可以不写 selector,自己手动建 Endpoints:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 场景:集群内有外部数据库,想给 Pod 一个统一的 DNS 名字访问
apiVersion: v1
kind: Service
metadata:
name: external-db
spec:
ports:
- port: 3306
# 没有 selector!
---
apiVersion: v1
kind: Endpoints
metadata:
name: external-db # 名字必须和 Service 完全一致
subsets:
- addresses:
- ip: 192.168.1.100 # 外部数据库的真实 IP
ports:
- port: 3306

这时候 kube-proxy 照常生成转发规则,把流量发到 192.168.1.100:3306——给集群外资源起了一个集群内 DNS 名字。


五、DNS 服务发现:CoreDNS 的解析链路

5.1 整体架构

1
2
3
4
5
6
7
8
9
10
Pod 发起 DNS 查询 "my-nginx-svc"
│
▼
Pod 的 /etc/resolv.conf → nameserver 指向 CoreDNS Service ClusterIP
│
▼
CoreDNS Pod(kube-system 中,通常 2 个副本)
│ 查自己的配置(从 Service 和 Pod 自动生成)
▼
返回 my-nginx-svc 的 ClusterIP: 10.96.x.x

5.2 Pod 的 /etc/resolv.conf 长什么样

1
2
3
nameserver 10.96.0.10          # CoreDNS 的 ClusterIP
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

search 域就是为什么同 namespace 内只用写 my-nginx-svc 而不是完整 FQDN——系统自动拼接后缀逐个尝试。

5.3 完整 FQDN 结构

1
2
3
4
5
6
7
<service名>.<namespace>.svc.<cluster域>

my-nginx-svc.default.svc.cluster.local
│ │ │ └───── 集群域(默认 cluster.local)
│ │ └────────── 固定后缀 "svc"
│ └────────────────── namespace 名
└─────────────────────────────── Service 名

5.4 同 namespace vs 跨 namespace

场景 写法 原因
同 namespace my-nginx-svc search 域自动补全
跨 namespace my-nginx-svc.production 需指定 namespace
跨 namespace 完整 my-nginx-svc.production.svc.cluster.local 显式全路径

5.5 DNS 缓存与 TTL

每次查询的 TTL 默认 30 秒。Service 的 ClusterIP 是不变的,所以即使后端 Pod 全换了,缓存也是有效的——真正变化的 Endpoints 由 kube-proxy 管,不是 DNS 管。


六、三种 Service 类型的数据流全景

6.1 流量路径对比

1
2
3
4
5
6
7
8
9
ClusterIP(集群内部):
Pod A → DNS 解析 → ClusterIP → iptables DNAT → 后端 Pod

NodePort(节点端口对外):
外部客户端 → 节点IP:31234 → iptables DNAT → ClusterIP → iptables 再 DNAT → 后端 Pod
└─ 第一跳:NodePort → ClusterIP ─┘ └─ 第二跳:ClusterIP → Pod ─┘

LoadBalancer(云上):
外部客户端 → 云LB公网IP → 转发到所有节点的 NodePort →(后续同 NodePort)

NodePort 的本质是:在每台节点的 iptables 里加一条规则,把 节点IP:31234 的流量 DNAT 到 ClusterIP:80,后续和 ClusterIP 一模一样。

6.2 哪种场景用哪种

类型 使用场景 原因
ClusterIP 集群内微服务互调(前端→后端→数据库) 不暴露到集群外,安全,默认选择
NodePort 开发测试临时对外,云 LB 的后端 简单,但端口范围受限(30000-32767)
LoadBalancer 生产对外暴露 HTTP/HTTPS 自动化配置云 LB + 公网 IP + 健康检查

七、Kind 环境下的网络真相

7.1 Kind 的节点是 Docker 容器

真实集群:节点 = 物理机/虚拟机 → NodePort 直接在宿主机网络栈上监听端口。

Kind 集群:节点 = Docker 容器 → NodePort 端口开在容器内部,宿主机默认看不到。

1
2
3
4
5
真实集群:         你的笔记本 → 节点IP:31234 → Pod
└─ 节点真实网卡

Kind 集群: 你的笔记本 → 容器IP:31234 → Pod
└─ Docker 网络内部,笔记本默认不通

7.2 三种解法

办法 原理 何时用
kubectl port-forward svc/xxx 8080:80 --address 0.0.0.0 kubectl 在宿主机起代理,通过 API server 隧道转发 临时测试,最快
extraPortMappings 建集群时配置 建 Kind 集群时在容器上做 -p 31234:31234 建集群时就确定要用 NodePort
NodePort 不用,直接用 Ingress Ingress Controller 通过 hostPort/hostNetwork 对外暴露 80/443 生产方式,第五章讲

kubectl port-forward 是开发测试最方便的方式,它的转发路径和真实 NodePort 不同(走 API server 隧道),但效果相同。


八、Service、Endpoints、kube-proxy 三者协作全貌

把前面各节串起来,一张图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
                          ┌──────────┐
│ API │
│ Server │
└────┬─────┘
│ watch (持续监听)
┌─────────────────────────┼─────────────────────────┐
│ │ │
┌────▼─────┐ ┌──────▼──────┐ ┌──────▼──────┐
│Endpoints │ │ kube-proxy │ │ CoreDNS │
│Controller│ │ (每节点) │ │ (集群 DNS) │
└──────────┘ └──────┬──────┘ └─────────────┘
维护 Endpoints 对象 │ watch Service + Endpoints
记录匹配 Pod 的 IP │ 改写本地 iptables/IPVS
│
┌────────▼────────┐
│ iptables 规则 │
│ 10.96.0.50:80 │
│ → DNAT → Pod地址│
└────────┬────────┘
│
┌──────────────┼──────────────┐
│ │ │
┌───Pod───┐ ┌───Pod───┐ ┌───Pod───┐
│app=nginx│ │app=nginx│ │app=nginx│
│10.244.0│ │10.244.0│ │10.244.0│
│ .5 │ │ .6 │ │ .7 │
└─────────┘ └─────────┘ └─────────┘

数据面(你的请求包经过的):iptables 规则 → Pod
控制面(配置如何生效的):API Server → Endpoints Controller / kube-proxy → 更新 iptables


九、常见误区纠正

误区 真相
“ClusterIP 是一个虚拟网卡” 不是,仅存在于 iptables/IPVS 规则中,ip addr 看不到
“Service 是代理,流量经过它” 不是,K8s Service 无进程,是内核规则转发(DNAT)
“kube-proxy 转发每个请求” 不对,kube-proxy 只写规则,不参与数据面转发
“NodePort 在 Kind 里直接能用” 不能,因为 Kind 节点是 Docker 容器,宿主机看不到容器端口
“Service 用 DNS 做负载均衡” DNS 只做名字解析(返回 ClusterIP),负载均衡靠 iptables/IPVS
“删掉 Service 后 Pod 也受影响” 不受影响,Service 只是 Pod 前面的入口,删 Service 不影响 Pod 运行
“Endpoints 变化需要等 DNS 缓存过期” 不需要,DNS 只到 ClusterIP(不变的),Endpoints 变化由 kube-proxy 实时更新

十、与主章节的对照关系

主章节 本辅助讲义对应内容
3.1 Pod 网络困境 第二节:ClusterIP 是什么
3.2 Service 靠 label 关联 Pod 第四节:Endpoints 机制
3.3 三种 Service 类型 第六节:三种类型数据流全景
3.4 ClusterIP 实操 第三节:kube-proxy 三种转发模式
3.5 NodePort 第七节:Kind 环境 NodePort 真相
3.6 DNS 服务发现 第五节:CoreDNS 解析链路
3.7 章节练习 全文作为练习时的参考答案

本章核心认知回顾

1
2
3
4
5
6
7
8
9
10
11
12
13
Service 底层三要素:

1. ClusterIP = 内核规则中的虚拟地址(不是网卡,ip addr 看不到)
└─ kube-proxy 写 iptables/IPVS 规则实现 DNAT 转发

2. Endpoints = "动态电话本",记录匹配 Pod 的 IP 列表
└─ 数据源,kube-proxy 据此生成规则 → Pod 增减自动更新

3. CoreDNS = 集群 DNS,把 Service 名解析为 ClusterIP
└─ 搜索域机制:短名自动拼接 <ns>.svc.cluster.local

数据面:iptables/IPVS 内核规则(高性能,无用户态转发)
控制面:API Server → Endpoints Controller / kube-proxy → 更新规则

K8s学习笔记:03-辅助讲义-Service网络深度解析
https://bote798.top/2026/07/13/K8s学习笔记-03-辅助讲义-Service网络深度解析/
作者
bote798
发布于
2026年7月13日
更新于
2026年7月16日
许可协议