一、事件概述
在 Kubernetes 集群中新增 Ingress:
makefile
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
镜像版本:
bash
registry.cn-beijing.aliyuncs.com/kubesphereio/nginx-ingress-controller:v1.3.1
Controller 参数:
ini
--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. 域名访问异常
访问:
arduino
http://tool.xxx.com
返回:
404 Not Found
nginx
2. Pod 内业务正常
进入 tools pod:
curl 127.0.0.1
返回正常 HTML 页面:
xml
<title>hellolbb</title>
说明:
- Pod 正常
- nginx 正常
- root/index 正常
3. Ingress 对象存在
sql
kubectl describe ingress -n lbbtest tools-route
结果:
rust
tool.lishicloud.com
/ -> tools:80
且:
bash
Scheduled for sync
说明:
Ingress Controller 已 watch 到 ingress 对象
4. nginx 配置中不存在对应 host
在 ingress controller pod 内:
perl
nginx -T | grep tool.lishicloud.com
无任何结果。
说明:
Ingress Controller 未成功生成对应 routing 配置
四、排查过程
阶段1:基础链路验证
验证项
Pod
curl 127.0.0.1
正常
Service
arduino
kubectl get svc
kubectl get endpoints
正常。
SLB
确认为:
L4 TCP 转发
排除:
- Host 被改写
- 七层转发问题
阶段2:Ingress Controller 排查
查看 controller 配置
r
nginx -T
未发现:
tool.lishicloud.com
相关 server block。
说明:
Ingress 未真正进入 nginx routing
阶段3:查看 Controller Pod Event
执行:
sql
kubectl describe pod
发现大量:
javascript
Error reloading NGINX
并持续:
sql
x600+ over 7d
说明:
ingress-nginx reload 已长期失败
五、根因定位
最终错误:
arduino
location "^/rtsp/" cannot be inside the exact location "/doc.html"
此前还有:
arduino
location "^/material" cannot be inside the exact location "/doc.html"
六、问题 Ingress 定位
定位到:
makefile
namespace: com-srv
name: datashow-server
存在:
ini
nginx.ingress.kubernetes.io/server-snippet:
location = /doc.html {
deny all;
return 403;
同时:
bash
path: /material
path: /rtsp/
七、技术原理分析
Ingress-nginx 会自动生成:
bash
location ^/material
location ^/rtsp/
而:
ini
location = /doc.html
属于:
Exact Location
Nginx 禁止:
在 Exact Location 内嵌套 Prefix/Regex Location
最终生成非法 nginx 配置:
bash
location = /doc.html {
location ^/material {
}
}
导致:
nginx -t fail
reload fail
。
八、为什么旧业务正常
因为:
yaml
reload fail != nginx 退出
Ingress-nginx 会继续运行:
最后一次成功的 nginx 配置
因此:
| 类型 | 状态 |
|---|---|
| 旧 Ingress | 正常 |
| 新 Ingress | 永远不生效 |
这也是问题极具迷惑性的原因。
九、最终修复方案
删除:
bash
nginx.ingress.kubernetes.io/server-snippet
避免:
ini
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 配置进入生产环境
十三、经验总结
本次问题本质:
css
A ingress 配置错误
↓
ingress-nginx reload 全局失败
↓
B ingress 永远不生效
↓
误以为 B 有问题
属于:
典型 ingress-nginx 历史技术债问题
该案例说明:
Kubernetes Ingress 的真正复杂度不在 YAML
而在:
Ingress Controller 最终生成的 nginx 配置树