容器生命周期的钩子
容器钩子
容器中有两个钩子:
PostStart
这个钩子在容器创建后立即执行。
但是,并不能保证钩子将在容器ENTRYPOINT之前运行。
没有参数传递给处理程序。
PreStop
这个钩子在容器终止之前立即被调用。
它是阻塞的,意味着它是同步的, 所以它必须在删除容器的调用发出之前完成。
钩子处理程序的实现
容器可以通过实现和注册该钩子的处理程序来访问钩子。
可以为容器实现两种类型的钩子处理程序:
- Exec - 在容器的cgroups和命名空间内执行一个特定的命令,比如pre-stop.sh。
该命令消耗的资源被计入容器。 - HTTP - 对容器上的特定的端点执行HTTP请求。
钩子处理程序的执行
当容器生命周期管理钩子被调用后,Kubernetes管理系统执行该钩子在容器中注册的处理程序。
在含有容器的Pod的上下文中钩子处理程序的调用是同步的。
这意味着对于PostStart钩子, 容器ENTRYPOINT和钩子执行是异步的。
然而,如果钩子花费太长时间以至于不能运行或者挂起, 容器将不能达到running状态。
PreStop钩子的行为是类似的。
如果钩子在执行期间挂起, Pod阶段将停留在running状态并且永不会达到failed状态。
如果PostStart或者PreStop钩子失败, 它会杀死容器。
用户应该使他们的钩子处理程序尽可能的轻量。
然而,有些情况下,长时间运行命令是合理的, 比如在停止容器之前预先保存状态。
钩子交付保证
钩子交付打算至少一次,这意味着对于给定的事件,一个钩子可能被多次调用, 例如对于PostStart或者PreStop。
它是由钩子的实现来正确的处理这个。
通常,只有单次交付。
例如,如果一个HTTP钩子的接收者挂掉不能接收流量, 该钩子不会尝试重新发送。
然而,在一些极不常见的情况下,可能发生两次交付。
例如,如果在发送钩子的途中kubelet重启, 该钩子可能在kubelet启动之后重新发送。
调试钩子处理程序
在Pod的事件中没有钩子处理程序的日志。 如果一个处理程序因为某些原因运行失败,它广播一个事件。
对于PostStart, 这是FailedPostStartHook事件, 对于PreStop, 这是FailedPreStopHook事件。
可以通过运行kubectl describe pod <pod_name>
来查看这些事件。
给容器生命周期设置操作事件,定义预启动和预结束事件操作
本实验将会创建含有一个容器的Pod,我们将会给这个容器设置预启动和预结束操作。
下面是Pod的配置文件:
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命令停止容器。这在容器被因错误而结束时很有帮助。
创建Pod:
kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/lifecycle-events.yaml
验证Pod里的容器是否运行:
kubectl get pod lifecycle-demo
连接到Pod里容器的shell:
kubectl exec -it lifecycle-demo -- /bin/bash
在shell里,验证postStart是否创建了message文件:
root@lifecycle-demo:/# cat /usr/share/message
输出显示了文件确实被创建了:
Hello from the postStart handler
说明
Kubernetes在容器创建之后就会马上发送postStart事件,但是并没法保证一定会 这么做,它会在容器入口被调用之前调用postStart操作,因为postStart的操作跟容器的操作是异步的,而且Kubernetes控制台会锁住容器直至postStart完成,因此容器只有在 postStart操作完成之后才会被设置成为RUNNING状态。
Kubernetes在容器结束之前发送preStop事件,并会在preStop操作完成之前一直锁住容器 状态,除非Pod的终止时间过期了。