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 秒。如果在这个时间内没有收到响应,探针会失败。

posted @ 2024-08-23 19:17  Hello_worlds  阅读(7)  评论(0编辑  收藏  举报