目录
- kubernetes之pod健康检查
- 1、概述和分类
- 2、LivenessProbe探针(存活性探测)
- 3、ReadinessProbe探针(就绪型探测)
- 4、探针的实现方式
- 4.1、ExecAction
- 4.2、HTTPGetAction
- 4.3、TCPSocketAction
- 5、探测行为属性
- 6、扩展的探测机制
kubernetes之pod健康检查
1、概述和分类
pod通过两类探针来检查容器的健康状态。分别是LivenessProbe(存活性探测)和ReadinessProbe(就绪型探测)
2、LivenessProbe探针(存活性探测)
用于判断容器是否健康(Running状态)并反馈给kubelet。有不少应用程序长时间持续运行后会逐渐转为不可用的状态,并且仅能通过重启操作恢复,kubernetes的容器存活性探测机制可发现诸如此类问题,并依据探测结果结合重启策略触发后的行为。存活性探测是隶属于容器级别的配置,kubelet可基于它判定何时需要重启一个容器。如果一个容器不包含LivenessProbe探针,那么kubelet认为该容器的LivenessProbe探针返回的值永远是Success。Pod spec为容器列表中的相应容器定义其专用的探针即可启用存活性检测,目前,kubernetes的容器支持存活性检测的方法包含以下三种:ExecAction、TCPSocketAction和HTTPGetAction。
3、ReadinessProbe探针(就绪型探测)
用于判断容器服务是否可用(Ready状态),达到Ready状态的Pod才可以接收请求。对于被Service管理的Pod,Service与Pod Endpoint的关联关系也将基于Pod是否Ready进行设置。Pod对象启动后,容器应用通常需要一段时间才能完成其初始化的过程,例如加载配置或数据,甚至有些程序需要运行某类的预热过程,若在此阶段完成之前即接入客户端的请求,势必会因为等待太久而影响用户体验。因此应该避免于Pod对象启动后立即让其处理客户端请求。而是等待容器初始化工作执行完成并转为Ready状态。尤其是存在其他提供相同服务的Pod对象的场景更是如此。如果在运行过程中Ready状态变为False,则系统自动将其从Service的后端Endpoint列表中隔离出去,后续再把恢复到Ready状态的Pod加回后端Endpoint列表。这样就能保证客户端在访问Service时不会被转发到服务不可用的Pod示例上。
4、探针的实现方式
LivenessProbe
和ReadinessProbe
均可配置以下三种探针实现方式:
可参考官方文档:https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/
4.1、ExecAction
通过在目标容器中执行由用户自定义的命令来判定容器的健康状态,即在容器内部执行一个命令,如果改命令的返回码为0,则表明容器健康。spec.containers.LivenessProbe
字段用于定义此类检测,它只有一个可用属性command
,用于指定要执行的命令,下面是在资源清单文件中使用liveness-exec
方式的示例:
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness-exec
name: liveness-exec
spec:
containers:
- name: liveness-demo
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 60; rm -rf /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- test
- -e
- /tmp/healthy
initialDelaySeconds: 15
timeoutSeconds: 1
上面的资源清单中定义了一个Pod
对象,基于busybox
镜像启动一个运行“touch /tmp/healthy; sleep 60; rm -rf /tmp/healthy; sleep 600”命令的容器,此命令在容器启动时创建/tmp/healthy文件,并于60秒之后将其删除,存活性探针运行“test -e /tmp/healthy”命令检查文件的存在性,若文件存在则返回状态码为0,表示成功通过测试。
创建该资源,并通过kubectl describe pods liveness-exec
查看详细信息
Containers:
liveness-demo:
Container ID: docker://a2974585905bdeef4ab39ba9a87bf710a61beae5180f31907ba33c8725c0bf79
Image: busybox
Image ID: docker-pullable://busybox@sha256:895ab622e92e18d6b461d671081757af7dbaa3b00e3e28e12505af7817f73649
Port:
Host Port:
Args:
/bin/sh
-c
touch /tmp/healthy; sleep 60; rm -rf /tmp/healthy; sleep 600
State: Running
Started: Wed, 14 Aug 2019 11:26:09 +0800
Last State: Terminated
Reason: Error
Exit Code: 137
Started: Wed, 14 Aug 2019 11:24:10 +0800
Finished: Wed, 14 Aug 2019 11:26:08 +0800
Ready: True
Restart Count: 2
Liveness: exec [test -e /tmp/healthy] delay=0s timeout=1s period=10s #success=1 #failure=3
Environment:
......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 2m26s default-scheduler Successfully assigned default/liveness-exec to 172.16.1.66
Warning Unhealthy 57s (x3 over 77s) kubelet, 172.16.1.66 Liveness probe failed:
Normal Pulling 27s (x2 over 2m23s) kubelet, 172.16.1.66 pulling image "busybox"
Normal Pulled 27s (x2 over 2m23s) kubelet, 172.16.1.66 Successfully pulled image "busybox"
Normal Killing 27s kubelet, 172.16.1.66 Killing container with id docker://liveness-demo:Container failed liveness probe.. Container will be killed and recreated.
Normal Created 26s (x2 over 2m22s) kubelet, 172.16.1.66 Created container
Normal Started 25s (x2 over 2m21s) kubelet, 172.16.1.66 Started container
输出信息中清晰的显示了容器健康状态检测变化的相关信息:容器当前处于Running
状态,但前一次是Terminated
,原因是退出码为137的错误信息,它表示进程是被外部信号所终止的。137事实上是由两部分数字之和生成的:128+signum,其中signum是导致进程终止信号的数字标识。9标识SIGKILL,这意味着进程是被强行终止的
待容器重启完成后再次查看,容器已经处于正常运行状态,直到文件再次被删除,存活性探测失败而重启,从下面结果可以看出,名为liveness-exec
的pod在10分钟内重启了5次
[root@master01 demo]# kubectl get pods liveness-exec
NAME READY STATUS RESTARTS AGE
liveness-exec 1/1 Running 5 10m
需要注意的是,exec
指定的命令运行于容器中,会消耗容器的可用资源配额,另外,考虑到探针操作的效率本身等因素,探针操作的命令应该尽可能简单和轻量。
4.2、HTTPGetAction
通过容器的ip
地址,端口号及路径调用HTTPGet
方法,如果响应的状态码大于等于200且小于400,则认为容器健康,spec.containers.livenessProbe.httpGet
字段用于定义此类检测,它的可用配置字段包括如下几个:
- host :请求的主机地址,默认为
Pod IP
;也可以在httpHeaders
中使用Host:
来定义 - port :请求的端口,必选字段
- httpHeader <[]Object>:自定义的请求报文首部
- path :请求的HTTP资源路径,即
URL path
- scheme:建立连接使用的协议,仅可为
HTTP
或HTTPS
,默认为HTTP
下面是在资源清单文件中使用liveness-http
方式的示例,通过lifecycle
最后那个的postStart hook
创建了一个专用于httpGet
测试的页面文件healthz
:
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness-demo
image: nginx:1.12-alpine
ports:
- name: http
containerPort: 80
lifecycle:
postStart:
exec:
command:
- /bin/sh
- -c
- 'echo Healty > /usr/share/nginx/html/healthz'
livenessProbe:
httpGet:
path: /healthz
port: http
scheme: HTTP
initialDelaySeconds: 30
timeoutSeconds: 1
上面的清单文件中定义的httpGet
测试中,请求的资源路径为/healthz
,地址默认为Pod IP,端口使用了容器中定义的端口名称HTTP
,这也是明确为容器指明要暴露的端口的用途之一,通过kubectl describe pods liveness-http
查看容器正常运行,健康状态检测为正常
Containers:
liveness-demo:
Container ID: docker://bf05e0a9e6e1ac95f67b91f0b167b9fc2e3ad0bd0ffa4336debcc4b3c24978a7
Image: nginx:1.12-alpine
Image ID: docker-pullable://nginx@sha256:3a7edf11b0448f171df8f4acac8850a55eff30d1d78c46cd65e7bc8260b0be5d
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Wed, 14 Aug 2019 12:01:31 +0800
Ready: True
Restart Count: 0
Liveness: http-get http://:http/healthz delay=30s timeout=1s period=10s #success=1 #failure=3
Environment:
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-g7ls6 (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-g7ls6:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-g7ls6
Optional: false
QoS Class: BestEffort
Node-Selectors:
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 6m51s default-scheduler Successfully assigned default/liveness-http to 172.16.1.66
Normal Pulling 6m48s kubelet, 172.16.1.66 pulling image "nginx:1.12-alpine"
Normal Pulled 6m43s kubelet, 172.16.1.66 Successfully pulled image "nginx:1.12-alpine"
Normal Created 6m43s kubelet, 172.16.1.66 Created container
Normal Started 6m42s kubelet, 172.16.1.66 Started container
通过kubectl exec
命令删除经由postStart hook创建的测试页面healthz
kubectl exec liveness-http rm /usr/share/nginx/html/healthz
再次查看资源详细信息,事件输出中的信息表明探测失败,容器被杀掉后被重新创建
......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 12m default-scheduler Successfully assigned default/liveness-http to 172.16.1.66
Normal Pulling 12m kubelet, 172.16.1.66 pulling image "nginx:1.12-alpine"
Normal Pulled 12m kubelet, 172.16.1.66 Successfully pulled image "nginx:1.12-alpine"
Warning Unhealthy 3s (x3 over 23s) kubelet, 172.16.1.66 Liveness probe failed: HTTP probe failed with statuscode: 404
Normal Created 2s (x2 over 12m) kubelet, 172.16.1.66 Created container
Normal Killing 2s kubelet, 172.16.1.66 Killing container with id docker://liveness-demo:Container failed liveness probe.. Container will be killed and recreated.
Normal Pulled 2s kubelet, 172.16.1.66 Container image "nginx:1.12-alpine" already present on machine
Normal Started 1s (x2 over 12m) kubelet, 172.16.1.66 Started container
一般来说,HTTP
类型的探测操作应该针对专用的URL路径进行,例如,示例中为其准备的/healthz
,另外,此URL路径对应的web资源应该以轻量化的方式在内部对应用程序的各关键组件进行全面检测以确保它们可以正常向客户端提供完整的服务。
这种检测方式仅对分层架构中的当前一层有效,例如,它能检测应用程序工作正常与否的状态,但重启操作却无法解决其后端服务(如数据库或缓存服务)导致的故障,此时,容器可能会被一次次重启,直到后端服务恢复正常为止。
4.3、TCPSocketAction
通过容器的IP地址和端口号进行TCP
检查,如果能够建立TCP
连接,则表明容器健康。相比较来说,它比基于HTTP
的探测要更高效,更节约资源,但精准度略低,毕竟建立连接成功未必意味着页面资源可用,spec.containers.livenessProbe.tcpSocket
字段用于定义此类检测,它主要包含以下两个可用的属性:
- host:请求连接的目标
IP
地址,默认为Pod IP
- port:请求连接的目标端口,必选字段
下面是在资源清单文件中使用liveness-tcp
方式的示例,它向Pod IP
的80/tcp端口发起连接请求,并根据连接建立的状态判定测试结果:
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-tcp
spec:
containers:
- name: liveness-tcp-demo
image: nginx:1.12-alpine
ports:
- name: http
containerPort: 80
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 30
timeoutSeconds: 1
通过kubectl describe pods liveness-http
查看容器正常运行,健康状态检测为正常
Containers:
liveness-tcp-demo:
Container ID: docker://816b27781aeb384e1305e0a5badebd5ea21ea98c834e62179cd1dac2a704ccd7
Image: nginx:1.12-alpine
Image ID: docker-pullable://nginx@sha256:3a7edf11b0448f171df8f4acac8850a55eff30d1d78c46cd65e7bc8260b0be5d
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Wed, 14 Aug 2019 12:29:12 +0800
Ready: True
Restart Count: 0
Liveness: tcp-socket :80 delay=30s timeout=1s period=10s #success=1 #failure=3
Environment:
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-g7ls6 (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-g7ls6:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-g7ls6
Optional: false
QoS Class: BestEffort
Node-Selectors:
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 62s default-scheduler Successfully assigned default/liveness-tcp to 172.16.1.66
Normal Pulled 60s kubelet, 172.16.1.66 Container image "nginx:1.12-alpine" already present on machine
Normal Created 60s kubelet, 172.16.1.66 Created container
Normal Started 59s kubelet, 172.16.1.66 Started container
5、探测行为属性
使用kubectl describe
命令查看配置了存活性探测或者就绪型探测对象的详细信息时,其相关内容中会包含如下内容:
Liveness: exec [test -e /tmp/healthy] delay=15s timeout=1s period=10s #success=1 #failure=3
它给出了探测方式及其额外的配置属性delay
、timeout
、period
、success
、failure
及其各自的相关属性值,用户没有明确定义这些属性字段时,他们会使用各自的默认值,这些属性值可通过spec.containers.livenessProbe
的如下属性字段来给出:
initialDelaySeconds
:存活性探测延迟时长,即容器启动多久后再开始第一次探测操作,显示为delay
属性,默认为0秒,即容器启动后立刻开始进行探测。timeoutSeconds
:存活性探测的超时时长,显示为timeout属性,默认为1s,最小值也为1s。periodSeconds
:存活性探测的频度,显示为period属性,默认为10s,最小值为1s;过高的频率会对pod
对象带来较大的额外开销,而过低的频率又会使得对错误的反应不及时。successThreshold
:处于失败状态时,探测操作至少连续多少次的成功才被认为是通过检测,显示为#success
属性,默认值为1,最小值也为1。failureThreshold
:处于成功状态时,探测操作至少连续多少次的失败才被视为是检测不通过,显示为#failure
属性,默认值为3,最小值为1。
6、扩展的探测机制
kubernetes
的ReadinessProbe
机制可能无法满足某些复杂应用对容器内服务可用状态的判断,所以kubernetes
从1.11
版本开始引入了Pod Ready++
特性对Readiness
探测机制进行扩展,在1.14
版本时达到GA
稳定版本,称其为Pod Readiness Gates
。
通过Pod Readiness Gates
机制,用户可以将自定义的ReadinessProbe
探测方式设置在Pod
上,辅助kubernetes
设置Pod
何时达到服务可用状态Ready
,为了使自定义的ReadinessProbe
生效,用户需要提供一个外部的控制器Controller
来设置相应的Condition
状态。Pod
的Readiness Gates
在pod
定义中的ReadinessGates
字段进行设置,如下示例设置了一个类型为www.example.com/feature-1的新Readiness Gates
:
Kind: Pod
......
spec:
readinessGates:
- conditionType: "www.example.com/feature-1"
status:
conditions:
- type: Ready # kubernetes系统内置的名为Ready的Condition
status: "True"
lastProbeTime: null
lastTransitionTime: 2018-01-01T00:00:00Z
- type: "www.example.com/feature-1" # 用户定义的Condition
status: "False"
lastProbeTime: null
lastTransitionTime: 2018-01-01T00:00:00Z
containerStatuses:
- containerID: docker://abcd...
ready: true
......
新增的自定义Condition
的状态status
将由用户自定义的外部控制器设置,默认值为False
,kubernetes
将在判断全部readinessGates
条件都为True
时,才设置pod
为服务可用状态(Ready或True)
参考地址:https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-readiness-gate