Kubernetes 网络各类端口全链路模型
1. 核心概念矩阵:谁在干活?

💡 终极洞察:
流量转发不看“工牌” (containerPort),只看“导航指令” (targetPort)。
- 若
targetPort==App Port→→ 通 (哪怕containerPort写错了)。- 若
targetPort!=App Port→→ 不通 (哪怕containerPort和App Port一模一样)。
2. 流量全景图:一次请求的“生死四级跳”
场景设定:
- 用户请求:
http://192.168.1.50:30080 - K8s Service:
nodePort: 30080,port: 80,targetPort: 9090 - Pod 声明:
containerPort: 8080(⚠️ 故意写错的干扰项) - 应用代码:
server.port = 9090(✅ 真实监听)
🏃♂️ 接力过程详解
第一跳:物理入口 (Node Port)
- 动作: 请求撞击节点
192.168.1.50的30080端口。 - 守门员:
kube-proxy(iptables/IPVS) + 防火墙。 - 判定: 防火墙放行?NodePort 范围合法?
- 结果: ✅ 通过。流量进入宿主机网络栈。
第二跳:虚拟路由 (Service Port)
- 动作:
kube-proxy执行 DNAT (目标地址转换)。 - 变换:
NodeIP:30080→→<ClusterIP>:80。 - 意义: 流量脱离具体节点,进入 K8s 虚拟覆盖网络 (Overlay Network)。
- 结果: ✅ 通过。
第三跳:精准投递 (TargetPort -> App Port) 【决胜局】
- 动作: Service 根据 Endpoints 列表,选择后端 Pod,并执行第二次端口转换。
- 变换:
<ClusterIP>:80→→<PodIP>:9090。 - 关键逻辑:
- K8s 完全忽略 YAML 中声明的
containerPort: 8080。 - K8s 严格遵循 Service 中定义的
targetPort: 9090。 - 数据包被直接发往 Pod IP 的 9090 端口。
- K8s 完全忽略 YAML 中声明的
- 结果: ✅ 通过 (因为导航指向了 9090)。
第四跳:最终接收 (App Port)
- 动作: 数据包进入容器 Network Namespace,内核查找监听进程。
- 决胜时刻:
- Java 进程配置
server.port=9090,正在监听。 - TCP 握手成功 🎉。
- Java 进程配置
- 反例推演:
- 如果 Java 配的是
8080? →→ 9090 无人监听 →→ Connection Refused ❌。 - 如果
containerPort改成9090但 Java 还是8080? →→ 依然 Connection Refused ❌ (因为containerPort不改写路由)。
- 如果 Java 配的是
3. 常见误区与“尸体”分析

4. 黄金配置法则: “两同一显”原则
为了消除认知负担,请死守以下三条铁律:
1. 应用与声明同 (App Port == containerPort)
- 做法: 代码里配
8080,YAMLcontainerPort也写8080。 - 价值: 文档即事实。运维人员看
kubectl describe pod看到的端口,就是代码真正跑的端口。
2. 转发与实听同 (targetPort == App Port)
- 做法: Service 的
targetPort必须死死咬住代码实际监听的端口。 - 价值: 确保流量最后一公里准确送达。这是连通的唯一真理。
3. 显式指定 targetPort
- 做法: 在 Service YAML 中永远不要省略
targetPort。 - 价值: 避免 K8s 默认行为带来的“魔法”和隐患。明确意图,拒绝猜测。
✅ 推荐的标准 YAML 模板 (Copy-Paste Ready)
# 1. Deployment (应用层) - 诚实声明 apiVersion: apps/v1 kind: Deployment metadata: name: my-java-app spec: template: spec: containers: - name: app image: my-java-image:v1 # 【原则1】声明端口 = 代码实际监听端口 (server.port=8080) ports: - containerPort: 8080 env: - name: SERVER_PORT value: "8080" --- # 2. Service (网络层) - 精准导航 apiVersion: v1 kind: Service metadata: name: my-java-svc spec: type: NodePort selector: app: my-java-app ports: # 【外部/内部调用端口】标准化为 80,方便内部微服务调用 - port: 80 # 【原则2 & 3】显式指定!必须等于代码实际监听端口 (8080) targetPort: 8080 # 【外部入口端口】固定一个易记的端口 (30000-32767) nodePort: 30080
5. 总结:一场精密的接力赛
Kubernetes 的网络流量不是“广播”,而是一场定向接力:
- NodePort 打开小区大门。
- Service Port 指引进入大楼的方向。
- TargetPort (在 Service 中定义) 是唯一的导航仪,锁定具体的房间号。
- App Port (在代码中定义) 是房间里张开双臂的人。
记住:containerPort只是贴在运动员身上的号码牌。
裁判(kube-proxy)发球时,只看导航仪(TargetPort)指向哪里。
只有当 导航仪指向的房间 里,恰好有 人在等待,这场接力才算完美完成。
💡 额外建议:排错速查命令
如果遇到连接问题,按顺序执行以下“三板斧”:
- 查 Service 导航:
kubectl get svc <svc-name> -o yaml | grep targetPort # 确认 targetPort 是多少 (例如 9090)
- 查 Pod 实况:
kubectl get pods -l app=<label> -o wide # 拿到 Pod IP kubectl exec -it <pod-name> -- netstat -tulpn | grep <targetPort> # 确认容器内真的有进程在监听 targetPort 吗?
- 直连测试 (绕过 K8s 代理):
# 在集群内任意节点或 Pod 中测试 curl -v http://<Pod-IP>:<targetPort> # 如果这里不通,那就是代码(App Port)的问题,与 K8s 配置无关!
浙公网安备 33010602011771号