蛮荆

Kubernetes 应用最佳实践 - init 容器和钩子函数

2023-03-15

init 容器

init 容器是一种特殊的容器,在 Pod 中的其他容器启动之前运行,单个 Pod 中可以有任意数量的 init 容器。

Pod 中所有 init 容器按顺序逐个执行,当所有 init 容器执行 「成功」后,才会启动其他容器

如果其中一个 init 容器失败,Pod 将根据 restartPolicy 选择是否重新启动,如果需要重新启动(restartPolicy 配置不等于 Never), 所有的 init 容器将再次重新运行,如果不需要重新启动(restartPolicy 配置等于 Never),Pod 的状态被标记为失败。

也就是说,可以利用 init 容器来完成应用的必要初始化操作,例如定义 3 个 init 容器分别来完成:

  1. 数据库连接池初始化
  2. 缓存连接池初始化
  3. 热点数据缓存在本地预加载

这样当 3 个 init 容器执行成功后,应用就可以随时接收流量了,反之,如果 3 个 init 容器任意一个出现问题,应用不会启动,这样确保流量不会进入到有问题的容器中。

图片来源: https://livebook.manning.com/book/kubernetes-in-action

作用

init 容器可以分离逻辑关注点,使容器保持单一用途

  • 开发人员可以聚焦业务代码逻辑,创建应用容器
  • 运维可以可以专注创建 init 容器,初始化应用依赖的所有前置组件

从作用上来说,通过在 Pod 中的应用容器中进行初始化操作,可以达到和 init 容器相同的作用,为什么一定要使用 init 容器呢? 主要原因是 init 容器提供了「顺序执行」和 「必须成功」的双重语义保证,虽然在应用容器也可以实现类似的约束,但是这会增加应用代码的复杂性。

最佳实践

  • init 容器应该保持轻量,同时应该快速执行完成并返回执行结果
  • init 容器内执行逻辑应该独立,不依赖于任何数据库状态数据和第三方接口返回值等情况
  • init 容器执行过程保证幂等 (尤其是容器可能执行失败的情况下)

生命周期事件函数

Kubernetes 提供了两种容器事件函数 (钩子函数):

  1. Post-Start: 容器启动后调用
  2. Pre-Stop : 容器停止 (Terminated) 前调用

事件函数与探针的使用方式类似:

  • 执行一个命令
  • 发送一个 HTTP请求

Post-Start

虽然 Post-Start 事件函数和容器代码是并行执行的,但是在 Post-Start 事件函数执行完成之前,容器会停留在 Waiting 状态,如果 Post-Start 事件函数执行失败,容器会被重启。

Pre-Stop

Pre-Stop 事件函数只有在容器结束(Terminated) 的时候才会触发,并且在函数执行完成后向容器应用进程发送 SIGTERM 信号,应用进程可以利用该信号来完成 “优雅关闭并退出”。

Pre-Stop 事件函数无论是否执行成功,容器最终都会被终止

最佳实践

  • 在 Post-Start 事件函数中启动定时任务、异步队列等操作
  • 在 Post-Start 事件函数中执行关闭文件、网络连接等操作
  • 重要业务逻辑不依赖于事件函数的执行结果

作用域

  1. init 容器的作用域是 Pod, 同时 init 容器不支持探针和事件函数
  2. 探针的作用域是容器
  3. Post-Start, Pre-Stop 函数的作用域是容器

图片来源: https://stackoverflow.com/questions/47999419/equivalent-of-init-containers-that-runs-after-termination

Reference

转载申请

本作品采用 知识共享署名 4.0 国际许可协议 进行许可,转载时请注明原文链接,图片在使用时请保留全部内容,商业转载请联系作者获得授权。