如何动态管理 k8s 中单个 Pod 内的容器

背景

最近有一个流水线引擎相关的需求,希望能够按需控制一个 Pod 内的容器创建或者启停,以此来实现流水线步骤执行的控制。

本文主要记录之前研究的一些结论,备忘的同时也给后续有需要的同学一个思路。

分析

熟悉 k8s 的同学应该知道,一个 Pod 在创建的时候,需要把内含的容器指定好,在 Pod 运行之后,无法再新增或者删除内部的容器。

临时容器

通过研究 k8s 的官方 API 发现,k8s 提供了临时容器(Ephemeral Containers)这么一个玩意,可以在现有的 Pod 中临时运行,以便完成用户的操作(如故障排查)。

通过 k8s 提供的 API,可以非常方便地往一个已有 Pod 追加临时容器(不能修改/删除临时容器),以此实现流水线中特定步骤的执行。

定制 Entrypoint

另外一个思路就是像 TEKTON 的实现一样(详见 说明文档):在创建 Pod 时,一次性创建好所有容器,不过每个容器的 entrypoint 都使用定制过的脚本,脚本循环检测「固定路径」的文件,判断是否要执行业务逻辑还是直接退出。

如果觉得这样的控制权不够,还可以考虑修改 Pod 的 labels/annotations,容器监听 labels/annotations 值的变化再发生指定动作(附:通过文件将 Pod 信息呈现给容器)。

小结

总的来说,无论是「临时容器」还是「定制 Entrypoint」都可以达到目的。

前者由于是「新特性」,只有最新的几个 k8s 版本才会默认集成该特性,不一定适用于每个集群。而且由于该特性自带 Debug 属性,临时容器的运行资源可能没有办法保障,对于稳定性/可用性要求极高的场景,不一定适用。

后者的操作比较正统,目前想到的劣势主要在于资源的一次性分配、entrypoint 的定制化这两点:对于串行执行步骤较多的流水线,在分配 Pod 时没法充分利用上现有宿主机的剩余资源;entrypoint 的定制则需要考虑得比较全面,比如后续的日志收集,以及业务自行定制的镜像的兼容性。

PS:这里不考虑多 Pod(每个 Pod 一个容器执行一个步骤),主要是因为不同步骤之前如果需要共享数据会比较困难(需要 NFS 等手段)。