找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4266

积分

0

好友

562

主题
发表于 4 小时前 | 查看: 5| 回复: 0

问题背景

Kubernetes 里服务访问不通是比节点 NotReady 更常见的线上故障。节点 NotReady 还偏基础设施层,而服务不通直接表现为业务不可用:页面能打开但数据加载不出来,API 返回 502/504,Pod 之间内部调用超时。这类问题的根因分散在多个层次:Pod 没启动、Service 配置有误、Endpoint 没关联到 Pod、网络策略拦截了流量、Ingress 规则写错、DNS 解析失败等等。

更要命的是,Kubernetes 的网络是虚拟网络,流量路径并不直观。外部请求经过 NodePort 或 LoadBalancer 到达某个节点,再由 kube-proxy 转发到后端 Pod;Pod 之间的调用虽然直接通过 Service IP 或 DNS 名称,但实际连接的是 Endpoint IP。路径中任何一个环节出问题,访问就会中断。

这篇文章面向初中级 Kubernetes 运维和 DevOps 工程师,以一个典型的“服务访问返回 502”故障为线索,从 Pod、Service、Endpoint、kube-proxy、CNI、Ingress 六个层次系统讲解排查方法。每个层次都配有检查命令、判断逻辑和修复步骤。所有命令在 Kubernetes 1.24 及以上版本验证通过,部分命令早期版本表现略有差异,文中会标注。

适用场景

  • 服务对外提供访问,但返回 502 Bad Gateway 或 504 Gateway Timeout
  • Pod 之间通过 Service 名称调用,但请求超时或连接拒绝
  • 通过 Ingress 访问服务,但 URL 无法解析或请求路由到错误的后端
  • NodePort / LoadBalancer 类型的 Service 无法从外部访问
  • Headless Service 下的 Pod 之间无法通过 DNS 互相发现
  • 某个命名空间内的 Pod 无法访问其他命名空间的服务
  • 特定 IP 段或端口的流量被网络策略阻断

K8s 服务访问路径全解析

动手排查之前,必须清楚流量从客户端到后端 Pod 的完整路径。不同类型的服务,路径不同。

场景一:集群内部 Pod 访问 Service(最常见)

PodA -> ClusterIP:ServicePort -> kube-proxy (iptables/ipvs) -> EndpointIP:ContainerPort -> PodB

Pod 内的进程访问 http://service-name.namespace.svc.cluster.local:port,这个 DNS 名称被 CoreDNS 解析为 Service IP,随后流量被 kube-proxy 拦截并通过 DNAT 转发到后端某个 Endpoint IP。

场景二:集群外部通过 NodePort 访问

外部客户端 -> NodeIP:NodePort -> kube-proxy -> EndpointIP:ContainerPort -> PodB

外部请求抵达任意节点的 NodePort,kube-proxy 将流量转发到后端 Pod,不一定是目标 Pod 所在的节点。

场景三:通过 Ingress 访问

外部客户端 -> Ingress Controller Pod -> Ingress 规则匹配 -> Service:NodePort -> kube-proxy -> PodB

流量先打到 Ingress Controller(通常是一个 NodePort 或 LoadBalancer 类型的 Service),Ingress Controller 根据 Host 和 Path 规则找到对应的 Backend Service,再通过 Service 转发到后端 Pod。

理解这三条路径,就知道每个环节该查什么了。

第一步:确认问题范围和现象

1.1 确认问题是否真实存在

别臆测问题,先复现:

# 通过 kubectl 确认目标 Service 存在
kubectl get svc -n <namespace> <service-name>

# 确认 Pod 是否存在且 Running
kubectl get pods -n <namespace> -l app=<app-label>

# 如果 Pod 不在 Running 状态,先解决 Pod 问题
# (Pod 都没起来,Service 肯定访问不了)

1.2 从业务角度确认问题现象

# 测试外部能否访问(用 NodePort 或 LoadBalancer IP)
curl -v http://<external-ip>:<port>/<health-path>

# 典型 502 错误:
# HTTP/1.1 502 Bad Gateway
# Server: nginx/1.24.0
# <html><body><h1>502 Bad Gateway</h1></body></html>

# 典型超时错误:
# curl: (7) Failed to connect to <ip> port <port>: Connection timed out

1.3 确认问题影响范围

# 查看该 Service 有多少个健康的 Endpoint
kubectl get endpoints -n <namespace> <service-name>

# 如果 endpoints 列表为空或数量少于预期,说明 Service 没有关联到健康的 Pod
# 如果 endpoints 数量正常,问题可能在 Ingress 或更上层

