技术排查报告:Kubernetes Ingress 路由异常

4 阅读3分钟

一、事件概述

在 Kubernetes 集群中新增 Ingress:

host: tool.xxx.com
service: tools:80

后,访问域名始终返回:

404 Not Found
nginx

业务目标:

tool.xxx.com
→ ingress-nginx
→ tools service
→ nginx pod

实际现象:

  • Pod 内 curl 127.0.0.1 正常
  • Service / Endpoint 正常
  • Ingress 对象存在
  • 但外部始终 404
  • 新增 Ingress 不生效

最终定位为:

集群中已有历史 Ingress 配置导致 ingress-nginx 全局 reload 持续失败

从而导致:

所有新增/变更 ingress 永远无法真正生效

二、环境信息

1. Ingress Controller

镜像版本:

registry.cn-beijing.aliyuncs.com/kubesphereio/nginx-ingress-controller:v1.3.1

Controller 参数:

--controller-class=k8s.io/ingress-nginx
--ingress-class=nginx
--watch-ingress-without-class=true

2. 集群架构

Internet
   ↓
华为云 SLB(L4)
   ↓
Ingress Controller Pod
192.168.0.102
192.168.0.91
   ↓
K8s Service
   ↓
Backend Pod

三、问题现象

1. 域名访问异常

访问:

http://tool.xxx.com

返回:

404 Not Found
nginx

2. Pod 内业务正常

进入 tools pod:

curl 127.0.0.1

返回正常 HTML 页面:

<title>hellolbb</title>

说明:

  • Pod 正常
  • nginx 正常
  • root/index 正常

3. Ingress 对象存在

kubectl describe ingress -n lbbtest tools-route

结果:

tool.lishicloud.com
/ -> tools:80

且:

Scheduled for sync

说明:

Ingress Controller 已 watch 到 ingress 对象

4. nginx 配置中不存在对应 host

在 ingress controller pod 内:

nginx -T | grep tool.lishicloud.com

无任何结果。

说明:

Ingress Controller 未成功生成对应 routing 配置

四、排查过程

阶段1:基础链路验证

验证项

Pod

curl 127.0.0.1

正常

Service

kubectl get svc
kubectl get endpoints

正常。

SLB

确认为:

L4 TCP 转发

排除:

  • Host 被改写
  • 七层转发问题

阶段2:Ingress Controller 排查

查看 controller 配置

nginx -T

未发现:

tool.lishicloud.com

相关 server block。

说明:

Ingress 未真正进入 nginx routing

阶段3:查看 Controller Pod Event

执行:

kubectl describe pod

发现大量:

Error reloading NGINX

并持续:

x600+ over 7d

说明:

ingress-nginx reload 已长期失败

五、根因定位

最终错误:

location "^/rtsp/" cannot be inside the exact location "/doc.html"

此前还有:

location "^/material" cannot be inside the exact location "/doc.html"

六、问题 Ingress 定位

定位到:

namespace: com-srv
name: datashow-server

存在:

nginx.ingress.kubernetes.io/server-snippet:
  location = /doc.html {
      deny all;
      return 403;

同时:

path: /material
path: /rtsp/

七、技术原理分析

Ingress-nginx 会自动生成:

location ^/material
location ^/rtsp/

而:

location = /doc.html

属于:

Exact Location

Nginx 禁止:

在 Exact Location 内嵌套 Prefix/Regex Location

最终生成非法 nginx 配置:

location = /doc.html {
    location ^/material {
    }
}

导致:

nginx -t fail
reload fail


八、为什么旧业务正常

因为:

reload fail != nginx 退出

Ingress-nginx 会继续运行:

最后一次成功的 nginx 配置

因此:

类型状态
旧 Ingress正常
新 Ingress永远不生效

这也是问题极具迷惑性的原因。

九、最终修复方案

删除:

nginx.ingress.kubernetes.io/server-snippet

避免:

location = /doc.html

注入。

十、修复后结果

修复后:

  • ingress-nginx reload 恢复正常
  • tool.lishicloud.com routing 正常生成
  • 新增 ingress 生效
  • 404 消失

十一、风险分析

当前集群存在:

  • 大量历史 ingress
  • regex path
  • rewrite-target
  • server-snippet
  • configuration-snippet

属于:

高风险 ingress 技术债环境

十二、改进建议

1. 升级 ingress-nginx

当前版本:

v1.3.1

过旧。

建议:

v1.8.x ~ v1.9.x

作为过渡升级目标。

2. 禁止使用 server-snippet

原则:

禁止业务侧直接注入原生 nginx location

避免:

  • reload 全局失败
  • nginx 配置树冲突
  • location merge 异常

3. 建立 ingress 规范

建议限制:

  • regex path
  • rewrite-target
  • snippet annotation

4. 建立 ingress lint / admission 校验

避免:

非法 nginx 配置进入生产环境

十三、经验总结

本次问题本质:

A ingress 配置错误
↓
ingress-nginx reload 全局失败
↓
B ingress 永远不生效
↓
误以为 B 有问题

属于:

典型 ingress-nginx 历史技术债问题

该案例说明:

Kubernetes Ingress 的真正复杂度不在 YAML

而在:

Ingress Controller 最终生成的 nginx 配置树