问题背景
业务在TKE中启用了istio 服务网格, pod 连接数据库超时
进入到容器中通过命令去测试是可以直接连上, 通过entrypoint
挂载命令连接失败,用户是用了istio作为服务治理
原因分析
首先确定,客户在pod里,通过命令行是可以直接连上数据库的。并且,在命令行中执行业务脚本,也是可以运行的。只有当作为entrypoint方式启动脚本,才会失败。再加上用户使用了istio。那么最有可能的就是istio的经典问题,对 Istio 用户来说,一个常见的困扰是:sidecar 和用户容器的启动顺序:sidecar(envoy) 和用户容器的启动顺序是不确定的,如果用户容器先启动了,envoy 还未完成启动,这时候用户容器往外发送请求,请求仍然会被拦截,发往未启动的 envoy,请求异常。在 Pod 终止阶段,也会有类似的异常,根源仍然是 sidecar 和普通容器的生命周期的不确定性。负责流量转发的envoy sidecar和业务容器不能保证哪个先启动,因此导致业务容器启动后,无法连接数据库。
解决方案
目前常规的规避方案主要是有这样几种:
- 业务容器延迟几秒启动, 或者失败重试
- 启动脚本中主动探测 envoy 是否ready,如 127.0.0.1:15020/healthz/ready
无论哪种方案都显得很蹩脚,为了彻底解决上述痛点,从 kubernets 1.18版本开始,k8s 内置的 Sidecar 功能将确保 sidecar 在正常业务流程开始之前就启动并运行,即通过更改pod的启动生命周期,在init容器完成后启动sidecar容器,在sidecar容器就绪后启动业务容器,从启动流程上保证顺序性。而 Pod 终止阶段,只有当所有普通容器都已到达终止状态(Succeeded for restartPolicy=OnFailure 或 Succeeded/Failed for restartPolicy=Never),才会向sidecar 容器发送 SIGTERM 信号。