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日
许可协议