Kubernetes允許Pod終止之前,執行自定義邏輯。
字段定義
字段定義:pod.spec.containers.lifecycle.preStop
$ kubectl explain pod.spec.containers.lifecycle.preStop
KIND: Pod
VERSION: v1
RESOURCE: preStop <Object>
DESCRIPTION:
PreStop is called immediately before a container is terminated due to an
API request or management event such as liveness/startup probe failure,
preemption, resource contention, etc. The handler is not called if the
container crashes or exits. The reason for termination is passed to the
handler. The Pod's termination grace period countdown begins before the
PreStop hooked is executed. Regardless of the outcome of the handler, the
container will eventually terminate within the Pod's termination grace
period. Other management of the container blocks until the hook completes
or until the termination grace period is reached. More info:
https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks
Handler defines a specific action that should be taken
FIELDS:
exec <Object>
One and only one of the following should be specified. Exec specifies the
action to take.
httpGet <Object>
HTTPGet specifies the http request to perform.
tcpSocket <Object>
TCPSocket specifies an action involving a TCP port. TCP hooks not yet
supported
有三種preStop方式:
- exec:
- httpGet:
- tcpSocket:
示例
使用最簡單的exec作示例,詳細查看一下exec下需要定義的字段:
$ kubectl explain pod.spec.containers.lifecycle.preStop.exec
KIND: Pod
VERSION: v1
RESOURCE: exec <Object>
DESCRIPTION:
...
FIELDS:
command <[]string>
Command is the command line to execute inside the container, the working
directory for the command is root ('/') in the container's filesystem. The
command is simply exec'd, it is not run inside a shell, so traditional
shell instructions ('|', etc) won't work. To use a shell, you need to
explicitly call out to that shell. Exit status of 0 is treated as
live/healthy and non-zero is unhealthy.
接下來按照字段釋義,直接定義一個Pod:
$ kubectl apply -f pod.yaml
# pod.yaml文件內容:
apiVersion: v1
kind: Pod
metadata:
name: busybox
namespace: default
spec:
containers:
- name: busybox
image: busybox
command: ["/bin/sh", "-c", "sleep 10m"]
lifecycle:
preStop:
exec:
command:
[
"/bin/sh",
"-c",
"echo this pod is stopping. > /stop.log && sleep 10s",
]
刪除pod:
$ kubectl delete pod busybox
在新終端窗口(因為刪除pod會占用終端窗口)獲取pod內文件內容,需要在pod完全刪除之前(10s內,也可以將該值設置稍長一點):
$ kubectl exec busybox -c busybox -- cat /stop.log
# 可以得到日志內容
this pod is stopping.
這說明,preStop確實生效了。
使用場景
- 你的請求已經到達了當前Pod,硬終止會導致請求失敗,我們希望已經到達了當前Pod的請求處理完成再將其停止掉,盡可能避免請求失敗;
- Pod已經本身已經注冊到了服務中心,我們希望在Pod停止之前,主動向服務注冊中心通知下線;
結束語
與preStop相對應,有一個postStart的概念,在容器創建成功后執行,可用於初始化資源,准備環境等;
如果preStop與postStart執行失敗,將會殺死容器。所以作為鈎子函數,應該盡量保證它們是輕量的;
Pod的終止過程:
刪除Pod => Pod被標記為Terminating狀態 => Service移除該Pod的endpoint => kubelet甄別Terminating狀態的pod,執行pod的preStop鈎子 => 如果執行preStop超時(grace period) ,kubelet發送SIGTERM並等待2秒 => ...