3、网络拓扑基础:K8s网络模型、Ingress/Nginx配置、Service与Endpoint关系

在云原生IDP(内部开发者平台)中,网络拓扑是流量调度的骨架。理解Kubernetes网络模型、Ingress/Nginx配置以及Service与Endpoint的联动关系,是定位和恢复网络故障的前提。本章从底层模型到上层配置,逐层拆解关键组件。

3.1 Kubernetes网络模型:扁平IP与通信原则

K8s网络模型要求所有Pod可以直接通信,无需NAT,且每个Pod拥有独立的IP地址。这一模型由CNI(容器网络接口)插件实现,常见方案包括Calico、Flannel、Cilium。

通信类型 通信路径 是否经过NAT 典型故障点
Pod ↔ Pod(同节点) 通过cni0/veth对直接转发 否 CNI插件配置错误、内核路由表丢失
Pod ↔ Pod(跨节点) 通过节点路由/overlay隧道 否 节点间网络连通性、隧道封装MTU问题
Pod ↔ Service 通过iptables/IPVS规则转发 是(DNAT) kube-proxy规则失效、conntrack表满
外部 ↔ Service 通过Ingress/NodePort/LB 是(SNAT/DNAT) Ingress控制器异常、端口冲突
故障恢复要点: 当Pod间通信超时,优先检查CNI插件状态(kubectl get pods -n kube-system | grep cni)和节点路由表(ip route)。跨节点通信故障时,使用ping或traceroute验证节点间underlay网络。
K8s网络模型通信路径 Pod A (10.1.1.2) Pod B (10.1.1.3) Pod C (10.1.2.5) Service (10.0.0.1) Ingress (域名) 同节点直连 跨节点隧道 DNAT 负载均衡转发 路由规则 图例说明 实线:直接通信路径;虚线:隧道或负载均衡转发路径。 所有Pod IP在集群内扁平可达,Service通过DNAT将流量转发到后端Pod。

3.2 Service与Endpoint:流量转发的核心纽带

Service是K8s中抽象的服务发现单元,它通过标签选择器动态关联一组Pod。Endpoint(或EndpointSlice)则维护了Service后端Pod的实际IP:Port列表。kube-proxy监听这些变化,实时更新节点上的iptables/IPVS规则。

3.2.1 Service类型与适用场景

Service类型 ClusterIP NodePort LoadBalancer ExternalName
集群内访问 ✅ 是 ✅ 是 ✅ 是 ❌ 否
外部访问 ❌ 否 ✅ 是(节点端口) ✅ 是(LB IP) ✅ 是(CNAME)
负载均衡 轮询(iptables/IPVS) 轮询 云厂商LB + 轮询 DNS解析
典型故障场景 kube-proxy未运行 节点防火墙拦截端口 LB健康检查失败 DNS解析超时

3.2.2 Endpoint更新机制与故障排查

当Pod就绪状态变化时,Endpoint控制器会更新Endpoint对象。如果Pod未通过就绪探针,Endpoint会将其移除,避免流量打到不可用Pod。

关键命令:
# 查看Service对应的Endpoint
kubectl get endpoints <service-name> -n <namespace>

# 查看EndpointSlice(K8s v1.21+默认)
kubectl get endpointslices -l kubernetes.io/service-name=<service-name> -n <namespace>

# 检查kube-proxy规则
kubectl logs -n kube-system kube-proxy-xxxxx | grep "syncProxyRules"
常见故障模式: 如果Service的Endpoint列表为空,但Pod正在运行,请检查Pod的status.conditions中Ready是否为True,以及Service的selector是否与Pod标签匹配。标签拼写错误是高频原因。
Service与Endpoint关系 Service: my-app ClusterIP: 10.0.0.1:80 selector: app=my-app, version=v1 Endpoint: my-app (10.1.1.2:8080, 10.1.1.3:8080, 10.1.2.5:8080) Pod A (10.1.1.2) Ready: True Pod B (10.1.1.3) Ready: True Pod C (10.1.2.5) Ready: False 未就绪,排除 Pod C就绪探针失败,Endpoint自动将其移除,流量仅转发到Pod A和Pod B。

3.3 Ingress与Nginx配置:南北向流量入口

Ingress是K8s中管理外部访问集群服务的API对象,通常由Ingress Controller(如Nginx Ingress Controller、Traefik)实现。Ingress Controller运行在集群内,监听Ingress资源并动态生成反向代理配置(如nginx.conf)。

3.3.1 Ingress核心配置示例

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - app.example.com
    secretName: tls-secret
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 80
      - path: /web
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80

3.3.2 Nginx Ingress Controller故障排查清单

  • 检查Controller Pod状态: kubectl get pods -n ingress-nginx,确保Running且就绪。
  • 验证Ingress资源是否被识别: kubectl describe ingress <name>,查看Events中是否有错误。
  • 查看Nginx配置是否生效: 进入Controller Pod,检查/etc/nginx/nginx.conf中是否包含对应路由。
  • 测试后端Service连通性: 使用kubectl exec -it <pod> -- curl <service-cluster-ip>:<port>。
  • 检查TLS证书: kubectl get secret <tls-secret> -o yaml,确保证书未过期且域名匹配。
实战技巧: 当Ingress返回502时,大概率是后端Service的Endpoint为空或Pod未就绪。使用kubectl get endpoints <service-name>快速确认。如果Endpoint正常,再检查Nginx Controller与Pod之间的网络策略(NetworkPolicy)是否放行。

3.4 网络拓扑故障恢复实战流程

当IDP平台出现网络访问异常时,按照以下流程逐层排查,可快速定位根因:

  1. 确认故障范围: 是单个服务、多个服务还是整个集群不可达?
  2. 检查Ingress层: 域名解析是否正常?Ingress Controller是否运行?Nginx配置是否加载?
  3. 检查Service层: Service的ClusterIP是否可达?Endpoint列表是否包含就绪Pod?
  4. 检查Pod层: Pod是否Running?就绪探针是否通过?Pod日志是否有异常?
  5. 检查网络插件: CNI Pod是否正常?节点路由表是否正确?节点间网络是否连通?
快速诊断命令组合:
# 一键检查Ingress、Service、Endpoint、Pod状态
kubectl describe ingress <name>
kubectl get svc <name> -o wide
kubectl get endpoints <name>
kubectl get pods -l app=<app-label> -o wide

# 检查kube-proxy规则(需在节点上执行)
iptables-save | grep <service-cluster-ip>
ipvsadm -Ln | grep <service-cluster-ip>