参考:https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/
https://kubernetes.io/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/
大多数编程语言框架都会提供组件生使周期管理钩子,与此类似,kubernetes通过容器的生命周期钩子管理容器。首先要为钩子注册处理句柄,当容器生命周期发生变化时,如创建、销毁时,触发为钩子注册的句柄的执行。
PostStart
当容器被创建后,为这个钩子注册的处理句柄立刻执行,但是不保证钩子的处理句柄在容器的ENTRYPOINT之前执行。无法向此钩子的处理句柄传递参数。
PreStop
在容器被终止这之前执行,如果此操作没有执行完成,那么它会阻塞kubelet发送删除容器的操作。无法向此钩子的处理句柄传递参数。
Exec
容器内的命令、脚本、及其它可执行程序。命令本身处于与窗口相同的namespace与cgroup之下,执行命令所点用的资源计入容器。
HTTP
向容器中的某个HTTP endpoint发送请求,由谁发送?文档里没有说。
当容器生命周期的变化事件发生时,Kubernetes management system在容器内部执行注册相应钩子的处理句柄。对于PostStart类型的钩子处理句柄,如果执行时间太长或者被挂起,则容器无法进入"running"状态。如果PreStop类型的钩子处理句柄在执行时被挂起,则容器一直停留在"Terminating"状态,并且在"terminationGracePeriodSeconds"后容器被杀死。如果PostStart或者PreStop执行失败,则容器直接被杀死。
用户应该尽量使钩子处理句柄执行的任务更轻,以免执行时间太长,使容器无法进入"running"状态或者无法正常终止而被系统强制杀死。但是有时候,长时间的处理句两是有意义的,比如在停止容器之前保存状态。
系统趋向于当容器生命周期状态发生变化时,为钩子注册的处理句柄只被调用一次,但在某些情况下,这个特性无法保证,也就是说钩子的处理句柄可能会被调用多次,应该由钩子处理句柄的具体实现保证对此种情况的正确处理。
如果钩子处理句柄执行失败,通过如下命令查看:
kubectl describe pod
结果:
Events: FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 1m 1m 1 {default-scheduler } Normal Scheduled Successfully assigned test-1730497541-cq1d2 to gke-test-cluster-default-pool-a07e5d30-siqd 1m 1m 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Pulling pulling image "test:1.0" 1m 1m 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Created Created container with docker id 5c6a256a2567; Security:[seccomp=unconfined] 1m 1m 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Pulled Successfully pulled image "test:1.0" 1m 1m 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Started Started container with docker id 5c6a256a2567 38s 38s 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Killing Killing container with docker id 5c6a256a2567: PostStart handler: Error executing in Docker Container: 1 37s 37s 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Killing Killing container with docker id 8df9fdfd7054: PostStart handler: Error executing in Docker Container: 1 38s 37s 2 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} Warning FailedSync Error syncing pod, skipping: failed to "StartContainer" for "main" with RunContainerError: "PostStart handler: Error executing in Docker Container: 1" 1m 22s 2 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Warning FailedPostStartHook
假设有如下pod定义,其中包含一个容器,容器中包含对PostStart与PreStop容器生命周期事件的处理,如下:
apiVersion: v1 kind: Pod metadata: name: lifecycle-demo spec: containers: - name: lifecycle-demo-container image: nginx lifecycle: postStart: exec: command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"] preStop: exec: command: ["/usr/sbin/nginx","-s","quit"]
从以上配置文件可以看到,当发生PostStart事件时,向/usr/share/message文件中写入一句话。当发生PreStop时,执行一条命令,退出nginx。
创建pod:
kubectl create -f https://k8s.io/examples/pods/lifecycle-events.yaml
确认pod运行状态:
kubectl get pod lifecycle-demo
在窗口内执行shell:
kubectl exec -it lifecycle-demo -- /bin/bash
在容器内确认/usr/share/message文件内容:
Hello from the postStart handler
可以看到PostStart事件的处理被正确执行。