# 查看 Pod 分布
kubectl get pods -n <namespace> -o wide | grep <service-name>

第二步:从 Pod 层开始排查

Pod 是流量的最终目的地。如果 Pod 本身不正常,上游再查也是白搭。

2.1 确认 Pod 是否存在且 Running

kubectl get pods -n <namespace> -o wide

# 确认所有副本都在 Running
# 如果有非 Running 状态的 Pod:
kubectl get pods -n <namespace> --field-selector=status.phase!=Running

2.2 查看 Pod 事件

Pod 创建失败或重启时,Events 是最直接的线索:

kubectl describe pod <pod-name> -n <namespace>

# 重点看最后 20 行 Events
kubectl describe pod <pod-name> -n <namespace> | tail -20

# 常见的问题线索:
# - ImagePullBackOff: 镜像拉取失败,检查镜像名称、tag、私有仓库认证
# - CrashLoopBackOff: 容器启动后立即退出,检查应用启动命令和健康检查
# - CreateContainerConfigError: 配置错误,检查 ConfigMap/Secret 挂载
# - OOMKilled: 内存不足被杀,检查资源限制和实际使用
# - Evicted: 被驱逐,检查节点资源压力

2.3 查看容器内部日志

# 查看当前日志(stdout)
kubectl logs <pod-name> -n <namespace>

# 如果容器重启过,查看上次运行的日志(用于排查启动后立即崩溃的问题)
kubectl logs <pod-name> -n <namespace> --previous

# 如果是多容器 Pod,指定容器名
kubectl logs <pod-name> -n <namespace> -c <container-name>

# 实时查看日志
kubectl logs -f <pod-name> -n <namespace> --tail=100

2.4 登录 Pod 内部排查

如果日志没有线索,可以进 Pod 内部测试网络连通性:

# 进容器(需要容器内有 bash)
kubectl exec -it <pod-name> -n <namespace> -- /bin/bash

# 如果容器没有 bash,用 sh
kubectl exec -it <pod-name> -n <namespace> -- /bin/sh

# 确认容器进程是否监听在预期端口
# Java 应用:ps aux | grep java
# Nginx / Python / Node.js:netstat -tlnp 或 ss -tlnp
# 注意:很多精简镜像没有这些命令,可以临时安装或用其他方式验证

# 测试 localhost 端口是否监听
wget -qO- http://127.0.0.1:<container-port>/healthz
# 或
curl -s http://127.0.0.1:<container-port>/healthz

# 如果 localhost 访问正常,但通过 Service 访问有问题,说明问题在 Service 层

2.5 检查 Pod 资源限制

资源限制设置不当会导致 Pod 被 OOMKill 或 throttle,引发请求超时:

