先讲讲项目的性质和部署方式,项目是前后端分离的,都用的 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
也是比较典型的配置方式,其中前端是用 openrestydocker 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。那么解法可以是

  1. 禁用 dns,影响性能
  2. dns 配置超时,一定程度的可用性降低,一定程度影响性能
  3. 监听 k8s be service 启动、重启事件,收到后在 openresty 刷新 dns,需要开发,开发团队自己确保基础设施的可靠性
  4. 保证 k8s be deployment 完成后再做 k8s fe deployment,用确保时序的方式避免部署问题,但不能解决后续可能出现的重启问题

想了一想好像这个需求应该是很常见的,社区一定有解法,搜了一溜发现并没有,奇怪的是提这个问题的人都少之又少,那他们是怎么解决的呢?然后就去翻了 k8s 文档,应该属于服务发现范畴,看到了VIP,这不是之前做数据库热切用到的么,看起来是能解决问题的,但看着有点重,看到这里发现 service 有个 ClusterIP 的概念,在 service 的生命周期里是不会变的,就是用来做 service 解耦的,外部不需要知道 service 里面有什么。那么问题来了,这个行为是默认的,为什么 fe openresty dns 会解析出 be podIP 呢?应该是一个 service ClusterIP 才对。检查了一下运维同学的 yml 才发现 clusterIP 都设置了 none。。。忽然想起很多性能调优不稳定的往事。。。真的是。。

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