如何控制 K8S 单个 Pod 中容器的启动顺序?
其实只要把这个问题放到谷歌里一搜,就可以得到一个有效的、让人满意的答案。但是,为什么呢?没有人讲过。无论我使用中文、英文进行搜索,都没有人提到为什么在 postStart 执行当前容器的健康检查代码就可以控制容器的启动顺序,包括官方文档(甚至一度误导了我)。
在官方文档里有这么一段话:
Kubernetes 在容器创建后立即发送 postStart 事件。 然而,postStart 处理函数的调用不保证早于容器的入口点(entrypoint) 的执行。postStart 处理函数与容器的代码是异步执行的,但 Kubernetes 的容器管理逻辑会一直阻塞等待 postStart 处理函数执行完毕。
一开始我看到“postStart 处理函数与容器的代码是异步执行的”这句话,以为网上铺天盖地、明显是复制粘贴的文章是错的,至少是旧的。我把这个文档给公司大佬看,他也迟疑了,但是他搜到的那篇文章里的实验结果的确是阻塞了。我秉持着要知其本质的想法,继续寻找答案。
通过不断的在不同的网站上搜索,终于在 GitHub 上搜到了一个看起来毫不相干但却是唯一一个有效且相关的 Issue——Containers startup is blocked by postStart lifecycle hook。在这个 Issue 里,提出者说某一个容器的 postStart 阻塞了其他容器的启动,K8S 的人却说这是 feature 而不是 bug。😀另外提出者的想法跟我一样,都以为 K8S 文档中那句“postStart 处理函数与容器的代码是异步执行的”意思是 postStart Hook 不会阻塞容器启动,因为是“异步的”。
那么根据这个 Issue 里的对话可以得知,K8S 在启动同一个 Pod 里容器时,其启动顺序会按照配置文件中的顺序去启动(注意,在这里它并不会等容器启动完成才继续),而当你为某一个容器增加 postStart Hook 之后,K8S 的启动流程会被这个 Hook 给阻塞住,直到 Hook 完成了,才会继续往下执行。这样一来只需要在容器的 postStart Hook 里执行对当前容器的状态的查询代码、直到容器内进程或服务状态正常才退出,就可以保证在下一个容器启动前,该容器能正常提供服务。
这时候就能理解官方文档中的那句话了“postStart 处理函数与容器的代码是异步执行的,但 Kubernetes 的容器管理逻辑会一直阻塞等待 postStart 处理函数执行完毕。”。它的意思是——postStart 处理函数和容器启动是同时被调用的,但是双方的实际执行却是互不干涉的。Kubernetes 的容器管理逻辑不会等待容器启动完成,但是会一直阻塞等待 postStart 处理函数执行完毕。
题外话
网络上甚嚣尘上的那篇控制 K8S Pod 内的容器启动顺序的文章互相抄来抄去,都是引用的 istio 里的配置,而这个配置的 Pull Request 引用了上述 K8S 里的那个 Issue,却没有一个人来提一下这样配置能生效的原因(也许有,但我没看到)。也许都是觉得能跑就行了,毕竟是 K8$ 嘛。哈哈哈。