背景
近期CI/CD进程中遇到这样一个问题,线上应用滚动更新过程中,大概两分钟的时间,应用不能对外提供服务。
k8s管理容器应用,容器组的pods逐个销毁重建(新增新pod, 销毁旧pod,完成替换)。
单个pod的资源分配较低(如cpu分配0.1-0.2核,内存分配256-512M)。
原因
pod可对外提供服务的过程:新pod启动时,系统分配应用进程Id,应用建立各项连接池:连接数据库(mysql), 一致缓存(redis)、监控(infludb)、服务中心(zookeeper)、配置中心(apollo)等。进入pod内,通过netstat -antp可查看,系统分配地址,建立各项连接的过程。连接建立完成后,系统分配应用的服务端口,开始对外提供服务。
原有判断pod启动成功的标志是pod内是否分配了应用进程Id,这种方式带来的问题显而易见:新pod分配了应用进程Id后,并不能立即对外提供服务,旧的Pod却已经被销毁。新pod的应用进程Id建立后,k8s认为该pod已经可以正常提供服务,则将流量导入,但实际新pod的应用服务端口尚未建立。
解决
针对这种情况,引入readiness探针后,可真正实现不停服滚动更新。
通过应用提供接口的方式,readiness探针不仅检测应用端口是否建立,还可以判断应用是否真正提供服务。如SpringBoot-actuator的health接口或者单独提供检测的接口。
另外,cpu的资源上限可适当增加,应用启动过程的长短与硬件资源多少尤其是cpu核数相关。
参考文档:链接
扩展
1.除了Readiness探针用于pod就绪检查外,相应有Liveness探针用于运行状态检查,两者共同的作用均为检查服务运行状态,若通过则将pod加入容器组负载,失败则移除。
2.每个pod启动,原则需10s以内,合理分配内存及cpu等资源(尽可能多一些)即可减少pod启动时间。