控制 Pod 内容器的启动顺序
2021.4.30 更新:
最新的方案,请跳转新篇 Kubernetes 上如何控制容器的启动顺序。
背景
众所周知, Kubernetes Pod 内有两种容器: 初始化容器(init container)和应用容器(app container). 其中初始化容器的执行先于应用容器, 并且初始化容器和应用容器的个数分别为 0~n
和 1~n
.
初始化容器会按照顺序执行, 顺序执行的前提是初始化容器始终会运行到完成(completed)状态. 而应用容器恰好相反: 启动顺序随机, 并始终保持运行(running)状态.
问题
工作中有个架构的方案使用到了 sidecar 容器: 将基础组件功能从容器转移到 sidecar 容器中, 其中有个功能是从远程配置中心获取配置并保持实时更新. 保证实时更新没有问题, 但是配置文件需要在 app 启动之前完成初始化.
对于同为"应用容器"类型的 sidecar 容器来说, 由于容器启动顺序随机而无法做到这一点.
当时我们给定的方案是增加一个初始化容器进行配置的初始化, 不可避免的我们需要增加一个额外的容器, 即使是这个容器的生命周期非常短.
追求极致的我们总是对这个额外增加的容器耿耿于怀: 假如能控制应用容器的启动顺序…
新发现
近期在研究 CDF (Continuous Delivery Foundation)下的 Tekton, 其中有个概念是其将流水线(pipeline)中的各个步骤(step)作为应用容器在同一个 Pod 中运行.
我们都知道流水线中的步骤是按照定义的顺序执行的, 那么 Tekton 是如何保证应用容器的执行顺序的?
查看 pod 的 manifest 之后发现了下面的容器配置 (这个容器的作用从 git 仓库克隆代码)
spec:
containers:
- args:
- -wait_file
- /tekton/downward/ready
- -wait_file_content
- -post_file
- /tekton/tools/0
- -termination_path
- /tekton/termination
- -entrypoint
- /ko-app/git-init
- --
- -url
- http://gitlab.nip.io:8088/addozhang/tekton-test
- -revision
- develop
- -path
- /workspace/git-source
command:
- /tekton/tools/entrypoint
克隆代码的命令是:
git-init -url http://gitlab.nip.io:8088/addozhang/tekton-test -revision develop -path /workspace/git-source
但是容器的启动命令是/tekton/tools/entrypoint
并带上了一坨的参数(此处略过, 后面分析).
翻看了下文档:
This binary is used to override the entrypoint of a container by wrapping it. In tektoncd/pipeline this is used to make sure Task’s steps are executed in order, or for sidecars.
这个二进制文件被用于通过包装的方式来覆盖容器的入口点. 在 tektoncd/pipeline 中确保任务中的步骤或者 sidecar 被顺序地执行.
-entrypoint
: 原始的容器启动命令, 作为entrypoint
的子进程运行. 即上面的git-init XXXX
-post_file
: 子进程运行结束后写的文件路径(即上面的/tekton/tools/0
). 如果子进程执行失败, 则写一个{{post_file}}.err
文件, 而不是{{post_file}}
-wait_file
: 启动子进程前监控的文件路径(即上面的/tekton/downward/ready
). 通过监控到的{{watch_file}}
或者{{watch_file}}.err
文件来决定执行子进程, 还是跳过执行然后写入{{post_file}}.err
文件并返回错误码(exitCode
>= 0)-wait_file_content
: 等待wait_file
有实际内容写入, 持续监控wait_file
直到有内容写入.
回头看上面容器配置:
- 容器的
entrypoint
启动进程 - 监控到
/tekton/downward/ready
文件的创建, 并等待文件内容的写入 - 执行
git-init
子进程, 从 git 仓库克隆源码 - 创建
/tekton/tools/0
文件
实际应用
这个方案是否能解决我们的问题, 还是有一定的局限性的.
首先需要应用容器的启动命令进行重新的编排, 这个存在一定的挑战. 需要统一应用的启动命令才能做到规模化+自动化.
其次引入可用于监控的文件, 需要额外增加Volume
用于跨容器的文件访问. 当然通过增加emptyDir
的Volume
即可.
同时 sidecar 容器需要在完成启动后创建post_file
, 应用容器可以使用这个entrypoint
进行包装.
如果要突破这个局限, CRD 无非是个优秀的方案. 下一篇, 我们通过一个简单的 CRD 来实现.