背景
使用nginx-ingress遇到backends不更新的问题,在修改svc的 targetPort之后nginx-ingress的backends不能正常更新成新的targetPort。
关于endpointslices,是k8s 1.16 引入的新feature , 目的就是当客户端去get一个很大的endpoint的list的时候可能存在的卡顿,解析资源比较大引发的问题。 所以社区引入endpointslices 资源, 把大的endpoint 分片成很多100个端点块的资源,通过kcm的 --max-endpoints-per-slice 参数调整块大小。
新feature是有很多的问题的,比如kube-proxy 是在1.20之后再引入去获取 endpointslice,看社区出现过一个在使用ExternalName 导致的bug, 在1.23之后的k8s版本中修复了, 类似issue: https://github.com/kubernetes/kubernetes/issues/105986
nginx-ingress-controller 看是在 v1.9.0 之后引入使用的 endpointslices
https://github.com/kubernetes/ingress-nginx/commits/controller-v1.9.0/internal/ingress/controller/endpointslices.go
https://kubernetes.io/zh-cn/docs/concepts/services-networking/endpoint-slices/
https://github.com/kubernetes/kubernetes/commit/75f6c249235b40b24e9ea1efdb1ff81dd76a8d68
https://kubernetes.io/docs/reference/command-line-tools-reference/kube-controller-manager/
环境
| 集群版本 | nginx-ingress的版本 |
|---|---|
| 1.22.15 | v1.10.4 |
复现步骤
调整nginx-ingress-controller的日志级别为5 --v=5
1 | containers: |
检查现有状态
1)查看svc的的端口
1 | $ kubectl get svc nginx-svc -o yaml |
2)查看原来 backends
1 | $ kubectl exec deployment/nginx-ingress-controller -n kube-system -- /dbg backends get default-nginx-svc-8080 |
3)先打开nginx-ingress-controller日志跟踪
1 | $ kubectl logs -n kube-system nginx-ingress-controller-xxx -f | grep -E "socket.go|controller.go|main.go|queue.go|endpointslices.go|nginx.go|reflector.go" |
只修改targetPort从11111 为 2222
1 | $ kubectl edit svc nginx-svc |
问题复现
1)查看svc的的端口
- svc已经正常修改为2222了
2)查看原来 backends
- 可以看到backends 的targetPort还是原来的 1111
3)查看日志输出 nginx-ingress-controller日志跟踪
- 可以看到 endpointslices.go:166 , 还是获取的之前的targetPort为 1111 的endpointslices 资源,估计这个就是没有更新的原因
初步原因:
那就先查一下审计吧~
- nginx-ingress去watch的时间: 15:32:56:218090
- 更新endpointslices/nginx-svc-r89mv的时间: 15:32:56.221695
破案了啊, 果然nginx-ingress的watch到的时间, 比kcm更新endpointslices 时间早了 221695 - 218090 = 3605us , 根因 找到了呀~
那么问题来了,为啥是偶发的 在debug日志看一下
- 和后端服务的endpoint数量有关系
- 延迟这个东西说不准,有时候快有时候慢的
那应该就是kcm 去更新 endpointslices 的时候 和 nginx-ingress watch到的这个events 之间有延迟,所以就需要去看看代码了~
怎么解决
社区问题,还是先找社区看看是否有类似的问题。给社区提交issue : https://github.com/kubernetes/ingress-nginx/issues/11863
哈哈哈, 被remove bug 了~ ,可是这个已经很bug了。
可恶, 对于issue社区应发的思考
- 对于提交问题的需要详尽的描述问题, 可是应该已经很详细了
- 社区成员没有义务,需要按他提供的方式去提供信息,要么就放弃吧
求仙问卜 不如源码得知!!!
1 | $ git clone https://github.com/kubernetes/ingress-nginx.git |
.ingress-nginx/internal/ingress/controller/endpointslices.go
看就是watch到 endpointSlices更新之后,就去loop最新的endpointSlices 资源, 我感觉加一个sleep就可以,延迟个 200ms,再去get endpointSlices
编译后结果, 已经能正常更新了!!!
给社区提交一个PR,万一merge了呢~
https://github.com/kubernetes/ingress-nginx/pull/11896
拓展
如何编译nginx-ingress-controller呢。
准备
1、找一台中国香港的ECS吧。 内地不行,不要问为什么~
2、安装docker-ce最新版本环境
1 | $ sudo curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun |
3、安装git
1 | $ yum -y install git |
4、go环境安装
1 | $ wget https://go.dev/dl/go1.23.2.linux-amd64.tar.gz |
编译
1、设置环境变量
1 | $ export DOCKER_IN_DOCKER_ENABLED=true |
2、克隆源代码
1 | $ git clone https://github.com/kubernetes/ingress-nginx.git |
3、切换分支(必须)
1 | $ git branch -a |
4、修改代码, 参考上文
5、更新 go.mod 文件
1 | $ go mod tidy |
6、编译
1 | $ make build |
7、打镜像
1 | $ make image |
8、推镜像
1 | $ docker tag gcr.io/k8s-staging-ingress-nginx/controller:v1.10.4 registry.cn-hangzhou.aliyuncs.com/zmquan/nginx:v1.10.4 |
编译: 参考这个大佬的文档