主题
Kubernetes Service 实战培训教材
基于《Kubernetes Service 原理由浅入深》《Service 全链路深入解析》《port/targetPort/NodePort 关系解读》《NodeIP:NodePort vs VIP:NodePort》《Service 端口冲突答疑》等内部文档整合编写。
- 培训对象:Kubernetes 运维、后端研发、DevOps、测试工程师
- 培训时长:建议 1 天(6 小时:理论 4h + 实验 2h)
- 前置知识:Linux 网络基础、容器基础、Pod 概念、YAML 基础
- 教材版本:v1.0
目录
- 课程目标与学习地图
- Service 核心概念
- Service 四种类型
- 端口深度解析:port / targetPort / NodePort
- Service 全链路数据包流转
- kube-proxy 实现机制
- 外部访问与 VIP 设计
- 端口冲突与最佳实践
- 动手实验手册
- 故障排查演练
- 课程考核
- 附录:速查表与参考资料
第1章 课程目标与学习地图
1.1 学完本课程你能做什么
| 能力层级 | 具体能力 |
|---|---|
| 理解 | 解释 Service 的本质、四种类型、端口含义 |
| 应用 | 正确编写 Service YAML,选择合适的 Service 类型 |
| 分析 | 从 kube-proxy 规则层面分析流量走向 |
| 排障 | 定位 Service 访问不通、端口冲突、源 IP 丢失等问题 |
| 设计 | 为生产环境设计 NodePort、LoadBalancer、Ingress 入口方案 |
1.2 学习地图
┌─────────────────────────────────────────────────────────────┐
│ Kubernetes Service │
├───────────────┬───────────────┬───────────────┬─────────────┤
│ 概念层 │ 端口层 │ 实现层 │ 入口层 │
├───────────────┼───────────────┼───────────────┼─────────────┤
│ ClusterIP │ port │ kube-proxy │ NodePort │
│ NodePort │ targetPort │ iptables │ LoadBalancer│
│ LoadBalancer │ nodePort │ ipvs │ Ingress │
│ ExternalName │ containerPort │ conntrack │ VIP │
│ Headless │ hostPort │ EndpointSlice │ MetalLB │
└───────────────┴───────────────┴───────────────┴─────────────┘第2章 Service 核心概念
2.1 为什么需要 Service
Pod 的特点:
- 生命周期短暂
- IP 不固定
- 随时扩缩容
Service 的作用:
- 为一组 Pod 提供稳定的虚拟 IP(ClusterIP)
- 通过 Label Selector 动态关联 Pod
- 提供服务发现、负载均衡
2.2 Service 的本质
Service 不是进程,不是网卡,而是 Kubernetes 中的一种抽象资源 + 一组转发规则。
真正实现转发的是:
- EndpointSlice:记录后端 Pod 的 IP:targetPort
- kube-proxy:在每个节点上配置 iptables/ipvs 规则
2.3 核心对象关系
┌──────────────┐ selector ┌─────────────┐
│ Service │ ────────────────> │ Pod │
│ ClusterIP:80 │ │ 10.244.x.x │
└──────┬───────┘ └─────────────┘
│
│ 自动生成
▼
┌─────────────────┐
│ EndpointSlice │
│ IP:targetPort │
└─────────────────┘
│
│ kube-proxy 监听并生成规则
▼
┌─────────────────┐
│ iptables / ipvs │
└─────────────────┘第3章 Service 四种类型
3.1 ClusterIP(默认)
- 分配集群内部虚拟 IP
- 仅集群内部可达
- 用于微服务间调用
yaml
spec:
type: ClusterIP
selector:
app: web
ports:
- port: 80
targetPort: 80803.2 NodePort
- 在 ClusterIP 基础上,在每个节点上开放一个端口
- 外部通过
<NodeIP>:<NodePort>访问 - NodePort 默认范围 30000-32767
yaml
spec:
type: NodePort
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # 可选3.3 LoadBalancer
- 请求云厂商或 MetalLB 创建外部负载均衡器
- 分配外部 IP
- 底层仍依赖 NodePort
yaml
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80803.4 ExternalName
- 没有 selector,不分配 ClusterIP
- 将 Service 映射为外部域名的 CNAME
- 用于平滑迁移或访问外部服务
yaml
spec:
type: ExternalName
externalName: db.example.com3.5 四种类型对比
| 类型 | 是否有 ClusterIP | 是否可被外部访问 | 典型场景 |
|---|---|---|---|
| ClusterIP | ✅ | ❌ | 微服务内部调用 |
| NodePort | ✅ | ✅(节点 IP) | 临时测试 |
| LoadBalancer | ✅ | ✅(外部 IP) | 生产公网入口 |
| ExternalName | ❌ | 间接 | 外部服务映射 |
第4章 端口深度解析:port / targetPort / NodePort
4.1 一句话解释
| 字段 | 绑定对象 | 一句话解释 |
|---|---|---|
port | Service | Service 对外暴露的端口,调用方使用 |
targetPort | Pod 容器 | 容器真实监听的端口,流量最终到达这里 |
nodePort | 节点网卡 | 节点对外开放的端口,外部用户通过 <节点IP>:<NodePort> 访问 |
4.2 流量链
外部用户
│
▼
<NodeIP>:30080 nodePort
│
▼
Service:80 port (ClusterIP:port)
│
▼
Pod:8080 targetPort4.3 用快递物流类比
port= 公司总机号码targetPort= 员工分机号码nodePort= 园区门口公共收件窗口
4.4 不同场景下的端口配置
| 场景 | type | port | targetPort | nodePort |
|---|---|---|---|---|
| 内部微服务调用 | ClusterIP | 80 | 8080 | 不写 |
| 临时外部测试 | NodePort | 80 | 8080 | 30080 |
| 生产公网访问 | LoadBalancer | 80 | 8080 | 不写 |
| Ingress 后端 | ClusterIP | 80 | 8080 | 不写 |
4.5 研发常见错误
只改容器端口,忘了改 targetPort
- 现象:有 Endpoints,但请求无响应
- 排查:
telnet PodIP:targetPort不通
调用方写死 Pod IP
- Pod IP 会变化,应该通过 Service 域名访问
以为 port 必须等于 targetPort
- 两者可以不同,且通常建议不同
多个 NodePort 服务硬编码相同端口
- NodePort 是集群全局资源,会冲突
第5章 Service 全链路数据包流转
5.1 ClusterIP 全链路
Client Pod
│
│ 目的: 10.96.123.45:80
▼
┌─────────────────────────────┐
│ 本节点 kube-proxy 规则 │
│ (iptables / ipvs) │
└─────────────┬───────────────┘
│ DNAT
▼
Backend Pod: 10.244.1.10:8080核心认知:ClusterIP 不是真实网卡 IP,只是 iptables/ipvs 规则中的匹配条件。
5.2 NodePort 全链路
外部客户端
│
▼
Node-1:30080
│
▼
ClusterIP:80
│
▼
Pod:80805.3 端口转换关系总结
外部: <NodeIP>:30080 → nodePort
Service: 10.96.123.45:80 → port
Pod: 10.244.1.10:8080 → targetPort5.4 返回包与 conntrack
请求包:
源: Client-IP:random-port
目的: 10.96.123.45:80
DNAT 后:
源: Client-IP:random-port
目的: 10.244.1.10:8080
Pod 回复:
源: 10.244.1.10:8080
目的: Client-IP:random-port
返回包经过 conntrack 反向 DNAT:
源: 10.96.123.45:80
目的: Client-IP:random-port第6章 kube-proxy 实现机制
6.1 kube-proxy 三种模式
| 模式 | 说明 | 状态 |
|---|---|---|
| userspace | kube-proxy 用户态代理 | 已废弃 |
| iptables | 默认模式,内核态 DNAT | 广泛使用 |
| ipvs | 内核态 IPVS 负载均衡 | 大规模推荐 |
6.2 iptables 模式
kube-proxy 创建的核心链:
KUBE-SERVICES
├── KUBE-SVC-XXX # 某个 Service
│ ├── KUBE-SEP-XXX # 后端 Pod 1,DNAT 到 Pod-1:targetPort
│ └── KUBE-SEP-YYY # 后端 Pod 2,DNAT 到 Pod-2:targetPort
└── KUBE-NODEPORTS # 匹配 NodePort负载均衡算法:随机(通过 statistic mode random probability 实现)
6.3 ipvs 模式
IP Virtual Server (VS) = ClusterIP:port
├── Real Server 1 = Pod-1:targetPort
└── Real Server 2 = Pod-2:targetPort支持调度算法:rr、lc、dh、sh、sed、nq
默认转发模式:Masq(NAT)
6.4 iptables vs ipvs 对比
| 特性 | iptables | ipvs |
|---|---|---|
| 负载均衡层 | iptables 规则链 | IPVS virtual server |
| 调度算法 | 随机 | rr / lc / dh / sh / sed / nq |
| 后端数量大时 | 规则链膨胀 | 结构稳定 |
| 性能 | 较好 | 更好 |
| 长连接重试 | 较差 | 较好 |
| 内核要求 | 低 | 需要 ip_vs 模块 |
6.5 EndpointSlice
- Kubernetes 1.21+ 默认使用
- 将后端端点拆分为多个 Slice,每个最多 100 个端点
- 支持拓扑信息(zone、nodeName)
- 更高效地增量更新
第7章 外部访问与 VIP 设计
7.1 NodeIP:NodePort vs VIP:NodePort
| 对比项 | NodeIP:NodePort | VIP:NodePort |
|---|---|---|
| 可用性 | 低,单节点故障即中断 | 高,VIP 自动剔除故障节点 |
| 入口统一性 | 差,多个 NodeIP | 好,一个 VIP |
| 流量均衡 | 差 | 较好 |
| 源 IP 保留 | 看 externalTrafficPolicy | 看 externalTrafficPolicy |
| 维护成本 | 高 | 低 |
| 生产推荐度 | ❌ 不推荐 | ✅ 推荐 |
7.2 externalTrafficPolicy
| 模式 | 流量路径 | 源 IP | 空节点风险 | 适用场景 |
|---|---|---|---|---|
| Cluster | 可能跨节点转发 | 被 SNAT,丢失真实 IP | 无 | 追求均衡、容错 |
| Local | 只转发到本节点 Pod | 保留真实客户端 IP | 有 | 需要源 IP、Pod 分布均匀 |
7.3 VIP 方案对比
| 方案 | 类型 | 工作层次 | 复杂度 | 负载均衡 |
|---|---|---|---|---|
| MetalLB L2 | K8s 原生 | L2 (ARP/NDP) | 低 | Failover |
| MetalLB BGP | K8s 原生 | L3 (BGP/ECMP) | 中 | 多活 ECMP |
| kube-vip | K8s 原生 | L2 / BGP | 低 | Failover / ECMP |
| HAProxy + Keepalived | 外部独立 | L4 + VRRP | 中 | 主备 |
| Calico BGP | CNI 集成 | L3 (BGP) | 中 | ECMP |
7.4 生产入口设计建议
Internet
│
▼
LoadBalancer / VIP
│
▼
Ingress Controller (NodePort / LoadBalancer)
│
▼
Service (ClusterIP)
│
▼
Backend Pods- 业务 Service 使用 ClusterIP
- 通过 Ingress 暴露七层 HTTP/HTTPS
- 需要四层 TCP/UDP 时直接用 LoadBalancer
- 裸金属集群使用 MetalLB 或 kube-vip 提供 VIP
第8章 端口冲突与最佳实践
8.1 端口冲突判断原则
端口是否冲突,不取决于数字本身,而取决于它绑定在哪个网络对象上。
| 场景 | 是否冲突 | 原因 |
|---|---|---|
不同 Service 都用 port: 8080 | ❌ | 每个 Service 有独立 ClusterIP |
不同 Pod 都用 targetPort: 8080 | ❌ | 每个 Pod 有独立 IP |
同一个 Service 内两个 port: 8080/TCP | ✅ | 同 Service 内 port+protocol 必须唯一 |
| 同一个 Pod 内两个容器都监听 8080 | ✅ | 共享同一个网络命名空间 |
不同 Service 使用相同 nodePort | ✅ | NodePort 绑定节点,全局唯一 |
同一个节点上两个 Pod 使用相同 hostPort | ✅ | 节点端口被占用 |
8.2 生产最佳实践
- 统一后端端口:让所有后端服务统一使用
port: 8080/targetPort: 8080 - 给端口命名:便于 Ingress、监控、日志区分
- NodePort 自动分配:不要硬编码,避免冲突
- 优先使用 ClusterIP + Ingress:减少端口管理负担
- 配置 readinessProbe:只有就绪的 Pod 才会加入 EndpointSlice
- 使用 Topology Spread Constraints:保证 Pod 在节点间均匀分布
- 根据需求选择 externalTrafficPolicy:
- 需要保留源 IP → Local
- 追求均衡和容错 → Cluster
第9章 动手实验手册
实验1:部署并访问 ClusterIP Service
bash
# 创建 Deployment
kubectl create deployment nginx --image=nginx:alpine --replicas=2
# 创建 ClusterIP Service
kubectl expose deployment nginx --port=80 --target-port=80 --type=ClusterIP
# 验证
kubectl get svc nginx
kubectl get endpoints nginx
# 从集群内访问
kubectl run -it --rm debug --image=busybox --restart=Never -- wget -O- http://nginx实验2:NodePort 访问与端口观察
bash
# 修改 Service 为 NodePort
kubectl patch svc nginx -p '{"spec":{"type":"NodePort"}}'
# 查看 NodePort
kubectl get svc nginx
# 从外部访问
NODE_IP=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[0].address}')
NODE_PORT=$(kubectl get svc nginx -o jsonpath='{.spec.ports[0].nodePort}')
curl http://$NODE_IP:$NODE_PORT实验3:iptables 规则观察
bash
# 在节点上执行
iptables -t nat -L KUBE-SERVICES -n -v | grep nginx
iptables -t nat -L KUBE-NODEPORTS -n -v
iptables -t nat -L -n -v | grep KUBE-SEP实验4:ipvs 模式观察(需启用 ipvs)
bash
# 加载 ipvs 模块
modprobe ip_vs
# 查看规则
ipvsadm -Ln实验5:externalTrafficPolicy=Local 效果验证
bash
# 修改 externalTrafficPolicy
kubectl patch svc nginx -p '{"spec":{"externalTrafficPolicy":"Local"}}'
# 测试从有 Pod 的节点和无 Pod 的节点访问
# 观察:无 Pod 的节点是否会丢弃连接实验6:端口冲突验证
bash
# 部署两个 Service,都使用 port: 8080
kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
name: app-a
spec:
selector:
app: app-a
ports:
- port: 8080
targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: app-b
spec:
selector:
app: app-b
ports:
- port: 8080
targetPort: 8080
EOF
# 验证两个 Service 都能成功创建
kubectl get svc第10章 故障排查演练
10.1 Service 访问不通排查清单
bash
# 1. 检查 Service 是否存在
kubectl get svc <svc-name>
# 2. 检查 Endpoints/EndpointSlice 是否有后端
kubectl get endpoints <svc-name>
kubectl get endpointslices -l kubernetes.io/service-name=<svc-name>
# 3. 检查 Pod 标签是否匹配 selector
kubectl get pods -l <selector> --show-labels
# 4. 检查 Pod 是否就绪
kubectl get pods -l <selector>
# 5. 检查容器是否监听 targetPort
kubectl exec -it <pod> -- netstat -tlnp | grep <targetPort>
# 6. 从 Pod 内访问 Service
kubectl run -it --rm debug --image=busybox --restart=Never -- wget -O- http://<svc-name>:<port>
# 7. 查看节点 iptables/ipvs 规则
iptables -t nat -L KUBE-SERVICES -n -v | grep <svc-name>
ipvsadm -Ln | grep <cluster-ip>
# 8. 查看 conntrack
conntrack -L | grep <cluster-ip>
# 9. 抓包
sudo tcpdump -i any -nn host <cluster-ip> or port <nodePort>10.2 常见故障现象与原因
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| Service 没有 EXTERNAL-IP | 云厂商 CCM 未安装或 MetalLB 未配置 | 检查 CCM / MetalLB |
| 有 Endpoints 但访问超时 | Pod 未真正监听 targetPort | telnet PodIP:targetPort |
| NodePort 访问不通 | 防火墙/安全组拦截 | 检查节点防火墙 |
| 源 IP 被改写 | externalTrafficPolicy=Cluster | 改为 Local 或前端代理加 XFF |
| 流量不均衡 | Pod 分布不均 + Local 模式 | Topology Spread Constraints |
| 滚动更新时 502 | 长连接未断开 + 旧 Pod 已删除 | 配置 preStop / terminationGracePeriod |
第11章 课程考核
11.1 选择题
1. Service 的 port 是指?
A. 容器实际监听的端口
B. 节点上暴露的端口
C. Service 对外暴露的端口
D. Pod 内进程监听的端口
答案:C
2. 以下哪种 Service 类型不会分配 ClusterIP?
A. ClusterIP
B. NodePort
C. LoadBalancer
D. ExternalName
答案:D
3. iptables 模式下,kube-proxy 使用的负载均衡算法是?
A. 轮询
B. 最少连接
C. 随机
D. 加权轮询
答案:C
4. externalTrafficPolicy=Local 的主要作用是?
A. 提高负载均衡效果
B. 保留真实客户端源 IP
C. 减少 iptables 规则数量
D. 自动分配 NodePort
答案:B
11.2 实操题
- 创建一个 Deployment(2 个副本)和 ClusterIP Service,从集群内验证访问。
- 将 Service 改为 NodePort,从集群外通过
<NodeIP>:<NodePort>访问。 - 在节点上找到该 Service 对应的 iptables 规则链。
- 配置
externalTrafficPolicy=Local,测试源 IP 保留效果。 - 部署两个都使用
port: 8080的 Service,验证不会冲突。
11.3 设计题
某公司有一个裸金属 Kubernetes 集群,需要:
- 为 20 个微服务提供内部调用入口
- 为 5 个 Web 应用提供公网 HTTPS 入口
- 为 2 个 TCP 长连接服务提供四层入口
- 需要保留真实客户端源 IP
请设计 Service + Ingress + VIP 方案,并说明:
- 每种服务使用什么 Service 类型
- 外部 VIP 如何提供
- externalTrafficPolicy 如何选择
- 端口如何规划
第12章 附录:速查表与参考资料
12.1 Service YAML 速查
yaml
apiVersion: v1
kind: Service
metadata:
name: example
spec:
type: ClusterIP # 或 NodePort / LoadBalancer / ExternalName
selector:
app: example
ports:
- name: http
port: 80 # Service 端口
targetPort: 8080 # Pod 端口
nodePort: 30080 # 仅 NodePort/LoadBalancer 有效
sessionAffinity: None # 或 ClientIP
externalTrafficPolicy: Cluster # 或 Local12.2 关键命令速查
bash
# Service 与后端
kubectl get svc -o wide
kubectl get endpoints <svc>
kubectl get endpointslices -l kubernetes.io/service-name=<svc>
# Pod 标签与就绪
kubectl get pods -l app=<app> --show-labels
kubectl describe pod <pod>
# 网络规则
iptables -t nat -L KUBE-SERVICES -n -v
iptables -t nat -L KUBE-NODEPORTS -n -v
ipvsadm -Ln
conntrack -L | grep <ip>
# DNS 测试
kubectl run -it --rm debug --image=busybox --restart=Never -- nslookup <svc>.<namespace>
# 抓包
sudo tcpdump -i any -nn host <cluster-ip> or port <nodePort>12.3 参考资料
- 内部文档:《Kubernetes Service 原理由浅入深》
- 内部文档:《Kubernetes Service 全链路深入解析》
- 内部文档:《port / targetPort / NodePort 关系解读》
- 内部文档:《NodeIP:NodePort vs VIP:NodePort 访问方式深度解析》
- 内部文档:《所有后端 Service 都用 8080 端口,会冲突吗?》
- 官方文档:https://kubernetes.io/docs/concepts/services-networking/service/
- MetalLB 官方文档:https://metallb.universe.tf/
结语
掌握 Kubernetes Service 是理解集群网络通信的基础。本教材从概念、端口、实现、入口、排障五个层面系统讲解了 Service 的核心知识。建议学员在学习理论后,务必完成动手实验,并在实际工作中多观察 kubectl get endpoints、iptables -L、ipvsadm -Ln 等输出,形成对 Service 流量走向的直观理解。
教材生成时间:2026-07-18