D10 kubernetes pod中容器健康检查探针
0、简介
》 当pod状态显示为running,这表明pod中所有容器都已经运行,但这并不意味着pod中的应用程序已经准备好提供服务。实际上,running状态仅仅表示容器的启动状态,与应用程序是否准备好提供服务没有直接关系。可能由于以下原因,应用程序不能提供服务:
- 应用程序启动慢:容器已运行,但容器中的应用程序还在启动中,这个时候容器仍然无法提供服务
- 应用程序假死:应用程序由于某种原因(死锁、代码bug),无法继续执行后面的工作
》 为了解决这类问题,kubernetes提供了探针机制。探针被配置为周期性检查容器中应用程序的健康状态。如果应用程序异常,则kubernetes将通过容器探针采取响应的措施。
- 探针支持以下三种类型
- startupProbe:启动探针,检查容器中应用程序是否启动。它仅用于容器启动阶段确定应用程序是否运行,一旦启动探针成功,它就不会再继续执行
- livenessProbe:存活探针,检查容器中应用程序是否运行。如果存活探针失败,kubernetes将重新启动容器,以尝试恢复应用程序的运行状态
- readinessProbe:就绪探针,监测容器中应用程序是否整备好接受流量。如果就绪探针失败,kubernetes将pod标记为未就绪准备,从而防止将新的流量转发到该pod
- 探针支持以下三种检查方法:
- httpGet:向容器中执行发送HTTP请求来判断健康状态,如果响应的状态码大于或等于200且小于400则表示成功,其他状态码则表示失败
- tcpSocket:向容器中指定端口简历TCP连接来判断健康状态。如果tcp建立成功,则表示成功,否则表示失败
- exec:在容器中执行命令,根据命令的退出状态码来判断健康状态。如果命令的退出状态为0,则表示成功,非0表示失败
1、启动探针
》 启动探针是在kubernetes1.18 版本中引入的,用于在容器启动时检查应用程序是否启动。与就绪探针和存活探针不通,启动探针是在容器启动时进行的,而不是在容器运行时进行的
- 以下是启动探针的使用场景
- 避免不必要的重启:由于某种原因(如节点负载高)导致引用程序启动慢,使得initialDelaySeconds字段的值小于应用程序启动时间,那么初次探活探针必然是失败的。这种情况如果持续存在,则将导致pod频繁的重启。通过配置启动探针,可以延迟开始执行存活探针的时间,等待启动探针成功后,再继续执行存活探针
- 依赖其他服务的应用:如果应用程序依赖其他服务(如数据库、消息队列)。则需要等待这些服务准备就绪后才能启动应用程序。通过配置启动探针,可以检查依赖是否准备就绪
- 启动探针配置示例如下:
cat pod-startup.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
app: pod-startup
name: pod-startup
spec:
containers:
- name: web
image: uhub.service.ucloud.cn/librarys/nginx:1.23
startupProbe:
httpget:
path: /index.html
port: 80
failureThreshold: 30
periodSeconds: 10
》 上述配置中,startupProbe部分定义了启动探针,它通过发送HTTP请求来判定应用程序是否启动。其中failureThreshold字段用于设置探针失败的次数,periodSeconds字段用于设置探针执行间隔的时间。这两个字段表示应用程序将有5min(30X10=300s)的时间来完成启动过程。如果在这段时间内探针成功,则启动探针将不在继续执行,存活探针将接管以进行持续监控;否则,容器会被重新启动
2、存活探针
》 存活探针用于周期性监控应用程序是否运行。存活探针配置如下:
cat pod-liveness.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
app: pod-liveness
name: pod-liveness
spec:
containers:
- name: web
image: uhub.service.ucloud.cn/librarys/nginx:1.23
livenessProbe:
httpGet:
path: /index.html
port: 80
initialDelaySeconds: 10
periodSeconds: 20
》 在上述配置中,livenessProbe部分定义了存活探针,各字段含义如下:
- httpGet:发送HTTP请求来判断健康状态
path:访问路径,默认是/
port:请求端口
此外,还可以指定
host:请求的ip地址,默认是pod ip
scheme:请求协议,支持http和https,默认是http
httpHeards:自定义http头
- initalDelaySeconds
容器启动后等待多少秒开始执行探针,这通常根据应用程序的启动时间来设置
- periodSeconds
执行探针的时间间隔(单位秒),默认是10秒
》 综上所述,kubelet将在容器启动10秒后发出第一个探针,该探针向地址http://podip:80/index.html发送http请求。如果响应的状态码不是200~400,则kubelet组件判断探针失败,出发重新启动容器。随后,每隔20秒执行一次存活探针
- 创建pod资源
kubectl apply -f pod-liveness.yaml
- 通过 kubectl logs pod-liveness 查看日志,可以看到探针发送的http请求日志
172.16.99.73 - - [26/Aug/2024:09:21:14 +0000] "GET /index.html HTTP/1.1" 200 615 "-" "kube-probe/1.28" "-"
- 尝试模拟应用程序故障,看看会发生什么。删除容器中的index.html,使其无法访问
kubectl exec -it pod-liveness -- rm -f /usr/share/nginx/html/index.html
- pod日志中,可以看到请求失败的日志。
kubectl logs pod-liveness
2024/08/26 09:33:54 [error] 29#29: *17 open() "/usr/share/nginx/html/index.html" failed (2: No such file or directory), client: 172.16.99.73, server: localhost, request: "GET /index.html HTTP/1.1", host: "10.244.58.196:80"
172.16.99.73 - - [26/Aug/2024:09:33:54 +0000] "GET /index.html HTTP/1.1" 404 153 "-" "kube-probe/1.28" "-"
- pod 对象中记录了重新启动的次数
kubectl get pods -l app=pod-liveness
NAME READY STATUS RESTARTS AGE
pod-liveness 1/1 Running 3 (4m8s ago) 17m
- 查看pod事件,可以看到探针执行失败并触发重新启动容器
kubectl describe pod pod-liveness
Warning Unhealthy 99s (x9 over 9m59s) kubelet Liveness probe failed: HTTP probe failed with statuscode: 404
Normal Killing 99s (x3 over 9m19s) kubelet Container web failed liveness probe, will be restarted
3、就绪探针
》 就绪探针用于周期性监控应用程序是否准备好接受流量,尤其适用于pod通过Service对外暴露的场景。
》 当用户访问Service时,Service会将流量转发到后端pod。那Service什么情况下会将流量转发给后端pod呢。答案是pod为准备就绪状态,既当 READY 值两侧相等时。
》 如果pod状态准备就绪,但应用程序出现异常,那么用户将访问失败。为了避免这样的问题,可以为容器设置就绪探针,根据就绪探针来决定pod是否准备就绪,而不是单纯地根据容器状态来决定
- 就绪探针配置如下
cat pod-readiness.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
app: pod-readiness
name: pod-readiness
spec:
containers:
- name: web
image: uhub.service.ucloud.cn/librarys/nginx:1.23
readinessProbe:
httpGet:
path: /index.html
port: 80
initialDelaySeconds: 10
periodSeconds: 20
》 在上述配置中,readinessProbe部分定义了就绪探针。kubelet组件将在容器启动10s后发送第一个探针,该探针指向地址 http://podip:80/index.html发送http请求。如果响应的http状态码不是200~400,则kubelet组件判定探针失败,并将该pod标记为未准备就绪,这样Service就会自动从后端移除pod,而无需为其转发流量。随后,每隔20s执行一次就绪探针。
- 创建pod
kubectl apply -f pod-readiness.yaml
- 为该pod创建一个Service
kubectl expose pod pod-readiness --port=80 --target-port=80
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 148m
pod-readiness ClusterIP 10.107.77.122 <none> 80/TCP 13s
》 集群中任意节点都可以通过ip地址 10.107.77.122 访问后端pod
》 查看Endpoints对象,确认Service后端关联的pod
kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 172.16.99.71:6443 155m
pod-readiness 10.244.85.197:80 7m17s
》 Endpoints对象由kubernetes自动创建,负责动态收集和管理与Service相关联的pod ip和端口,以确保后端pod的信息始终保持最新。尝试模拟应用程序故障,删除index.html文件
kubectl exec -it pod-readiness -- rm -f /usr/share/nginx/html/index.html
》 随后,kubelet组件执行探针失败,该pod被标记为未准备就绪。同时,Endpoints对象将移除该pod。再次查看Endpoints对象,可以看到ENDPOINTS列的值为空
kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 172.16.99.71:6443 161m
pod-readiness 12m
》 此时,Service将停止为该pod转发流量。一单探针成功,Endpoint对象就会自动添加该pod,Service将重新开始为该pod转发流量
- 现在模拟一下应用程序恢复
kubectl exec -it pod-readiness -- touch /usr/share/nginx/html/index.html
》 进行查看发现Endpoint已经添加了恢复的pod
kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 172.16.99.71:6443 163m
pod-readiness 10.244.85.197:80 15m
4、tcpSocket和exec检查方法
》 使用httpGet检查方法能准确的获取应用程序的健康状态,但该方法并不适用于所有应用程序,如MySQL、DNS、ssh等。因此,这类的应用程序则需要使用tcpSocket和exec检查方法
4.1、tcpSocket检查方法
- 配置示例如下
cat pod-liveness-tcp.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
app: pod-liveness-tcp
name: pod-liveness-tcp
spec:
containers:
- name: db
image: uhub.service.ucloud.cn/librarys/mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
livenessProbe:
tcpSocket:
port: 3306
initialDelaySeconds: 20
periodSeconds: 20
》 上述配置中,定义了mysql pod,并配置了存活探针。该探针通过尝试连接MySQL的3306端口来判断健康状态。
》 需要了解的是,MySQL自带一个mysqladmin ping命令,用于检查mysql的健康状态。在这种情况下,使用应用程序自带的方法相比tcpSocket更为准确
4.2 exec检查方法
- 配置示例如下
cat pod-liveness-exec.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
app: pod-liveness-exec
name: pod-liveness-exec
spec:
containers:
- name: db
image: uhub.service.ucloud.cn/librarys/mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
livenessProbe:
exec:
command:
- /bin/sh
- -c
- "mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}"
initialDelaySeconds: 20
periodSeconds: 20
》 在上述配置中,容器启动20s后执行 mysqladmin ping -u root -p 123456命令。命令如果执行成功,则将输出 mysqld is alive,并且该命令的退出状态码为0,以表示探针执行成功。命令如果执行失败,则将提示 连接本地mysql服务失败的错误,并且该命令的退出状态码为非0,以表示探针失败
5、实例
- 就绪探针实例
readinessProbe:
failureThreshold: 3
httpGet:
path: /pay/health
port: 8080
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 3
successThreshold: 1
timeoutSeconds: 180
1. failureThreshold: 3,每 3 秒进行一次健康检查
2. httpGet,使用httpget 通过 容器的 /pay/health 路径 检查容器是否健康
3. initialDelaySeconds: 30,容器启动后,Kubernetes 会等待 30 秒钟后才开始执行健康检查。这个延迟时间通常用于给应用足够的时间来启动并准备好接受流量。
4. periodSeconds: 3,健康检查的间隔时间为 3 秒,也就是说每 3 秒 Kubernetes 会执行一次健康检查。频繁检查可能会加重系统负担,频率过低可能会导致发现问题的速度变慢。
5. successThreshold: 1,表示容器健康检查只需要成功一次就认为容器已经准备好接受流量。
6. timeoutSeconds: 180,每次健康检查请求的最大等待时间为 180 秒。如果在这个时间内没有收到响应,探针会失败。