目前在做的专有云领域,一个基于 k8s 的容器云迁云项目, 集群稳定运行一年后,有天突然出现 P0 事故,全平台入口宕机,事后将 ingress 架构一拆为三,写了一篇博客记录; 但是对 ingress 了解不深,观点可能有失偏颇
所以发到 v2 上,给大佬们批评指正
原文地址(博客托管在 github pages 上,加载可能很慢,请见谅):👇🏻
1
oaa 216 天前
有点没懂。
“ 同时 Ingress 本身有一个 reload 机制,当检测到副本数从 N -> 0 或者 0 -> N 时,Ingress Controller 会同时触发两个 Ingress 的重载,开辟新的 worker 进程,并关闭老的 worker 进程; ” 你的意思是,如果后端 pod 挂了,Nginx-Ingress 会 reload ? |
2
Zaden 216 天前 4
第一反应是 ingress 游戏……
|
3
JoeJasper 216 天前 1
试试基于 envoy 的 Higress
|
4
easterfan OP @oaa 是的,后端 pod 副本是 1 ,Crash 后,副本数 1->0; 然后 k8s 会重启这个 pod ,把他的副本又从 0->1; 但是 0->1, 1->0, 都会触发 ingress reload ,触发的很频繁
|
5
lsk569937453 216 天前 3
有这么多 Ingress controller 的实现,包括但不限于 envoy,traefik,kong 。你不能因为一个 nginx ingress controller 出问题就否定整个 ingress 啊。
|
6
billzhuang 216 天前
TIL
"Ingress 本身有一个 reload 机制,当检测到副本数从 N -> 0 或者 0 -> N 时,Ingress Controller 会同时触发两个 Ingress 的重载,开辟新的 worker 进程,并关闭老的 worker 进程" 这个是 nginx ingress controller 干的么? |
7
easterfan OP @lsk569937453 感谢指正,哈哈哈 标题有点激进了,更正《冒死分析:nginx Ingress 没有准备好成为"统一流量入口"》
|
8
defunct9 216 天前
pod crash ,这个才是要命的原因吧。说的更极端点,后端的 pod 掉光了,前面有啥也没用啊。
|
9
easterfan OP @defunct9 是的,pod 没上测试集群,直接带缺陷上生产集群了;也是巧合,但是因为全平台入口宕机,事故影响面大,PaaS 平台得背锅 80% QAQ
|
12
adamwym 216 天前
如果 nginx 直接使用 service cluster ip 做 upstream 地址是不是就可以避免 pod 重启导致的 nginx 频繁 reload 了
|
13
adamwym 216 天前
|
14
isno 216 天前
看到 [冒死分析] ,有点眼熟...
你把 ingress 一分为三,但再碰到个“请求 CDP” 就 Crash 的 Pod 呢? 这个问题的 root cause 是频繁重启的 Pod ,如果监测到这样的 Pod ,就临时把这个服务从 ingress 摘掉,这样是不是更好点?或者看看 kong 、apisix 怎么解决的 |
15
egen 216 天前
可以看看 easegress
|
16
defunct9 216 天前
要命也不是 ingress ,UDP 用 ng 来转发也不对,根本无状态。换成 haproxy 估计会好。
|
17
cheng6563 216 天前
nginx ingress 不知是不是非云原生的原因,好像是这类问题不少,我之前还见过在 ingress annotations 配置的东西插入了 nginx 的全局配置把 nginx 搞挂的。
话说我司是用的 daemonset 跑的 traefik ingress |
18
feedcode 216 天前
> 一处理 UDP 请求,马上就 Crash 。首先出于 kubernetes 的自愈机制,deploy 控制器检测到副本数从 1 -> 0 后,会自动重启 pod ,控制副本数从 0 -> 1 ;
pod crash 后不是 kubelet 负责重启的吗,与 Deploy Controller 没啥关系。deploy 变动会触发 replicate set 变动,然后 Replication Controller 负责 pod 更新, 也就是说 Deploy Controller 管不到 pod 副本数 pod crash 后影响的是 Service 的 EndpointSlice , 不会直接影响 nginx config, 为啥会导致 nginx 重启 |
19
feedcode 216 天前
@cheng6563 nginx ingress controller 有 validation webhook, enable 之后可以挡掉 99%的无效 annotation
|
20
lasuar 216 天前
```
再同时供应商将 UDP 请求设置了一个超时机制,超时时间为 600s ,由于 pod 已经 crash ,所以连接一直在等待响应,虽然 Ingress 本身也有 worker 进程的超时时间,为 240s ,两者取最短,实际上 pod crash 状态出现时,每个 UDP 请求最多只等待 240s ,老的 worker 进程就会被关闭。但 240s 也是很长的时间了,已经足够发 N 多 UDP 请求,足够触发 N 次副本数 1->0, 0->1 的变化使 Ingress reload 多次,足够发生老的 nginx worker 进程被占用一直处于释放中,新的 worker 已经被用尽到无法创建。 ``` 恕我直言,真看不太懂你这段描述,能否提供一个稳定复现的步骤呢?我和它们的疑问一样,为何服务 pod 重启会导致 ingress pod 重启。 |
21
lasuar 216 天前
此外,你这个标题属实夸张!
|
23
easterfan OP @billzhuang 是的,这个 bug 也是提在 ingress-ingress-controller 下的 https://github.com/kubernetes/ingress-nginx/issues/5492
|
24
huihuimoe 216 天前 via iPad
有个问题不太理解,为何 udp 应用要接 ingress 。
而不是使用 metallb 之类的 service lb 去承载? |
25
rushssss 216 天前
实际上 ingress-nginx 在处理后端 endpoint slices 变化时已经尽可能想办法避免频繁的 reload ,参考: https://kubernetes.github.io/ingress-nginx/how-it-works/#avoiding-reloads-on-endpoints-changes
但是在 endpoint slices 从 0 -> 1 或是从 1 -> 0 的这两种情况下依然会触发 Reload, 或许楼主当时要是能给 Pod 多整几个副本就能正好绕过这个问题 :) 当然正经解决方案还是可以考虑用 envoy 这类真正不用 reload 的中间件,或者直接把 TCP/UDP 流量直接通过 SLB 打到 nodeport 上 |
26
svatyvabin 216 天前
@easterfan 而且我没记错的话,reload 好像还会把 websocket 断掉。
|
27
jqknono 216 天前 via Android
这种 debug 经验没有任何分享价值
|
28
anubu 216 天前
大一统应该是 gateway api 吧,似乎很少看到相关分享。
|
31
easterfan OP @svatyvabin websocket 暂时还没观察到,reload 把 worker 进程耗尽,倒是非常明显,ingress 独占的 8C16G 机器,worker 数是 8 ,基本 10 次左右,1min 内就可以复现 worker 进程耗尽的现象了
|
34
momo24672 216 天前
好奇这个 reload 是 nginx ingress 有,还是所有的 ingress 比如 kong 也会有。
|
36
easterfan OP @cheng6563 感谢提醒,我回去找一下这个报错
1. annotation 引起格式问题导致 ngixn 挂 2. 频繁 reload 场景耗尽 worker 进程,导致 ingress 挂 使用 nginx-ingress 做全局流量入口,这两种场景是全局宕机的风险 |
37
fsdrw08 216 天前 via Android
我的理解,ingress 只能算是反向代理的规则,至于反向代理是如何实现这些规则的还得看各家 ingress provider 的方法,所以不能说 ingress 不行,就案例来说,就是 nginx reload 导致的问题。当然,大项目,多后台的情况,应该考虑使用 api gateway
|
38
corvofeng 216 天前 via Android
看起来是转发 UDP 请求遇到的 如果是 HTTP 请求 是不会触发 reload 的 会由 Lua 来配置后端
|
39
corvofeng 216 天前 via Android
看起来是转发 UDP 请求遇到的 如果是 HTTP 请求 是不会触发整体 reload 的 会由 Lua 来配置 upstream 后端
|
42
privil 216 天前 1
@JoeJasper 确实,之前看 Sealos 的网关选型经验 https://mp.weixin.qq.com/s/Ks1iOCQFFMyLJp8C7HtpaA
|
44
ExplodingFKL 216 天前
看架构里面最奇怪的是为啥要用 nginx 来做 udp 转发
|
45
sampeng 216 天前
我很纳闷。。。udp 你一定要用 ingress 怪谁呢。。。
|
46
sampeng 216 天前
在上 k8s 的时候 udp 入口就不要从 ingress 进来。这不是 ingress 干的事。或者说,不合理,不好用。ingress 就处理 http 就好了。
|
47
sampeng 216 天前
既然是在云上。svc 直接挂在 nlb 上暴露出去即可。。压根不需要 ingress 来参与
|
48
sampeng 216 天前
另一方面,health check 太糟糕。你这锅盖 ingress 上实在是不对。作为运维,你的监控系统和 nginx 的 health 检查居然不和你业务相结合。。。nginx 挂了你倒是自动重启 nginx 啊。。。
所以两个小时核心是 udp 服务挂了两个小时?? 反正 lz 是懂起标题的 |
49
clhlc 215 天前
slb 流量直接到 pod ,去掉 ingress 这一层
|
50
easterfan OP @huihuimoe 主要是一开始 ingress 定位就是所有流量入口,没调研到 udp 场景,也是出了事故后,才知道供应商有 UDP 应用~
metallb 我们目前还没有生产使用经验,感谢提醒,后面会调研下 |
51
easterfan OP @rushssss 感谢回复!很靠谱的方案
不过”UDP 流量直接通过 SLB 打到 nodeport 上“,这个方案可能不太合适 1. 集群规模 100 多台机器,除了管控 node 常驻外,其他 worker node ,都是会存在主机上下线场景,nodeport 的 EIP 不好固定,UDP 流量都打到管控 node 的话,这几台机器高峰期压力很大 2. 还是集群规模上,100 多台机器上都开 nodeport 端口,实际只有 1 2 台机器开 EIP + nodeport ,为一个业务开这么多端口,开销大,也显得浪费,所有供应商的对外服务暴露,没有必要情况,都要求首先走 ingress ,不走 nodeport 3. 现在架构设计是 SLB 下挂了 2 台 ingress 主机,如果用 机器 EIP+nodeport 方式,让业务流量直接打到 worker 机器上,那现在这种负载均衡设计就没意义了啊 cc @sampeng |
52
sampeng 215 天前
@easterfan 哦。你的网络模式是没和外部打通的?我一般云上建集群是使用 ip 模式。这样更灵活,网络吞吐也更好,因为从技术上来说,网络包是正儿八经的跟网卡绑定进行流转的,可以做更多的事。这种方式 slb 就是直接到 pod 。比如 nginx ingress 。我推测你现在的方式是 nginx 用的 host ,然后独占一台机器。然后把 slb 指向这个机器组。
我从来就不用 nodeport 的方式。。。只会在开发环境自己懒得折腾就搞的 nodeport |
53
sampeng 215 天前
aws:
https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.2/guide/service/annotations/#nlb-target-type service.beta.kubernetes.io/aws-load-balancer-nlb-target-type ip mode will route traffic directly to the pod IP. network plugin must use native AWS VPC networking configuration for pod IP, for example Amazon VPC CNI plugin. 阿里云: https://help.aliyun.com/zh/ack/ack-managed-and-ack-dedicated/user-guide/add-annotations-to-the-yaml-file-of-a-service-to-configure-clb-instances#c049ddf4f5uba 直接将 Pod ENI 挂载到 CLB 后端 Annotation:service.beta.kubernetes.io/backend-type CLB 后端服务器类型。取值: eni:通过此配置将 Pod 挂载到 CLB 后端,可以提高网络转发性能。仅在 Terway 网络模式下生效。 ecs:将 ECS 挂载到 CLB 后端。 |
54
sampeng 214 天前
单机独占 host 的 nginx 。。你后面还会踩雷。。
|
55
oktp123 175 天前
可以试试 Higress ,基本上兼容 Nginx ingress 的注解了,没有 reload 的问题
|