• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
思想人生从关注生活开始
博客园    首页    新随笔    联系   管理    订阅  订阅

Kubernetes 网络各类端口全链路模型

1. 核心概念矩阵:谁在干活?

image

💡 终极洞察:
流量转发不看“工牌” (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 端口。
  • 结果: ✅ 通过 (因为导航指向了 9090)。

第四跳:最终接收 (App Port)

  • 动作: 数据包进入容器 Network Namespace,内核查找监听进程。
  • 决胜时刻:
    • Java 进程配置 server.port=9090,正在监听。
    • TCP 握手成功 🎉。
  • 反例推演:
    • 如果 Java 配的是 8080? →→ 9090 无人监听 →→ Connection Refused ❌。
    • 如果 containerPort 改成 9090 但 Java 还是 8080? →→ 依然 Connection Refused ❌ (因为 containerPort 不改写路由)。

3. 常见误区与“尸体”分析

image

4. 黄金配置法则: “两同一显”原则

为了消除认知负担,请死守以下三条铁律:

1. 应用与声明同 (App Port == containerPort)

  • 做法: 代码里配 8080,YAML containerPort 也写 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 的网络流量不是“广播”,而是一场定向接力:
  1. NodePort 打开小区大门。
  2. Service Port 指引进入大楼的方向。
  3. TargetPort (在 Service 中定义) 是唯一的导航仪,锁定具体的房间号。
  4. App Port (在代码中定义) 是房间里张开双臂的人。
记住:containerPort 只是贴在运动员身上的号码牌。
裁判(kube-proxy)发球时,只看导航仪(TargetPort)指向哪里。
只有当 导航仪指向的房间 里,恰好有 人在等待,这场接力才算完美完成。

💡 额外建议:排错速查命令

如果遇到连接问题,按顺序执行以下“三板斧”:
  1. 查 Service 导航:
    kubectl get svc <svc-name> -o yaml | grep targetPort
    # 确认 targetPort 是多少 (例如 9090)

     

  2. 查 Pod 实况:
    kubectl get pods -l app=<label> -o wide
    # 拿到 Pod IP
    kubectl exec -it <pod-name> -- netstat -tulpn | grep <targetPort>
    # 确认容器内真的有进程在监听 targetPort 吗?

  3. 直连测试 (绕过 K8s 代理):
    # 在集群内任意节点或 Pod 中测试
    curl -v http://<Pod-IP>:<targetPort>
    # 如果这里不通,那就是代码(App Port)的问题,与 K8s 配置无关!

     


posted @ 2026-03-09 13:26  JackYang  阅读(0)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3