现在在Pod的整个生命周期中,能影响到Pod的就只剩下健康检查这一部分了。在k8s集群当中,我们可以通过配置liveness probe(存活探针)
和readiness probe(可读性探针)
来影响容器的生命周期。
- kubelet通过
liveness probe
来确定你的应用程序是否正在运行,通俗点讲就是是否还活着
。一般来说,如果你的程序一旦崩溃了,kubernetes就会立刻知道这个程序已经终止了,然后就会重启这个程序。而我们的liveness probe
的目的就是来捕获到当前应用程序还没有终止,还没有崩溃,如果出现了这些情况,那么就重启处于该状态下的容器,使应用程序在存在bug的情况下依然能够继续运行下去。
- kubelet使用
readiness probe
来确定容器是否已经就绪就可以接收流量过来了。这个探针通俗点讲就是说是否准备好了
,现在可以开始工作了。只有当Pod中的容器都处于就绪状态的时候kubelet才会认定该Pod处于就绪状态,因为一个Pod下面可能会有多个容器。当然Pod如果处于非就绪状态,那么我们就会将它从Service的Endpoints列表中移除出来,这样我们的流量就不会被路由到这个Pod里面来了。
- exec: 执行一段命令
- http:检测某个http请求
- tcpSocket:使用此配置,kubectl将尝试在指定端口上打开容器的套接字。如果可以建立连接,容器被认为是健康的,如果不能就认为是失败的。实际上就是检查端口。
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec
spec:
containers:
- name: liveness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy;
sleep 30;
rm -rf /tmp/healthy;
sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
我们这里需要用到一个新的属性:
livenessProbe
,下面通过exec执行一段命令:-
periodSeconds
: 表示让kubelet每隔5s执行一次存活探针,也就是每5s执行一次上面的cat /tmp/healthy
命令,如果命令执行成功了,将返回0,那么kubelet就会认为当前这个容器是存活的,如果返回的是非0值,那么kubelet就会把该容器杀掉然后重启它。periodSeconds
的值默认是10s,最小1s。 -
initialDelaySeconds
: 表示在第一次执行探针的时候要等待5s,这样能够确保我们的容器能够有足够的时间启动起来。大家可以想象一下,如果你的第一次执行探针等候的时间太短,是不是很有可能容器还没正常启动起来,所以存活探针很可能始终都是失败的,这样就会无休止的重启下去。
/bin/sh -c "touch /tmp/healthy;
sleep 30;
rm -rf /tmp/healthy;
sleep 600"
意思是说在容器最开始的30s内创建一个
/tmp/healthy
文件,在这30s内执行cat /tmp/healthy
命令都会返回一个成功的返回码。30s后,我们删除这个文件,现在执行cat /tmp/healthy
是不是就会失败(默认检测失败3次才认为失败
),所以这个时候就会重启容器了。以下是过程
.......
.......
.......
Conditions:
TypeStatus
InitializedTrue
ReadyFalse
ContainersReadyFalse
PodScheduledTrue
Volumes:
default-token-557h9:
Type:Secret (a volume populated by a Secret)
SecretName:default-token-557h9
Optional:false
QoS Class:BestEffort
Node-Selectors:
Tolerations:node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
TypeReasonAgeFromMessage
-------------------------
NormalScheduleddefault-schedulerSuccessfully assigned default/liveness-exec to node02
NormalPulling2skubelet, node02Pulling image "busybox"##################################################################
.......
.......
.......
Conditions:
TypeStatus
InitializedTrue
ReadyTrue
ContainersReadyTrue
PodScheduledTrue
Volumes:
default-token-557h9:
Type:Secret (a volume populated by a Secret)
SecretName:default-token-557h9
Optional:false
QoS Class:BestEffort
Node-Selectors:
Tolerations:node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
TypeReasonAgeFromMessage
-------------------------
NormalScheduleddefault-schedulerSuccessfully assigned default/liveness-exec to node02
NormalPulling10skubelet, node02Pulling image "busybox"
NormalPulled4skubelet, node02Successfully pulled image "busybox"
NormalCreated4skubelet, node02Created container liveness
NormalStarted4skubelet, node02Started container liveness
##################################################################
.......
.......
.......
Conditions:
TypeStatus
InitializedTrue
ReadyTrue
ContainersReadyTrue
PodScheduledTrue
Volumes:
default-token-557h9:
Type:Secret (a volume populated by a Secret)
SecretName:default-token-557h9
Optional:false
QoS Class:BestEffort
Node-Selectors:
Tolerations:node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
TypeReasonAgeFromMessage
-------------------------
NormalScheduleddefault-schedulerSuccessfully assigned default/liveness-exec to node02
NormalPulling16skubelet, node02Pulling image "busybox"
NormalPulled10skubelet, node02Successfully pulled image "busybox"
NormalCreated10skubelet, node02Created container liveness
NormalStarted10skubelet, node02Started container liveness##################################################################
.......
.......
.......
Volumes:
default-token-557h9:
Type:Secret (a volume populated by a Secret)
SecretName:default-token-557h9
Optional:false
QoS Class:BestEffort
Node-Selectors:
Tolerations:node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
TypeReasonAgeFromMessage
-------------------------
NormalScheduleddefault-schedulerSuccessfully assigned default/liveness-exec to node02
NormalPulling64skubelet, node02Pulling image "busybox"
NormalPulled58skubelet, node02Successfully pulled image "busybox"
NormalCreated58skubelet, node02Created container liveness
NormalStarted58skubelet, node02Started container liveness
WarningUnhealthy14s (x3 over 24s)kubelet, node02Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
NormalKilling14skubelet, node02Container liveness failed liveness probe, will be restarted
我们可以观察到容器是正常启动的,在隔一会,比如60s后,再查看下Pod的Event,在最下面有一条信息显示
liveness probe失败
了,容器将要重启。然后可以查看到Pod的RESTARTS
值加1了:(我这里已经加到5了)[root@node01 ~]# kubectl get pods
NAMEREADYSTATUSRESTARTSAGE
hook-demo11/1Running025d
init-demo1/1Running025d
liveness-exec1/1Running57m20s
nginx-deploy-745bd74b44-4k2np1/1Running026d
nginx-deploy-745bd74b44-jr7wv1/1Running026d
nginx-deploy-745bd74b44-ngkrg1/1Running026d
nginx-deploy-745bd74b44-plgkw1/1Running026d
同样的,根据 periodSeconds 属性我们可以知道 kubelet 需要每隔3秒执行一次 liveness Probe,该探针将向容器中的 server 的 8080 端口发送一个 HTTP GET 请求。如果 server 的 /healthz 路径的 handler 返回一个成功的返回码,kubelet 就会认定该容器是活着的并且很健康,如果返回失败的返回码,kubelet 将杀掉该容器并重启它。initialDelaySeconds 指定kubelet 在该执行第一次探测之前需要等待3秒钟。
apiVersion: v1
kind: Pod
metada:
name: liveness-http
spec:
containers:
- name: liveness
image: cnych/liveness
args:
- /server
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: X-Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
除了上面的 exec 和 httpGet 两种检测方式之外,还可以通过 tcpSocket 方式来检测端口是否正常,大家可以按照上面的方式结合kubectl explain命令自己来验证下这种方式。
另外前面我们提到了探针里面有一个
initialDelaySeconds
的属性,可以来配置第一次执行探针的等待时间,对于启动非常慢的应用这个参数非常有用,比如 Jenkins、Gitlab 这类应用,但是如何设置一个合适的初始延迟时间呢?这个就和应用具体的环境有关系了,所以这个值往往不是通用的
,这样的话可能就会导致一个问题,我们的资源清单在别的环境下可能就会健康检查失败了,为解决这个问题,在 Kubernetes v1.16 版本官方特地新增了一个startupProbe(启动探针)
,该探针将推迟所有其他探针
,直到 Pod 完成启动为止
,使用方法和存活探针一样:startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30# 尽量设置大点
periodSeconds: 10
【05|05 Pod健康检查】比如上面这里的配置表示我们的慢速容器最多可以有5分钟(30个检查 * 10秒= 300s)来完成启动。
有的时候,应用程序可能暂时无法对外提供服务,例如,应用程序可能需要在启动期间加载大量数据或配置文件。在这种情况下,您不想杀死应用程序,也不想对外提供服务。那么这个时候我们就可以使用readiness probe来检测和减轻这些情况。 Pod 中的容器可以报告自己还没有准备,不能处理 Kubernetes 服务发送过来的流量。readiness probe的配置跟liveness probe基本上一致的。唯一的不同是使用readinessProbe而不是livenessProbe。两者如果同时使用的话就可以确保流量不会到达还未准备好的容器,准备好过后,如果应用程序出现了错误,则会重新启动容器。对于就绪探针我们会在后面 Service 的章节和大家继续介绍。
另外除了上面的initialDelaySeconds和periodSeconds属性外,探针还可以配置如下几个参数:
- timeoutSeconds:探测超时时间,默认1秒,最小1秒。
- successThreshold:探测失败后,最少连续探测成功多少次才被认定为成功。默认是 1,但是如果是
liveness
则必须是 1。最小值是 1。 - failureThreshold:探测成功后,最少连续探测失败多少次才被认定为失败。默认是 3,最小值是 1。