Kubernetes 设计模式笔记 —— 生命周期管理
由云原生平台管理的容器化应用,并不能控制其自身的生命周期。它们必须监听由管理平台发出的事件,再对生命周期做出相对应的变更。所谓的生命周期管理,即代表应用该如何读取和响应这些由管理平台发出的生命周期事件。
鉴于某些管理策略或者外部环境因素,在任意时间点,管理平台都有可能需要启动或者终止容器中的应用。容器化应用可以决定平台发出的哪些事件是重要的,应该以怎样的行为去响应。这实际上是一个平台用来同应用进行沟通、向应用发送命令的 API,应用可以选择接受或者忽略。
仅仅使用进程模型来启动和终止应用通常是不够的,现实世界中的应用往往需要更细粒度的交互控制和生命周期管理。有些应用需要 warm up,有些需要一个平滑、干净的关闭流程。因而 Kubernetes 设计了如下几种由平台发出的事件,容器可以选择监听和响应这些事件。
events
SIGTERM Signal
当 Kubernetes 决定关闭某个容器时,该容器会收到一个 SIGTERM 信号,之后容器会尝试尽快完成关闭流程。对于某些应用来说,干净的快速终止是可行的。但另外一些应用有可能需要完成处理中的请求,释放打开的连接,清理临时文件等。这会耗费更多的时间。
SIGKILL Signal
当某个容器进程在收到 SIGTERM 信号后并没有关闭,接下来它会再收到一个 SIGKILL 信号强制终止进程。默认情况下,Kubernetes 会在发出 SIGTERM 信号 30 秒后再发送 SIGKILL。这个 30 秒的过渡时间可以通过 Pod 的 .spec.terminationGracePeriodSeconds
字段进行配置。
Poststart Hook
仅仅使用进程信号来管理生命周期有一定程度的限制。因而 Kubernetes 又提供了 postStart
和 postStop
。
postStart
示例:
apiVersion: v1
kind: Pod
metadata:
name: post-start-hook
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
lifecycle:
postStart:
exec:
command:
- sh
- -c
- sleep 30 && echo "Wake up!" > /tmp/postStart_done
postStart
指定的命令会在容器创建后执行,与容器的基础进程异步。postStart
是一种阻塞请求,其 handler 完成之前,容器会一直处于 Waiting 状态,同时 Pod 处于 Pending 状态。
postStart
的这种特性可以用来延迟容器的启动,为容器的主进程的初始化争取时间。
另一个 postStart
的使用场景就是在 Pod 不满足特定的前提条件时,阻止容器完成启动。当 postStart
命令返回了一个非 0 的返回值,主进程会被 Kubernetes 杀掉。
类似于 Health Probe,postStart 和 preStop 有如下两种 handler 类型:
- exec:在容器中直接运行一个命令
- httpGet:向容器开放的某个端口发送 HTTP GET 请求
对于 postStart 执行的逻辑,需要注意以下几点:
- postStart 与容器进程是并行的关系,因而这个 hook 有可能在容器启动前执行
- postStart 有至少执行一次的目标,需要考虑重复执行的情况
- 对于失败的 HTTP 请求,postStart 不会重复尝试
preStop
preStop
hook 是一个在容器终止前发送给容器的阻塞请求。
apiVersion: v1
kind: Pod
metadata:
name: pre-stop-hook
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
lifecycle:
preStop:
httpGet:
port: 8080
path: /shutdown
虽然 preStop
是阻塞的,但若它挂起或者返回一个非成功的结果,并不会阻止进程被杀掉、容器被删除。preStop
只是为了能够平滑地关闭应用,是除 SIGTERM 之外的另一种方便的选择。
总结
云原生平台能提供的最大的好处之一,就是在不够可靠的云计算基础设施上,可靠地运行和扩展应用。这类平台设计了一系列应用必须遵守的协议和约束。处理和响应协议中的事件,能够确保应用平稳地启动和关闭,对接受服务的客户端只有最小的影响。应用的生命周期不再由个人所控制,而是完全由平台自动化管理。