记一个 k8s 中 service 的 clusterIP 配置错误的排查过程2020年4月30日
先讲讲项目的性质和部署方式,项目是前后端分离的,都用的 gitlab 的 CI/CD 去打镜像,build stage 过了后发到 k8s(前后端并发 apply 自己的 k8s yml),即git tag -> lint + test -> build -> build docker image -> k8s apply yml -> notify
k8s 集群的部署环境简化一下是这样的 阿里云 SLB -> k8s ingress -> fe service -> be service -> DB阿里云 SLB -> k8s ingress -> be service -> DB
也是比较典型的配置方式,其中前端是用 openresty 在 docker image 中带起来的
有几次发现部署不稳定,现象是前端 502,报的 cannot find route to xx.xx.xx.xx,检查了一下配置,确认没问题,在 fe pod 中重启 openresty,发现 fe 可以正常工作了,但过了一段时间后又挂了。看了一下这段时间的操作,有一次发版行为,不能确定是发版导致的还是 be 挂掉重启(被 k8s 重新配了一个 IP 地址)导致的 IP 失效。于是找了一套环境发版来尝试复现,发版前记录 pod/service 的 IP,发版,发现前端 502 了,报错信息中的 upstream IP 是发版前的 be pod 地址。等发版完成后去看了一下 be pod 的地址,果真已经变了。
yoxi 问题应该就在这里了,解析是没问题的,只是 openresty 部署的时候比后端先启动,缓存了老的 be IP。那么解法可以是
- 禁用
dns,影响性能 dns配置超时,一定程度的可用性降低,一定程度影响性能- 监听
k8s be service启动、重启事件,收到后在openresty刷新dns,需要开发,开发团队自己确保基础设施的可靠性 - 保证
k8s be deployment完成后再做k8s fe deployment,用确保时序的方式避免部署问题,但不能解决后续可能出现的重启问题
想了一想好像这个需求应该是很常见的,社区一定有解法,搜了一溜发现并没有,奇怪的是提这个问题的人都少之又少,那他们是怎么解决的呢?然后就去翻了 k8s 文档,应该属于服务发现范畴,看到了VIP,这不是之前做数据库热切用到的么,看起来是能解决问题的,但看着有点重,看到这里发现 service 有个 ClusterIP 的概念,在 service 的生命周期里是不会变的,就是用来做 service 解耦的,外部不需要知道 service 里面有什么。那么问题来了,这个行为是默认的,为什么 fe openresty dns 会解析出 be pod 的 IP 呢?应该是一个 service ClusterIP 才对。检查了一下运维同学的 yml 才发现 clusterIP 都设置了 none。。。忽然想起很多性能调优不稳定的往事。。。真的是。。

架构级的东西比代码更需要 review 啊