9.7 pod健康检查(三种探针)
-
pod健康检查和服务可用性检查:
种类 说明 startupProbe启动探针 k8s 1.16版本后引入的探测方式, 用于判断容器内应用程序是否已经启动
,如果配置了此探针,那么就会禁止其他的探测,直到它成功为止,成功后将不再探测。适用于某些应用启动比较慢的情况,如应用程序启动时需要与远程服务器建立网络连接,或者遇到网络访问较慢等情况,会造成容器启动缓慢,此时Readinessprob就不适用,因为这属于“有且仅有一次”的超长延时,可以通过StartupProbeLivenessProbe存活探针 用于探测容器是否存活(Running状态)
,如果探测失败,kubelet 会“杀死”容器并根据重启策略进行相应处理,若没有配置该探针,那么默认就是success。ReadinessProbe就绪探针 用于探测容器内的程序是否健康
,如果它的值是success,那么代表这个容器已经完成或者启动,并且程序已经是可以接受流量的状态。
9.7.1 探针四种实现方式
实现方式 | 说明 |
---|---|
ExecAction | 在容器内部运行一个命令,如果该命令返回码为0,则表明容器健康。 |
TCPSocketAction | 通过容器的IP地址和端口号执行TCP检查,如果能够建立TCP连接,则表明容器健康。 |
HTTPGetAction | 通过容器的IP地址、端口号及路径调用HTTP Get方法,如果响应码在200-400之间,则认为容器健康。 |
gRPC |
注:gRPC 容器探针功能进入 Beta 阶段,1.24 默认开启
9.7.2 配置探针
Probe 有很多配置字段,可以使用这些字段精确地控制启动、存活和就绪检测的行为:
1. initalDelaySeconds
- 容器启动后要等待多少秒才启动 启动(startupProbe)、存活(livenessProbe)和就绪(readinessProbe)探针。
- 如果定义了启动(starupProbe)探针,则存活(livenessProbe)探针和就绪(readinessProbe)探针的延迟将在启动(startupProbe)探针已成功之后才开始计算。
- 如果
periodSeconds
的值大于initialDelaySeconds
,则initialDelaySeconds
将被忽略。 - 默认是 0 秒,最小值是 0。
2. periodSeconds
- 执行探测的时间间隔(单位是秒)。
- 默认是 10 秒。最小值是 1。
3. timeoutSeconds
- 探测超时后等待多少秒。
- 默认值是 1 秒。最小值是 1。
4. successThreshold
- 探针在失败后,被视为成功的最小连续成功数。
- 默认值是 1。最小值是1。
- 存活(livenessProbe)和启动(startupProbe)探测的这个值必须是 1。
5. failureThreshold
- 探针连续失败了
failureThreshold
次之后, Kubernetes 认为总体上检查已失败:容器状态未就绪、不健康、不活跃。 - 对于启动(startupProbe)探针或存活(livenessProbe)探针而言,如果至少有
failureThreshold
个探针已失败, Kubernetes 会将容器视为不健康并为这个特定的容器触发重启操作。 - kubelet 遵循该容器的
terminationGracePeriodSeconds
设置。 - 对于失败的就绪(readinessProbe)探针,kubelet 继续运行检查失败的容器,并继续运行更多探针; 因为检查失败,kubelet 将 Pod 的
Ready
状况设置为false
。
6. terminationGracePeriodSeconds
- 为 kubelet 配置从为失败的容器触发终止操作到强制容器运行时停止该容器之前等待的宽限时长。
- 默认值是继承 Pod 级别的
terminationGracePeriodSeconds
值。 - 如果不设置则为 30 秒,最小值为 1。
注意:
如果就绪(readinessProbe)态探针的实现不正确,可能会导致容器中进程的数量不断上升。 如果不对其采取措施,很可能导致资源枯竭的状况。
9.7.3 livenessProbe 和 readinessProbe
场景:若是服务启动时间较长,虽然pod处于是Running状态,但是服务是不可用的
1. 创建探针
- 创建一个没有探针的 Pod
此时会出现pod运行状态正常,但其实服务不可用。
apiVersion: v1 # 必选, API 的版本号
kind: Pod # 必选,类型 Pod
metadata: # 必选,元数据
name: nginx # 必选,符合 RFC 1035 规范的 Pod 名称
spec: # 必选,用于定义 Pod 的详细信息
containers: # 必选,容器列表
- name: nginx # 必选,符合 RFC 1035 规范的容器名称
image: nginx:latest # 必选,容器所用的镜像的地址
imagePullPolicy: IfNotPresent
command: # 可选,容器启动执行的命令
- sh
- -c
- sleep 10; nginx -g "daemon off;"
ports: # 可选,容器需要暴露的端口号列表
- containerPort: 80 # 端口号
restartPolicy: Never
#创建pod
[root@k8s-master tanzhen]# kubectl create -f no-tanzhen.yaml
pod/nginx created
#立即查看pod运行状态,此时已是Running
[root@k8s-master tanzhen]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 4s 172.28.82.206 k8s-master <none> <none>
#通过curl请求nginx,10秒之内,是拒绝服务的
[root@k8s-master tanzhen]# curl 172.28.82.206
curl: (7) Failed connect to 172.28.82.206:80; Connection refused
#通过curl请求nginx,10秒之后,nginx服务才能正常请求
[root@k8s-master tanzhen]# curl 172.28.82.206
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
......
配置readinessProbe和livenessProbe健康检查:
apiVersion: v1 # 必选, API 的版本号
kind: Pod # 必选,类型 Pod
metadata: # 必选,元数据
name: nginx # 必选,符合 RFC 1035 规范的 Pod 名称
spec: # 必选,用于定义 Pod 的详细信息
containers: # 必选,容器列表
- name: nginx # 必选,符合 RFC 1035 规范的容器名称
image: davralin/nginx-autoindex # 必选,容器所用的镜像带pkill命令的地址
imagePullPolicy: IfNotPresent
command: # 可选,容器启动执行的命令
- sh
- -c
- sleep 10; nginx -g "daemon off;"
readinessProbe: # 可选,健康检查。注意三种检查方式同时只能使用一种。失败会切断流量
httpGet: # 接口检测方式
path: /index.html # 检查路径
port: 80
scheme: HTTP # HTTP or HTTPS
#httpHeaders: # 可选, 检查的请求头
#- name: end-user
# value: Jason
initialDelaySeconds: 10 # 初始化时间, 健康检查延迟执行时间
timeoutSeconds: 2 # 超时时间
periodSeconds: 5 # 检测间隔,循环检测(时间可以长一些)
successThreshold: 1 # 检查成功为 1 次表示就绪,接入流量
failureThreshold: 2 # 检测失败 2 次表示未就绪,切断流量
livenessProbe: # 可选,健康检查 存活检测,失败重启pod
tcpSocket: # 端口检测方式
port: 80
initialDelaySeconds: 10 # 初始化时间
timeoutSeconds: 2 # 超时时间
periodSeconds: 5 # 检测间隔
successThreshold: 1 # 检查成功为 1 次表示就绪
failureThreshold: 2 # 检测失败 2 次表示未就绪
ports: # 可选,容器需要暴露的端口号列表
- containerPort: 80 # 端口号
restartPolicy: Never
2.exec-liveness
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
在这个配置文件中,可以看到 Pod 中只有一个 Container
。 periodSeconds
字段指定了 kubelet 应该每 5 秒执行一次存活探测。 initialDelaySeconds
字段告诉 kubelet 在执行第一次探测前应该等待 5 秒。 kubelet 在容器内执行命令 cat /tmp/healthy
来进行探测。 如果命令执行成功并且返回值为 0,kubelet 就会认为这个容器是健康存活的。 如果这个命令返回非 0 值,kubelet 会杀死这个容器并重新启动它。
当容器启动时,执行如下命令:
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600"
这个容器生命的前 30 秒,/tmp/healthy
文件是存在的。 所以在这最开始的 30 秒内,执行命令 cat /tmp/healthy
会返回成功代码。 30 秒之后,执行命令 cat /tmp/healthy
就会返回失败代码。
在 30 秒内,查看 Pod 的事件,输出结果表明还没有存活探针失败::
# kubectl describe pod liveness-exec
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 11s default-scheduler Successfully assigned default/liveness-exec to node01
Normal Pulling 9s kubelet Pulling image "busybox"
Normal Pulled 7s kubelet Successfully pulled image "busybox"
Normal Created 7s kubelet Created container liveness
Normal Started 7s kubelet Started container liveness
35 秒之后,再来看 Pod 的事件,在输出结果的最下面,有信息显示存活探针失败了,这个失败的容器被杀死并且被重建了:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 57s default-scheduler Successfully assigned default/liveness-exec to node01
Normal Pulling 55s kubelet Pulling image "busybox"
Normal Pulled 53s kubelet Successfully pulled image "busybox"
Normal Created 53s kubelet Created container liveness
Normal Started 53s kubelet Started container liveness
Warning Unhealthy 10s (x3 over 20s) kubelet Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
Normal Killing 10s kubelet Container liveness failed liveness probe, will be restarted
再等 30 秒,确认这个容器被重启了:
# kubectl get pod liveness-exec
输出结果显示 RESTARTS
的值增加了 1。 请注意,一旦失败的容器恢复为运行状态,RESTARTS
计数器就会增加 1:
NAME READY STATUS RESTARTS AGE
liveness-exec 1/1 Running 1 1m
3. http-liveness
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
image: docker-ulucu-com.tencentcloudcr.com/base-service/liveness
args:
- /server
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
在这个配置文件中,你可以看到 Pod 也只有一个容器。 periodSeconds
字段指定了 kubelet 每隔 3 秒执行一次存活探测。 initialDelaySeconds
字段告诉 kubelet 在执行第一次探测前应该等待 3 秒。 kubelet 会向容器内运行的服务(服务在监听 8080 端口)发送一个 HTTP GET 请求来执行探测。 如果服务器上 /healthz
路径下的处理程序返回成功代码,则 kubelet 认为容器是健康存活的。 如果处理程序返回失败代码,则 kubelet 会杀死这个容器并将其重启。
返回大于或等于 200 并且小于 400 的任何代码都标示成功,其它返回代码都标示失败。
容器存活期间的最开始 10 秒中,/healthz
处理程序返回 200 的状态码。 之后处理程序返回 500 的状态码。
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
duration := time.Now().Sub(started)
if duration.Seconds() > 10 {
w.WriteHeader(500)
w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))
} else {
w.WriteHeader(200)
w.Write([]byte("ok"))
}
})
kubelet 在容器启动之后 3 秒开始执行健康检测。所以前几次健康检查都是成功的。 但是 10 秒之后,健康检查会失败,并且 kubelet 会杀死容器再重新启动容器。
10 秒之后,通过查看 Pod 事件来确认存活探针已经失败,并且容器被重新启动。
4. tcp-liveness-readinesss
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: docker-ulucu-com.tencentcloudcr.com/base-service/goproxy:1.0
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
TCP 检测的配置和 HTTP 检测非常相似。
- 就绪探针:kubelet 会在容器启动 5 秒后发送第一个就绪探针。 探针会尝试连接
goproxy
容器的 8080 端口。 如果探测成功,这个 Pod 会被标记为就绪状态,kubelet 将继续每隔 10 秒运行一次探测。 - 存活探针: kubelet 会在容器启动 15 秒后进行第一次存活探测。 与就绪探针类似,存活探针会尝试连接
goproxy
容器的 8080 端口。 如果存活探测失败,容器会被重新启动。
15 秒之后,通过看 Pod 事件来检测存活探针:
# kubectl describe pod goproxy
5. grpc-liveness
apiVersion: v1
kind: Pod
metadata:
name: etcd-with-grpc
spec:
containers:
- name: etcd
image: registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.5.0-0
command: [ "/usr/local/bin/etcd", "--data-dir", "/var/lib/etcd", "--listen-client-urls", "http://0.0.0.0:2379", "--advertise-client-urls", "http://127.0.0.1:2379", "--log-level", "debug"]
ports:
- containerPort: 2379
livenessProbe:
grpc:
port: 2379
initialDelaySeconds: 10
要使用 gRPC 探针,必须配置 port
属性。如果健康状态端点配置在非默认服务之上, 你还必须设置 service
属性。与 HTTP 和 TCP 探针不同,gRPC 探测不能使用命名端口或定制主机。
15 秒钟之后,查看 Pod 事件确认存活性检查并未失败:
# kubectl describe pod etcd-with-grpc
9.7.4 StartupProbe
-
针对服务启动时间较长的场景。
-
若通过增加存活(livenessProbe)探针的periodSeconds和failureThreshold配置,那么衍生出来,当服务启动之后,出现假死或者进程退出等情况下,pod不会在短时间内被重启,此时的服务是不可用的状态。
apiVersion: v1 # 必选, API 的版本号 kind: Pod # 必选,类型 Pod metadata: # 必选,元数据 name: nginx # 必选,符合 RFC 1035 规范的 Pod 名称 spec: # 必选,用于定义 Pod 的详细信息 containers: # 必选,容器列表 - name: nginx # 必选,符合 RFC 1035 规范的容器名称 image: davralin/nginx-autoindex # 必选,容器所用的镜像的地址 imagePullPolicy: IfNotPresent command: # 可选,容器启动执行的命令 - sh - -c - sleep 30; nginx -g "daemon off;" startupProbe: tcpSocket: # 端口检测方式 port: 80 initialDelaySeconds: 10 # 初始化时间 timeoutSeconds: 2 # 超时时间 periodSeconds: 5 # 检测间隔 successThreshold: 1 # 检查成功为 2 次表示就绪 failureThreshold: 5 # 检测失败 1 次表示未就绪 readinessProbe: # 可选,健康检查。注意三种检查方式同时只能使用一种。 httpGet: # 接口检测方式 path: /index.html # 检查路径 port: 80 scheme: HTTP # HTTP or HTTPS #httpHeaders: # 可选, 检查的请求头 #- name: end-user # value: Jason initialDelaySeconds: 2# 初始化时间, 健康检查延迟执行时间 timeoutSeconds: 2 # 超时时间 periodSeconds: 5 # 检测间隔 successThreshold: 1 # 检查成功为 2 次表示就绪 failureThreshold: 2 # 检测失败 1 次表示未就绪 livenessProbe: # 可选,健康检查 httpGet: path: /index.html port: 80 scheme: HTTP # exec: # 端口检测方式 # command: # - sh # - -c #- pgrep nginx initialDelaySeconds: 2 # 初始化时间 timeoutSeconds: 2 # 超时时间 periodSeconds: 5 # 检测间隔 successThreshold: 1 # 检查成功为 2 次表示就绪 failureThreshold: 2 # 检测失败 1 次表示未就绪 ports: # 可选,容器需要暴露的端口号列表 - containerPort: 80 # 端口号 restartPolicy: Always