# 查看 Pod 的资源请求和限制
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.containers
  • .resources}' # 查看 Pod 实际资源使用(需要 metrics-server) kubectl top pod <pod-name> -n <namespace> # 如果资源使用接近限制,说明需要调高限制或优化应用内存使用
  • 第三步:排查 Service 层

    确认 Pod 正常后,转到 Service 层。Service 是 Pod 的访问入口,也是最容易配置出错的地方。

    3.1 确认 Service 配置正确

    # 查看 Service 完整配置
    kubectl get svc <service-name> -n <namespace> -o yaml
    
    # 重点检查以下字段:
    # spec.selector: 是否正确关联到目标 Pod 的 label
    # spec.ports: 端口号、目标端口、协议是否正确
    # spec.type: ClusterIP / NodePort / LoadBalancer

    常见配置错误一:selector 写错

    # 错误示例:selector 写成了 app: web-frontend,但 Pod 的 label 是 app: web
    spec:
      selector:
        app: web-frontend  # 这个 selector 找不到任何 Pod

    正确做法:

    # 确认 Pod 实际的 label
    kubectl get pods -n <namespace> --show-labels
    
    # 查看 Service 的 selector 是否能匹配到 Pod
    kubectl get pods -n <namespace> -l app=web-frontend
    # 如果没有输出,说明 selector 写错了

    常见配置错误二:端口配置错误

    # 错误示例:targetPort 写成了字符串,但容器实际监听的端口是数字
    spec:
      ports:
      - port: 80
        targetPort: "http"  # 容器没有 named port "http",应该写 8080
        protocol: TCP

    3.2 确认 Endpoints 存在且健康

    Service 通过 Endpoints 关联到 Pod。如果 Endpoints 为空,说明 Service 找不到健康的后端:

    # 查看 Endpoints
    kubectl get endpoints <service-name> -n <namespace>
    
    # 正常输出:
    # NAME               ENDPOINTS
    # my-service         10.244.1.15:8080,10.244.2.23:8080
    # 如果为空:<none>
    
    # 查看 Endpoints 详细信息(关联了哪些 Pod IP 和端口)
    kubectl describe endpoints <service-name> -n <namespace>

    Endpoints 为空的排查方法

    Endpoints 为空通常有两个原因:selector 匹配不到 Pod,或者匹配的 Pod 没有 ready(readinessProbe 失败)。

    # 1. 确认 selector 是否匹配到 Pod
    kubectl get pods -n <namespace> --show-labels
    # 手动验证:Service selector 的每个 key-value 是否都能在 Pod label 中找到
    
    # 2. 确认 Pod 的 Ready 状态
    kubectl get pods -n <namespace> -o wide
    # 关注 Ready 列:应该是 1/1、2/2 等,如果不是,说明 readinessProbe 有问题
    
    # 3. 查看 Pod 的 readinessProbe 配置
    kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.containers
  • .readinessProbe}'
  • readinessProbe 配置错误的常见场景

    # 错误示例:readinessProbe HTTP 路径返回 404,但应用实际路径是 /api/health
    readinessProbe:
      httpGet:
        path: /healthz  # 应用没有 /healthz 端点
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 5

    3.3 测试从集群内部访问 Service

    从 Pod 内部访问 Service 是最基础的测试。如果这一步失败,说明 kube-proxy 或 CoreDNS 有问题:

    # 创建一个临时测试 Pod
    kubectl run -n <namespace> testpod --image=busybox:1.36 --restart=Never -it --rm -- sh
    
    # 在 Pod 内部执行以下测试:
    
    # 1. DNS 解析测试
    nslookup <service-name>
    # 正常输出:
    # Name:      <service-name>
    # Address:   <ClusterIP>
    
    # 如果 nslookup 失败(DNS 问题)
    nslookup kubernetes.default
    # 如果连 kubernetes 都解析不了,说明 CoreDNS 有问题
    
    # 2. 通过 Service IP 访问
    wget -qO- http://<ClusterIP>:<port>/healthz
    
    # 3. 通过 DNS 名称访问
    wget -qO- http://<service-name>.<namespace>.svc.cluster.local:<port>/healthz
    
    # 4. 测试不同端口(有些服务可能有多个端口)
    wget -qO- http://<service-name>.<namespace>.svc.cluster.local:<port>/
    
    # 如果 DNS 名称能解析但连接超时:
    # 说明 kube-proxy 没有正确转发流量,检查 kube-proxy
    
    # 如果 Connection refused:
    # 说明容器内端口没监听或 Service targetPort 配置错误

    3.4 测试 NodePort 类型 Service

    如果 Service 是 NodePort 类型,在所有节点的 NodePort 上都应该能访问:

    # 查看 NodePort
    kubectl get svc <service-name> -n <namespace> | grep NodePort
    
    # 输出示例:
    # <none>   NodePort: http  30080/TCP
    # NodePort 是 30080,在所有节点上都能通过 <任意节点IP>:30080 访问
    
    # 从集群外部测试(如果有 firewall 规则,需要先确认 NodePort 已放行)
    curl -v http://<任意节点IP>:30080/<path>
    
    # 如果某个节点能访问、另一个不能:
    # 检查不能访问的节点上 kube-proxy 是否正常
    ssh <目标节点> "systemctl status kube-proxy"

    第四步:排查 kube-proxy 层

    kube-proxy 是 Service 流量的转发引擎。它运行在每个节点上,监听 Service 和 Endpoints 的变化,动态更新本地的 iptables 或 ipvs 规则。如果 kube-proxy 异常,Service 流量转发就会失败。

    4.1 检查 kube-proxy 是否运行

    # kube-proxy 以 DaemonSet 形式运行
    kubectl get pods -n kube-system -l k8s-app=kube-proxy
    
    # 查看 kube-proxy 日志
    kubectl logs -n kube-system -l k8s-app=kube-proxy --tail=50
    
    # 如果 kube-proxy Pod 不在 Running,检查详情
    kubectl describe pod -n kube-system -l k8s-app=kube-proxy

    4.2 检查 kube-proxy 的转发模式

    kube-proxy 支持 iptables 和 ipvs 两种模式,默认是 iptables。排查方法有所不同:

    # 查看 kube-proxy 的启动参数,确认使用的是 iptables 还是 ipvs
    kubectl get configmap -n kube-system kube-proxy -o yaml | grep mode
    
    # 或者在节点上查看
    ssh <node> "grep mode /var/lib/kubelet/config.yaml"
    
    # iptables 模式:默认,性能稍差,但稳定
    # ipvs 模式:性能更好,但配置复杂,某些内核版本支持不好

    4.3 iptables 模式排查

    # SSH 到某个节点上查看 iptables 规则
    
    # 1. 查看 NAT 表中关于某个 Service 的规则
    # 注意:规则很多,直接 grep
    ssh <node> "sudo iptables -t nat -L -n | grep <service-name>"
    
    # 输出示例:
    # KUBE-SVC-XXXXXXXX  tcp  --  anywhere  10.109.12.34  tcp dpt:80
    # KUBE-SEP-XXXXXXXX  tcp  --  anywhere  anywhere  statistic mode: probability mode: random 0.500000000
    # KUBE-SEP-XXXXXXXX  tcp  --  anywhere  10.244.1.15  tcp dpt:8080
    
    # KUBE-SVC-XXXXXXXX 是 Service 对应的链
    # KUBE-SEP-XXXXXXXX 是具体 Endpoint 的链
    # 如果没有这些规则,说明 kube-proxy 没有为这个 Service 生成规则
    
    # 2. 查看 KUBE-SERVICES 链中是否有该 Service
    ssh <node> "sudo iptables -t nat -L KUBE-SERVICES -n | grep <service-name>"
    
    # 3. 查看 FILTER 表的 FORWARD 链
    ssh <node> "sudo iptables -t filter -L FORWARD -n | grep KUBE"
    
    # 如果 FORWARD 链没有 ACCEPT KUBE 相关的规则,可能 kube-proxy 没有正确处理流量

    4.4 ipvs 模式排查

    # SSH 到节点上查看 ipvs 规则
    ssh <node> "sudo ipvsadm -L -n"
    
    # 正常输出:
    # IP Virtual Server version 1.2.1 (size=4096)
    # TCP  <ServiceIP>:80 rr
    #   -> <EndpointIP>:8081          Masq    1      0          0
    #   -> <EndpointIP>:8082          Masq    1      0          0
    
    # 如果 ipvsadm 没有安装或 ipvs 模块未加载,kube-proxy 会回退到 iptables
    # 检查 ipvs 模块是否加载
    ssh <node> "lsmod | grep ip_vs"

    4.5 kube-proxy 日志分析

    # 查看 kube-proxy 是否有报错
    kubectl logs -n kube-system -l k8s-app=kube-proxy | grep -i error
    
    # 常见错误:
    # "Failed to delete service" - 删除 Service 时清理规则失败
    # "Failed to sync iptables" - 同步规则失败,可能是权限问题
    # "ipvs struct not found" - ipvs 模式下某些连接状态异常

    第五步:排查网络插件层(CNI)

    如果 Service 和 kube-proxy 都正常,但 Pod 之间还是不通,问题可能在 CNI(容器网络接口)层。CNI 负责 Pod IP 分配和 Pod 之间的网络连通性。

    5.1 确认 Pod 网络是否正常

    # 在有问题的 Pod 内测试
    kubectl exec -it <pod-name> -n <namespace> -- /bin/sh
    
    # 测试到另一个 Pod 的连通性(通过 Pod IP,不是 Service IP)
    ping -c 3 <另一个Pod的IP>
    
    # 测试到网关的连通性
    ip route
    # 默认网关应该是 CNI 网桥或 flannel.1 / calico* 等接口
    
    # 如果 ping 不通:
    # 1. 确认两边的 Pod 是否在同一个网段
    # 2. 确认 CNI 插件创建的接口是否存在
    ip addr | grep -E "flannel|calico|cni|docker"

    5.2 常见 CNI 插件排查

    Flannel 排查

    # 查看 flannel 是否为所有节点创建了网络
    kubectl get pods -n kube-system -l app=flannel
    
    # 在节点上查看 flannel.1 接口
    ip addr show flannel.1
    
    # 查看 flannel 的网络范围(Pod CIDR)
    kubectl get cm -n kube-system kube-flannel-cfg -o yaml | grep -A 3 "net-conf.json"
    
    # 典型问题:节点 Pod CIDR 没有被 flannel 分配
    # 在节点上查看:
    ip addr show flannel.1
    # 如果 flannel.1 没有 UP,说明该节点的 CNI 网络没有正常初始化

    Calico 排查

    # 查看 calico-node 是否 Running
    kubectl get pods -n kube-system -l k8s-app=calico-node
    
    # 查看 calico-node 日志
    kubectl logs -n kube-system -l k8s-app=calico-node --tail=100
    
    # 查看 BGP 对等连接(需要 calicoctl)
    calicoctl node status
    
    # 查看 IP 池
    calicoctl get ippool -o wide
    
    # 典型问题:节点没有分配到 IP 池地址
    # 查看节点 IP 分配情况
    calicoctl get workloadendpoints -o wide

    5.3 跨节点 Pod 通信测试

    # 获取两个不同节点上 Pod 的 IP
    kubectl get pods -o wide --all-namespaces | grep Running
    
    # 在源 Pod 内测试到目标 Pod IP 的连通性
    kubectl exec -it <源Pod> -n <namespace> -- ping -c 5 <目标PodIP>
    
    # 如果同节点 Pod 通信正常,跨节点不通:
    # 1. 检查源节点到目标节点的路由(VPC 或物理网络层)
    # 2. 检查 CNI 的跨节点隧道是否正常(flannel 用 VXLAN,calico 可以用 BGP 或 VXLAN)
    # 3. 检查是否有防火墙规则阻止了 CNI 隧道端口(flannel UDP 8472,Calico IP-in-IP 4)
    
    # 测试特定端口(如果 ping 通了但服务访问不通,可能是防火墙或端口问题)
    kubectl exec -it <源Pod> -n <namespace> -- nc -zv <目标PodIP> <端口>

    第六步:排查 Ingress 层

    如果 Service 本身正常,但通过 Ingress 访问不通,问题就在 Ingress 层。Ingress 是外部流量的入口,也是配置最复杂的一层。

    6.1 确认 Ingress Controller 正常运行

    # Ingress Controller 通常部署在 kube-system 命名空间
    kubectl get pods -n kube-system | grep -E "ingress|nginx"
    
    # 常见 Ingress Controller:
    # nginx-ingress-controller(社区版或 Nginx Inc 版)
    # ingress-nginx(Kubernetes 官方维护的 nginx-ingress)
    # traefik
    
    # 如果 Ingress Controller 没有 Running:
    kubectl describe pod -n kube-system <ingress-controller-pod-name>
    
    # 如果 Ingress Controller Pod 重启频繁:
    kubectl logs -n kube-system <ingress-controller-pod-name> --previous | tail -50

    6.2 查看 Ingress 规则配置

    # 查看所有 Ingress 资源
    kubectl get ingress -A
    
    # 查看具体 Ingress 的配置
    kubectl get ingress <ingress-name> -n <namespace> -o yaml
    
    # 重点检查:
    # spec.rules: Host 和 Path 配置
    # spec.tls: HTTPS 证书配置
    # spec.backend: 默认后端(如果没有匹配规则时使用)

    6.3 确认 Ingress 和 Service 的关联

    # Ingress 的 backend.service.name 必须和目标 Service 名称一致
    kubectl get ingress <ingress-name> -n <namespace> -o jsonpath='{.spec.rules
  • .http.paths
  • .backend.service}' # 确认 Ingress backend 的 port 端口和 Service port 一致 kubectl get ingress <ingress-name> -n <namespace> -o jsonpath='{.spec.rules
  • .http.paths
  • .backend.service.port}'
  • 6.4 Ingress 日志分析

    # 查看 Ingress Controller 日志
    kubectl logs -n kube-system <ingress-controller-pod-name> -f --tail=100
    
    # 搜索访问日志
    # nginx-ingress-controller 日志格式:
    # <remote_IP> - <client_user> [<timestamp>] "<request_method> <request_path> <protocol>" <status_code> <body_bytes_sent> "<http_referrer>" "<http_user_agent>"
    
    # 搜索 502 / 503 / 504 错误
    kubectl logs -n kube-system <ingress-controller-pod-name> | grep " 502 \| 503 \| 504 "
    
    # 搜索特定 Host 的访问
    kubectl logs -n kube-system <ingress-controller-pod-name> | grep "Host: <domain>"
    
    # 如果没有日志输出,说明请求根本没到 Ingress Controller
    # 检查 DNS 解析、LB 配置、NodePort 是否正确

    6.5 逐层排查 Ingress 流量路径

    如果确认 Ingress 也有问题,按以下路径逐层排查:

    1. 外部 -> DNS 解析 -> Ingress Controller 的外部 IP/NodePort
    2. Ingress Controller -> Ingress 规则匹配 -> Backend Service
    3. Backend Service -> kube-proxy -> Endpoint -> Pod

    层级一:确认外部能访问到 Ingress Controller

    # 获取 Ingress Controller 的 NodePort 或 LoadBalancer IP
    kubectl get svc -n kube-system | grep -E "ingress|nginx"
    
    # 测试从外部直接访问 NodePort(绕过 DNS)
    curl -v http://<任意节点IP>:<NodePort>/<path>
    
    # 如果 NodePort 能访问,但域名访问不行:
    # 说明 DNS 解析有问题,域名没有解析到正确的 IP

    层级二:确认 Ingress 规则被正确加载

    # 查看 Ingress Controller 进程的配置(nginx.conf)
    kubectl exec -n kube-system <ingress-controller-pod-name> -- cat /etc/nginx/nginx.conf
    
    # 搜索对应的 server {} 块
    kubectl exec -n kube-system <ingress-controller-pod-name> -- grep -A 20 "server_name <domain>"
    
    # 确认 upstream {} 块中的 server 列表是否包含正确的 Endpoint IP
    kubectl exec -n kube-system <ingress-controller-pod-name> -- grep -A 10 "upstream <backend-service>"

    6.6 TLS/HTTPS 相关问题

    # 查看 Ingress 的 TLS 配置
    kubectl get ingress <ingress-name> -n <namespace> -o yaml | grep -A 10 tls
    
    # 常见 TLS 问题:
    # 1. Secret 不存在
    kubectl get secret <secret-name> -n <namespace>
    # 2. Secret 类型不是 kubernetes.io/tls
    # 3. 证书过期(Let's Encrypt 证书有效期 90 天)
    # 4. 证书和域名不匹配
    
    # 测试 HTTPS 访问
    curl -v https://<domain>/<path> --insecure
    
    # --insecure 参数跳过证书验证,用于排查是证书问题还是连接问题
    # 如果加 --insecure 能通,说明是证书配置问题

    第七步:排查 DNS 解析问题

    DNS 问题是导致“服务访问不通”的重灾区。Pod 访问 Service 通过 DNS 名称,如果 DNS 解析失败或缓慢,所有依赖 Service 名称的调用都会失败。

    7.1 测试 DNS 解析

    # 在 Pod 内测试 DNS
    kubectl exec -it <pod-name> -n <namespace> -- nslookup kubernetes.default
    kubectl exec -it <pod-name> -n <namespace> -- nslookup <service-name>.<namespace>.svc.cluster.local
    
    # 如果 nslookup 不存在,用 dig
    kubectl exec -it <pod-name> -n <namespace> -- apt-get update && apt-get install -y dnsutils
    kubectl exec -it <pod-name> -n <namespace> -- dig +short kubernetes.default.svc.cluster.local
    
    # 测试完整 DNS 名称
    kubectl exec -it <pod-name> -n <namespace> -- getent hosts <service-name>.<namespace>.svc.cluster.local

    7.2 查看 CoreDNS 状态

    # CoreDNS 通常以 Deployment 形式运行在 kube-system
    kubectl get pods -n kube-system -l k8s-app=kube-dns
    
    # 查看 CoreDNS 日志
    kubectl logs -n kube-system -l k8s-app=kube-dns --tail=100
    
    # 查看 CoreDNS 配置
    kubectl get configmap -n kube-system coredns -o yaml

    7.3 DNS 解析慢的常见原因

    DNS 解析本身不应该很慢,但如果 Pod 数量很大或 DNS 查询量很高,可能出现延迟。常见原因:

    • DNS 查询并发限制:Linux 内核对每个进程/容器的 DNS 并发查询有限制
    • ndots 配置过高:K8s 默认 ndots=5,意味着任何带 5 个以下点的名称都会先查集群 DNS 再查外部 DNS,导致所有外部 DNS 查询都走集群 DNS

    优化 ndots 配置(在 Pod 的 dnsPolicy 不为 Default 时生效):

    # 在 Pod spec 中添加 dnsConfig
    spec:
      dnsConfig:
        options:
        - name: ndots
          value: "2"  # 默认 5,改成 2 减少集群 DNS 查询
        - name: timeout
          value: "2"
        - name: attempts
          value: "2"

    第八步:排查网络策略(NetworkPolicy)

    如果以上所有层都正常,但流量就是不通,可能是 NetworkPolicy 阻止了流量。

    8.1 查看命名空间的 NetworkPolicy

    # 查看该命名空间是否应用了 NetworkPolicy
    kubectl get networkpolicy -n <namespace>
    
    # 查看具体的 NetworkPolicy 规则
    kubectl get networkpolicy <policy-name> -n <namespace> -o yaml

    8.2 常见 NetworkPolicy 配置错误

    # 错误示例:只允许特定标签的 Pod 访问
    spec:
      podSelector:
        matchLabels:
          role: frontend
      ingress:
      - from:
        - podSelector:
            matchLabels:
              role: nginx  # 只有带 nginx 标签的 Pod 能访问
    # 但实际请求来自其他标签的 Pod,所以被阻止

    临时测试:放行所有流量排查是否是 NetworkPolicy 问题

    # 如果确认是 NetworkPolicy 问题,需要临时放行,可以先删除 Policy
    kubectl delete networkpolicy <policy-name> -n <namespace>
    
    # 或者临时添加一条允许所有流量的 Policy
    kubectl apply -f - <<EOF
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: allow-all
      namespace: <namespace>
    spec:
      podSelector: {}
      ingress:
      - {}
    EOF

    第九步:综合故障案例

    案例一:Service 有 Endpoint 但返回 502

    现象:Service 的 Endpoints 列表正常(有 IP 有端口),但通过 Ingress 访问返回 502。

    排查过程

    # 1. 确认 Service 和 Endpoint 配置
    kubectl get svc my-service -n default
    kubectl get endpoints my-service -n default
    # 输出正常,Endpoint 数量和 Pod 数量一致
    
    # 2. 从 Pod 内直接访问 Service(绕过 Ingress)
    kubectl run -n default curl-test --image=curlimages/curl --restart=Never -it --rm -- sh
    # curl http://my-service.default.svc.cluster.local:8080/api/health
    # 能正常返回
    
    # 3. 通过 Ingress 访问返回 502
    curl http://<ingress-ip>/api/health
    # 返回 502
    
    # 4. 查看 Ingress Controller 日志
    kubectl logs -n kube-system nginx-ingress-controller-xxx | grep "/api/health"
    # 日志显示:"upstream timed out (110: Connection timed out)"
    
    # 5. 确认问题:Ingress Controller 无法连接到后端 Service
    # 检查 Ingress Controller 和后端是否在同一个网络
    # 发现:Ingress Controller 在 kube-system 命名空间,应用在 default 命名空间
    # 但 NetworkPolicy 默认允许同集群内通信,所以不是这个原因
    
    # 6. 实际根因:应用的重试机制导致请求携带无效的 "Host" 头
    # Ingress Controller 的 upstream 配置中 server_name 和请求头中的 Host 不匹配
    # 修复:调整 Ingress 的 host 字段或者应用的 Host 头

    修复方案

    # 在 Ingress 中明确指定 backend 的 serviceName 和 servicePort
    spec:
      rules:
      - host: api.example.com
        http:
          paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: my-service
                port:
                  number: 8080

    案例二:Pod 之间通过 Headless Service 无法互相发现

    现象:部署了有状态应用(MySQL 主从),使用 Headless Service,但 Pod 之间无法通过 DNS 互相发现。

    排查过程

    # 1. 确认 Headless Service 配置
    kubectl get svc mysql-headless -n database -o yaml
    
    # 关键字段:
    # clusterIP: None  <-- 这个 None 是 Headless Service 的标志
    # spec:
    #   selector:
    #     app: mysql
    
    # 2. 确认 Pod 的 DNS 记录
    kubectl exec -it mysql-0 -n database -- nslookup mysql-headless.database.svc.cluster.local
    # 正常情况下应该返回所有匹配的 Pod IP
    
    # 3. 如果 DNS 记录为空,检查:
    # - selector 是否能匹配到 Pod label
    kubectl get pods -n database -l app=mysql --show-labels
    
    # - StatefulSet 的 serviceName 是否和 Headless Service 名称一致
    kubectl get statefulset mysql -n database -o jsonpath='{.spec.serviceName}'

    根因:StatefulSet 的 serviceName 必须和 Headless Service 名称完全一致,否则 Pod 的 DNS 记录不会生成。

    第十步:预防措施

    10.1 建立服务可达性巡检

    下面这个简单的 Bash 脚本可用于命令行巡检,建议配合 Prometheus 告警使用:

    #!/bin/bash
    # save as: k8s_service_health_check.sh
    # 建议配合 Prometheus 告警使用,这里提供命令行巡检方式
    
    NAMESPACES=$(kubectl get ns -o jsonpath='{.items
  • .metadata.name}' | tr ' ' '\n' | grep -v kube-system) for NS in $NAMSPACES; do   # 找出所有非 Headless 的 ClusterIP Service   SERVICES=$(kubectl get svc -n $NS -o json | jq -r '.items[] | select(.spec.clusterIP != "None") | select(.spec.clusterIP != "") | .metadata.name')   for SVC in $SERVICES; do     ENDPOINTS=$(kubectl get endpoints $SVC -n $NS -o json | jq '.subsets | length')     if [ "$ENDPOINTS" == "0" ] || [ "$ENDPOINTS" == "null" ]; then       echo "[ALERT] Service $SVC in namespace $NS has NO endpoints"     fi   done done echo "巡检完成"
  • 10.2 Ingress 和 Service 关联性校验

    每次部署新服务时,用以下命令校验 Ingress 和 Service 的关联是否正确:

    #!/bin/bash
    # 检查所有 Ingress 资源对应的 Service 是否存在且有 Endpoints
    
    for INGRESS in $(kubectl get ingress -A -o jsonpath='{.items
  • .metadata.name}'); do   NS=$(kubectl get ingress $INGRESS -A -o jsonpath='{.items[0].metadata.namespace}')   SVC=$(kubectl get ingress $INGRESS -n $NS -o jsonpath='{.spec.rules[0].http.paths[0].backend.service.name}')   PORT=$(kubectl get ingress $INGRESS -n $NS -o jsonpath='{.spec.rules[0].http.paths[0].backend.service.port.number}')   echo "Ingress: $INGRESS, Service: $SVC, Port: $PORT"   EP_COUNT=$(kubectl get endpoints $SVC -n $NS -o json 2>/dev/null | jq '.subsets | map(.addresses) | flatten | length')   if [ "$EP_COUNT" == "0" ] || [ "$EP_COUNT" == "null" ]; then     echo "  [WARNING] Service $SVC has no endpoints!"   fi done
  • 10.3 Pod readinessProbe 配置规范

    # 标准 Spring Boot 应用的 readinessProbe 配置
    readinessProbe:
      httpGet:
        path: /actuator/health/readiness
        port: 8080
      initialDelaySeconds: 30  # 等待应用启动
      periodSeconds: 10        # 每 10 秒检查一次
      timeoutSeconds: 5        # 超时 5 秒算失败
      successThreshold: 1      # 成功 1 次即 Ready
      failureThreshold: 3      # 连续失败 3 次才标记 NotReady
    
    # 标准 Golang 应用的 readinessProbe 配置
    readinessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
      failureThreshold: 3

    总结

    K8s 服务访问不通的问题,排查核心在于分层定位、逐层排除。推荐按以下优先级排查:

    第一优先级(5 分钟内定位)

    1. Pod 是否 Running、Ready,日志是否正常
    2. Service 的 Endpoints 是否有关联的 Pod IP
    3. 从 Pod 内直接访问 Service IP(绕过 Ingress 和 NodePort)

    第二优先级(5-15 分钟)

    1. kube-proxy 的 iptables/ipvs 规则是否正确生成
    2. CNI 插件是否正常(flannel.1 / calico* 接口是否存在)
    3. Ingress Controller 是否 Running,日志是否有 502/503 错误

    第三优先级(15 分钟以上)

    1. DNS 解析是否正常(CoreDNS 日志、ndots 配置)
    2. NetworkPolicy 是否阻止了合法流量
    3. 跨节点网络路由是否正确(VPC/物理网络层)

    关键原则

    • 始终从 Pod 层开始,往上排查。Pod 正常是 Service 正常的前提
    • kubectl get endpoints 判断 Service 是否有关联的 Pod,是最快速的诊断方法
    • Ingress 访问问题,80% 是 Ingress 和 Service 关联配置错误,20% 是 Ingress Controller 自身问题
    • NetworkPolicy 问题隐蔽性最强,排查到最后才考虑

    记住排查口诀:先 Pod 再 Svc,EP 不为空则网络通;Ingress 有问题先看日志,DNS 不通查 CoreDNS

    更多 Kubernetes 运维实践经验,欢迎访问云栈社区交流。




    上一篇:Agent记忆重构框架MemHarness:像人类一样评估改写经验,GRPO端到端训练
    下一篇:Oracle RAC中负责集群节点资源互斥访问的核心组件是哪个?LMON原理解析
    您需要登录后才可以回帖 登录 | 立即注册

    手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

    GMT+8, 2026-8-5 10:12 , Processed in 1.250425 second(s), 41 queries , Gzip On.

    Powered by Discuz! X3.5

    © 2025-2026 云栈社区.

    快速回复 返回顶部 返回列表