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 又提供了 postStartpostStop
postStart 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 是一个在容器终止前发送给容器的阻塞请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
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 之外的另一种方便的选择。

总结

云原生平台能提供的最大的好处之一,就是在不够可靠的云计算基础设施上,可靠地运行和扩展应用。这类平台设计了一系列应用必须遵守的协议和约束。处理和响应协议中的事件,能够确保应用平稳地启动和关闭,对接受服务的客户端只有最小的影响。应用的生命周期不再由个人所控制,而是完全由平台自动化管理。

参考资料

Kubernetes Patterns