在 Kubernetes 集群中部署应用后,运维同学经常遇到这样的场景:Deployment 创建了,Pod 状态是 Running,Service 也配置了,Ingress 规则也写好了,但外部用户就是访问不到服务。浏览器返回 502、503 或者直接超时,curl 测试也没有响应。
这种问题特别让人抓狂,因为每一层看起来都是正常的:Pod 没有 CrashLoopBackOff,Service Endpoints 有 IP,Ingress 配置语法也没错。但整个链路就是不通。问题可能出在 Ingress Controller 配置、Service 端口映射、Pod 网络策略、kube-proxy 规则、DNS 解析、负载均衡器健康检查,甚至云厂商的安全组规则。
本文面向初中级 Kubernetes 运维工程师和 DevOps 工程师,演示如何在 Ingress 配置后外部访问不通的场景下,从外到内逐层排查:先确认 Ingress Controller 状态,再验证 Service 和 Endpoints,再测试 Pod 网络连通性,最后排查 DNS、负载均衡器和安全组。读者能照着文章操作、观察日志、判断根因,并制定对应的修复方案。
本文适用于以下场景:
不适用场景:
外部请求到达 Pod 的完整路径:
外部客户端 ↓ DNS 解析(域名 → LoadBalancer IP) ↓ 云厂商 LoadBalancer / NodePort / HostNetwork ↓ Ingress Controller Pod(Nginx、Traefik、HAProxy 等) ↓ Kubernetes Service(ClusterIP) ↓ kube-proxy iptables/ipvs 规则 ↓ Pod IP ↓ 应用容器端口 排查时要从外往内走,每一层都验证连通性和配置。
Ingress 本身只是一个配置对象,描述了"哪个域名、哪个路径应该转发到哪个 Service"。真正干活的是 Ingress Controller,它是一个运行在集群中的 Pod(通常是 Nginx、Traefik、HAProxy、Istio Gateway 等),会监听 Ingress 对象的变化,动态生成反向代理配置,然后将流量转发到后端 Service。
Ingress Controller 通过以下方式暴露给外部:
Service 是一个虚拟 IP(ClusterIP),流量到达 Service 后,kube-proxy 会根据 iptables 或 ipvs 规则将流量转发到后端 Pod。Service 后端 Pod 列表由 Endpoints 对象维护。
如果 Endpoints 为空,说明没有 Pod 匹配 Service 的 selector,流量无法转发。
NetworkPolicy 可以限制 Pod 之间的网络访问。如果配置了 NetworkPolicy,可能导致 Ingress Controller Pod 无法访问后端 Pod。
外部访问失败 ↓ 1. 确认 Ingress Controller Pod 状态和日志 ↓ 2. 确认 Ingress 规则语法和 Service 引用 ↓ 3. 确认 Service 和 Endpoints 是否有后端 Pod ↓ 4. 确认后端 Pod 状态和监听端口 ↓ 5. 测试 Ingress Controller → Service → Pod 的网络连通性 ↓ 6. 排查 NetworkPolicy ↓ 7. 排查 DNS 解析 ↓ 8. 排查 LoadBalancer / NodePort 配置 ↓ 9. 排查云厂商安全组、防火墙 ↓ 10. 根据以上信息定位根因并修复 分层逐步验证:
确认 Ingress Controller 本身是否正常运行。
bash
# 查看 Ingress Controller Pod(常见命名空间:ingress-nginx、kube-system、istio-system) kubectl get pods -n ingress-nginx kubectl get pods -n kube-system | grep ingress kubectl get pods -A | grep ingress # 查看 Pod 详情 kubectl describe pod -n ingress-nginx # 查看 Pod 日志 kubectl logs -n ingress-nginx -- tail=100 kubectl logs -n ingress-nginx -f
Pod 状态应该是 Running,Ready 应该是 1/1 或 2/2(根据容器数量):
NAME READY STATUS RESTARTS AGE ingress-nginx-controller-5d88495688-abcde 1/1 Running 0 10d 日志应该没有严重错误,能看到启动信息和配置加载记录:
2026-08-26 1000 [notice] 1#1: start worker processes 2026-08-26 1000 [notice] 1#1: nginx configuration is reloaded Pending、CrashLoopBackOff、ImagePullBackOff → Ingress Controller 本身没启动0/1 → 容器启动失败或健康检查失败failed to load configuration、failed to update Ingress status、upstream connect error → 配置加载失败或后端不可达记录 Ingress Controller 的命名空间、Pod 名称、日志关键信息。
确认 Ingress Controller 是否正确暴露给外部。
bash
# 查看 Ingress Controller Service kubectl get svc -n ingress-nginx kubectl get svc -n kube-system | grep ingress # 查看 Service 详情 kubectl describe svc -n ingress-nginx
Service 类型应该是 LoadBalancer、NodePort 或者 Controller Pod 使用 hostNetwork: true:
LoadBalancer 类型:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx-controller LoadBalancer 10.96.100.100 203.0.113.50 80:32080/TCP,443:32443/TCP 10d
EXTERNAL-IP 应该是一个公网 IP(云厂商分配),不应该是 或 。
NodePort 类型:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx-controller NodePort 10.96.100.100 80:32080/TCP,443:32443/TCP 10d 可以通过任意 NodeIP:32080 访问。
hostNetwork 类型:
如果 Controller Pod 使用 hostNetwork: true,Service 可能不需要 LoadBalancer 或 NodePort,直接通过 Node IP 的 80/443 端口访问。
bash
# 检查 Pod 是否使用 hostNetwork kubectl get pod -n ingress-nginx -o yaml | grep hostNetwork EXTERNAL-IP 是 → 云厂商 LoadBalancer 未分配,检查云厂商配额、权限EXTERNAL-IP 是 且类型不是 NodePort → Ingress Controller 没有暴露方式记录 Ingress Controller 的外部访问入口(LoadBalancer IP、NodePort、Node IP)。
确认能否访问到 Ingress Controller 的默认后端或健康检查端点。
bash
# 如果是 LoadBalancer curl -I http:// curl -I http:///healthz # 如果是 NodePort curl -I http://: curl -I http://:/healthz # 如果是 hostNetwork curl -I http:// curl -I http:///healthz # 测试 HTTPS(如果配置了证书) curl -Ik https:// 应该能收到响应,即使是 404 或 default backend 也说明 Ingress Controller 可达:
HTTP/1.1 404 Not Found Server: nginx Date: Tue, 26 Aug 2026 1000 GMT Content-Type: text/html Content-Length: 146 Connection: keep-alive 或者:
HTTP/1.1 200 OK Server: nginx Date: Tue, 26 Aug 2026 1000 GMT Content-Type: text/plain Content-Length: 2 Connection: keep-alive ok 如果入口正常,继续下一步。
确认 Ingress 规则语法正确,backend Service 存在,host 和 path 匹配。
bash
# 查看 Ingress 资源 kubectl get ingress -A kubectl get ingress -n # 查看 Ingress 详情 kubectl describe ingress -n # 查看 Ingress YAML kubectl get ingress -n -o yaml yaml
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: example-ingress namespace: default spec: ingressClassName: nginx # 或者通过 annotation 指定 rules: - host: example.com http: paths: - path: /api pathType: Prefix backend: service: name: backend-service port: number: 8080
kubectl describe ingress 输出:
Name: example-ingress Namespace: default Address: 203.0.113.50 Ingress Class: nginx Rules: Host Path Backends ---- ---- -------- example.com /api backend-service:8080 (10.244.1.10:8080,10.244.2.20:8080) 关键字段:
Address:应该是 Ingress Controller 的 LoadBalancer IP,如果是空或 ,说明 Controller 没有更新 Ingress 状态Ingress Class:应该匹配 Ingress Controller 的 ingressClassNameBackends:应该显示 Service 名称、端口和 Endpoints IPAddress 是空 → Ingress Controller 没有更新 Ingress 状态,检查 Controller 日志Backends 显示 或 → Service 不存在或 Endpoints 为空Ingress Class 不匹配 → Ingress 不会被当前 Controller 处理host 或 path 配置错误 → 请求不会匹配到这个 IngressAddress 是空 → 检查 Ingress Controller 权限和日志Backends 显示错误 → 检查 Service 和 Endpoints记录 Ingress 的 host、path、backend Service 名称和端口。
确认 Service 存在,Endpoints 有后端 Pod IP,端口映射正确。
bash
# 查看 Service kubectl get svc -n # 查看 Service 详情 kubectl describe svc -n # 查看 Service YAML kubectl get svc -n -o yaml # 查看 Endpoints kubectl get endpoints -n # 查看 Endpoints 详情 kubectl describe endpoints -n Service:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE backend-service ClusterIP 10.96.200.100 8080/TCP 5d Endpoints:
NAME ENDPOINTS AGE backend-service 10.244.1.10:8080,10.244.2.20:8080 5d 或者:
bash
kubectl describe endpoints backend-service -n default 输出:
Name: backend-service Namespace: default Labels: Annotations: Subsets: Addresses: 10.244.1.10,10.244.2.20 NotReadyAddresses: Ports: Name Port Protocol ---- ---- -------- http 8080 TCP 或显示 NotReadyAddresses → 没有 Ready 的 Pod记录 Endpoints 中的 Pod IP 和端口。
确认 Pod 是否 Running,标签是否匹配 Service selector,端口是否监听。
bash
# 查看 Pod kubectl get pods -n -l # 查看 Pod 详情 kubectl describe pod -n # 查看 Pod 标签 kubectl get pod -n --show-labels # 检查 Service selector kubectl get svc -n -o jsonpath= '{.spec.selector}' # 进入 Pod 检查监听端口 kubectl exec -it -n -- netstat -tlnp kubectl exec -it -n -- ss -tlnp Pod 状态:
NAME READY STATUS RESTARTS AGE backend-deployment-5d88495688-abc 1/1 Running 0 5d backend-deployment-5d88495688-def 1/1 Running 0 5d Pod 标签:
NAME READY STATUS RESTARTS AGE LABELS backend-deployment-5d88495688-abc 1/1 Running 0 5d app=backend,version=v1 Service selector:
json
{"app":"backend"} 监听端口:
Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 1/python 0/1 → 健康检查失败确认 Pod 正常后,测试网络连通性。
确认 Ingress Controller Pod 能否访问后端 Service。
bash
# 进入 Ingress Controller Pod kubectl exec -it -n ingress-nginx -- /bin/sh # 在 Controller Pod 中测试 Service curl http://..svc.cluster.local: # 或者直接测试 ClusterIP curl http://: # 退出 exit 应该能收到后端应用的响应:
HTTP/1.1 200 OK Content-Type: application/json Content-Length: 123 {"status":"ok"} 如果连通性正常,回到 Ingress 规则排查。
绕过 Service,直接访问 Pod IP,排除 kube-proxy 规则问题。
bash
# 获取 Pod IP kubectl get pod -n -o jsonpath= '{.status.podIP}' # 进入 Ingress Controller Pod 或其他 Pod kubectl exec -it -n ingress-nginx -- /bin/sh # 直接访问 Pod IP curl http://: # 退出 exit 应该能收到后端应用的响应。
根据测试结果排查对应层面。
确认是否有 NetworkPolicy 阻止 Ingress Controller 访问后端 Pod。
bash
# 查看所有 NetworkPolicy kubectl get networkpolicy -A # 查看特定命名空间的 NetworkPolicy kubectl get networkpolicy -n # 查看 NetworkPolicy 详情 kubectl describe networkpolicy -n # 查看 NetworkPolicy YAML kubectl get networkpolicy -n -o yaml 如果没有 NetworkPolicy,输出为空:
No resources found in namespace.
如果有 NetworkPolicy,检查 podSelector 和 ingress 规则是否允许 Ingress Controller 访问:
yaml
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: backend-policy namespace: default spec: podSelector: matchLabels: app: backend policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: name: ingress-nginx ports: - protocol: TCP port: 8080 如果 NetworkPolicy 正常,继续排查外部访问。
确认域名解析是否指向 Ingress Controller 的 LoadBalancer IP 或 NodePort。
bash
# 本地测试 DNS 解析 nslookup example.com dig example.com # 在集群外的客户端测试 curl -v http://example.com/api DNS 解析应该返回 Ingress Controller 的 EXTERNAL-IP:
Server:8.8.8.8 Address:8.8.8.8#53 Non-authoritative answer: Name:example.com Address: 203.0.113.50 如果 DNS 正确,使用 curl 测试完整请求。
模拟真实请求,观察返回结果和错误信息。
bash
# 测试 HTTP 请求,显示详细信息 curl -v http://example.com/api # 测试 HTTPS 请求 curl -vk https://example.com/api # 指定 Host 头(如果 DNS 未配置) curl -v -H "Host: example.com" http:///api # 查看响应头 curl -I http://example.com/api 应该收到后端应用的响应:
< HTTP/1.1 200 OK < Server: nginx < Date: Tue, 26 Aug 2026 1000 GMT < Content-Type: application/json < Content-Length: 123 < {"status":"ok"} HTTP/1.1 502 Bad Gateway → Ingress Controller 无法连接后端HTTP/1.1 503 Service Unavailable → 后端无可用 PodHTTP/1.1 504 Gateway Timeout → 后端响应超时HTTP/1.1 404 Not Found → Ingress 规则不匹配或路径错误根据错误码排查对应层面。
从 Ingress Controller 视角看请求处理过程和错误信息。
bash
# 实时查看日志 kubectl logs -n ingress-nginx -f # 查看最近 100 行 kubectl logs -n ingress-nginx -- tail=100 # 过滤特定域名或路径 kubectl logs -n ingress-nginx | grep "example.com" kubectl logs -n ingress-nginx | grep "/api" 正常情况下,能看到访问日志:
203.0.113.100 - - [26/Aug/202600:00 +0000] "GET /api HTTP/1.1" 200 123 "-" "curl/7.68.0" 0.005 502 或 503 且日志显示 no live upstreams → Endpoints 为空502 且日志显示 upstream prematurely closed connection → Pod 主动关闭连接502 且日志显示 connect() failed (111: Connection refused) → Pod 端口未监听504 且日志显示 upstream timed out → Pod 响应慢根据日志中的错误信息定位问题层面。
根据日志定位根因。
确认云厂商的 LoadBalancer 健康检查、监听器、安全组配置正确。
登录云厂商控制台,检查:
根据云厂商控制台信息排查。
根据云厂商配置调整。
确认 Node 防火墙和云厂商安全组放行 Ingress Controller 使用的端口。
bash
# 在 Node 上检查 iptables 规则 iptables -L -n -v | grep # 检查 firewalld 状态 systemctl status firewalld firewall-cmd --list-all # 检查 ufw 状态 ufw status # 测试从外部访问 NodePort curl http://: 云厂商安全组:
根据防火墙和安全组规则调整。
修复防火墙或安全组配置。
bash
# 查看 Ingress kubectl get ingress -A kubectl describe ingress -n kubectl get ingress -n -o yaml # 查看 Ingress Controller Pod kubectl get pods -n ingress-nginx kubectl logs -n ingress-nginx -f kubectl describe pod -n ingress-nginx # 查看 Service kubectl get svc -n kubectl describe svc -n # 查看 Endpoints kubectl get endpoints -n kubectl describe endpoints -n # 查看 Pod kubectl get pods -n -l kubectl describe pod -n kubectl logs -n # 查看 NetworkPolicy kubectl get networkpolicy -A kubectl describe networkpolicy -n # 进入 Pod kubectl exec -it -n -- /bin/sh # 端口转发(调试用) kubectl port-forward svc/ 8080:8080 -n bash
# 基础测试 curl http://example.com/api curl https://example.com/api # 显示详细信息 curl -v http://example.com/api curl -vk https://example.com/api # 指定 Host 头 curl -H "Host: example.com" http:///api # 只显示响应头 curl -I http://example.com/api # 显示响应时间 curl -o /dev/null -s -w "%{time_total} " http://example.com/api bash
# DNS 解析 nslookup example.com dig example.com # 测试端口连通性 telnet nc -zv # 测试 HTTP wget -O- http://example.com/api yaml
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: example-ingress namespace: default annotations: nginx.ingress.kubernetes.io/rewrite-target: / nginx.ingress.kubernetes.io/ssl-redirect: "false" spec: ingressClassName: nginx rules: - host: example.com http: paths: - path: /api pathType: Prefix backend: service: name: backend-service port: number: 8080 tls: - hosts: - example.com secretName: example-tls yaml
apiVersion: v1 kind: Service metadata: name: backend-service namespace: default spec: selector: app: backend ports: - protocol: TCP port: 8080 targetPort: 8080 type: ClusterIP yaml
apiVersion: apps/v1 kind: Deployment metadata: name: backend-deployment namespace: default spec: replicas: 2 selector: matchLabels: app: backend template: metadata: labels: app: backend spec: containers: - name: backend image: myapp:v1.0 ports: - containerPort: 8080 livenessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /ready port: 8080 initialDelaySeconds: 5 periodSeconds: 5 yaml
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-ingress-controller namespace: default spec: podSelector: matchLabels: app: backend policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: name: ingress-nginx ports: - protocol: TCP port: 8080 说明:
namespaceSelector 匹配 Ingress Controller 所在命名空间(需要给命名空间打标签)ingress-nginx 命名空间,需要执行:bash
kubectl label namespace ingress-nginx name=ingress-nginx yaml
apiVersion: v1 kind: Service metadata: name: ingress-nginx-controller namespace: ingress-nginx spec: type: LoadBalancer selector: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/component: controller ports: - name: http port: 80 targetPort: http protocol: TCP - name: https port: 443 targetPort: https protocol: TCP yaml
apiVersion: v1 kind: Service metadata: name: ingress-nginx-controller namespace: ingress-nginx spec: type: NodePort selector: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/component: controller ports: - name: http port: 80 targetPort: http protocol: TCP nodePort: 32080 - name: https port: 443 targetPort: https protocol: TCP nodePort: 32443 bash
# 查看 502/503 错误 kubectl logs -n ingress-nginx | grep -E "502|503" # 查看 upstream 错误 kubectl logs -n ingress-nginx | grep "upstream" # 查看连接拒绝 kubectl logs -n ingress-nginx | grep "Connection refused" # 查看超时 kubectl logs -n ingress-nginx | grep "timeout" bash
# 查看应用启动日志 kubectl logs -n | head -50 # 查看错误日志 kubectl logs -n | grep -iE "error|exception|fail" # 查看健康检查日志 kubectl logs -n | grep -iE "health|ready" 如果有 Prometheus + kube-state-metrics,关注以下指标:
# Ingress 状态 kube_ingress_info kube_ingress_path # Service Endpoints 数量 kube_endpoint_address_available # Pod 状态 kube_pod_status_phase kube_pod_container_status_ready # Ingress Controller 指标(需要 Ingress Controller 暴露 metrics) nginx_ingress_controller_requests nginx_ingress_controller_request_duration_seconds nginx_ingress_controller_response_size # Ingress Controller 请求率 rate(nginx_ingress_controller_requests[1m]) # Ingress Controller 错误率 rate(nginx_ingress_controller_requests{status=~"5.."}[1m]) / rate(nginx_ingress_controller_requests[1m]) # Service Endpoints 数量 kube_endpoint_address_available{service="backend-service"} # Pod Ready 数量 sum(kube_pod_container_status_ready{pod=~"backend-.*"}) 现象:
HTTP/1.1 502 Bad Gatewayconnect() failed (111: Connection refused) 或 no live upstreams排查步骤:
修复方向:
现象:
HTTP/1.1 503 Service Unavailableno live upstreams排查步骤:
修复方向:
现象:
HTTP/1.1 504 Gateway Timeoutupstream timed out排查步骤:
修复方向:
现象:
HTTP/1.1 404 Not Found排查步骤:
修复方向:
现象:
curl: (28) Connection timed out排查步骤:
修复方向:
现象:
SSL certificate problem排查步骤:
修复方向:
建议:
建议:
kubectl apply 而不是 kubectl replace,方便回滚建议:
建议:
建议:
bash
# 检查 Pod 状态 kubectl get pods -n ingress-nginx # 检查 Service 外部 IP kubectl get svc -n ingress-nginx # 测试健康检查端点 curl http:///healthz 预期结果:
bash
# 检查 Endpoints kubectl get endpoints -n # 检查 Pod Ready 数量 kubectl get pods -n -l 预期结果:
bash
# 从 Ingress Controller Pod 访问 Service kubectl exec -it -n ingress-nginx -- curl http://: # 从 Ingress Controller Pod 访问 Pod IP kubectl exec -it -n ingress-nginx -- curl http://: 预期结果:
bash
# 测试 HTTP curl http://example.com/api # 测试 HTTPS curl https://example.com/api # 显示响应时间 curl -o /dev/null -s -w "%{http_code} %{time_total}s " http://example.com/api 预期结果:
bash
# 查看历史版本 kubectl rollout history ingress -n # 回滚到上一版本(注意:Ingress 不支持 rollout,需要手动恢复) kubectl apply -f # 或者编辑恢复 kubectl edit ingress -n bash
# 恢复备份 kubectl apply -f bash
# 删除新增的 NetworkPolicy kubectl delete networkpolicy -n # 恢复备份 kubectl apply -f kubectl get ingress -n -o yaml > backup.yaml Kubernetes Ingress 配置后外部访问不通是运维中常见问题,因为涉及的组件和配置层次多:Ingress Controller、Ingress 规则、Service、Endpoints、Pod、NetworkPolicy、DNS、LoadBalancer、安全组。本文演示了从外到内逐层排查的完整路径。
排查思路可以总结为:
每一步都要结合实际输出、日志、指标进行判断,不能靠猜测。修复方案要根据根因制定,验证要全面,回滚预案要提前准备。生产环境操作要谨慎,做好备份、灰度、监控、沟通。
掌握这套排查方法后,面对 Ingress 访问不通的问题时不再盲目,能快速定位根因,制定有效的修复方案,减少故障时间,提升服务可用性。
全部0条评论
快来发表一下你的评论吧 !