k8s笔记(4)-- pod生命周期和健康状态探测

前言

本文主要系统的介绍pod和pod健康状态探测。探测类型包括liveness,readiness和startup。

什么是pod

Pod是Kubernetes创建或部署的最小且最简单的基本单位,Pod表示在集群上运行的进程。

Pod封装了一个或多个运行应用程序的容器,存储资源,唯一的网络IP和控制容器运行方式的一些选项。一般会将docker作为k8s的容器运行时(container runtime),不过也可以使用其他容器运行时,如CRI-O(k8s项目),Containerd(docker项目)等。

容器运行时负责真正管理镜像和容器的生命周期。

pod使用方式

查看pod的yaml参数:kubectl explain pods.spec.containers

  • 运行单个容器的容器: 一个pod存在一个容器;

  • 运行多个需要协同工作的容器的pod:一个pod存在多个容器协同工作,该应用程序由紧密耦合且需要共享资源的多个位于同一地点的容器组成。多个容器是紧耦合的,共享网络和存储,通过lo接口互相通信,对外呈现为一个单独的pod实体。如果想水平扩展pod,可通过Controller Manager复制多个pod提供负载均衡服务。

pod生命周期

k8s笔记(4)-- pod生命周期和健康状态探测_第1张图片
pod生命周期:

  • 初始化容器阶段会初始化pod中每一个容器,容器是串行执行的。
  • 启动main container,在main container刚刚启动后就可执行postStart指令。
  • 在整个main container运行周期中做两类健康探测:liveness probe(存活探测)和readiness probe(就绪探测)
  • 在main container结束前可以执行preStop命令

lifestyle

创建pod时,可以用lifecycle来配置容器在运行前和关闭前的一些动作。
kubectl explain pod.spec.containers.lifecycle
lifecycle有两个钩子函数:

  • postStart:容器创建成功后,运行前的任务,用于资源部署、环境准备等。
  • preStop:在容器被终止前,用于优雅的关闭应用程序、通知其他系统等。

postStart

创建容器后立即调用PostStart。如果处理程序失败,容器将根据其终止并重启策略重新启动。直到preStart完成才会进入下一步,如livenessProbe。

# kubectl explain pod.spec.containers.lifecycle.postStart
# cat preStart-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
        name: perstart-exec-pod
        namespace: default
spec:
        containers:
                - name: perstart-exec-container
                  image: busybox:latest
                  imagePullPolicy: IfNotPresent
                  lifecycle:
                        postStart:
                                exec:
                                        command: ['/bin/sh','-c','echo test >>/tmp/index.html']
                  command: ['/bin/httpd']
                  args: ['-f','-h /tmp']

preStart类似,没有好的栗子,不做介绍。

pod状态

kubectl explain pods.status.phase

通过phase字段来表示pod的状态,该字段是只读的。Pod生命周期中的状态包括:

  • Pending: Pod 已被 Kubernetes 接受,但尚未创建一个或多个容器镜像。这包括被调度之前的时间以及通过网络下载镜像所花费的时间,执行需要一段时间。
  • Running: Pod 已经被绑定到了一个节点,所有容器已被创建。至少一个容器正在运行,或者正在启动或重新启动
  • Succeeded: 所有容器成功终止,也不会重启。
  • Failed: 所有容器终止,至少有一个容器以失败方式终止。也就是说,这个容器要么已非 0 状态退出,要么被系统终止。
  • Unknown: 由于一些原因,Pod 的状态无法获取,通常是与 Pod 通信时出错导致的。

pod健康状态探测

当创建pod后,如何确定pod容器是否正常启动?pod中的应用是否正常启动?pod应用是否正常返回?是否可以对pod进行健康检查?kubelet可以选择对正在运行的容器进行三种健康状态探测并进行相应处理:livenessProbe,readinessProbe和startupProbe。yaml字段查看:kubectl explain pod.spec.containers.livenessProbe

  • livenessProbe: 存活探针,探测容器是否正在运行。如果存活探针失败,则kubelet将kill掉容器,并且容器将接受其重启策略。如果容器未配置存活探针,则默认状态为Success
  • readinessProbe: 就绪探针,探测容器是否准备好服务请求。如果就绪探针失败,则会从对应的service中移除Pod的IP地址。初始延迟之前的默认就绪状态为Failure。如果容器未提供就绪探针,则默认状态为Success
  • startupProbe: 启动探针,探测容器中的应用程序是否已启动,通常用来探测需要额外启动时间的容器应用程序。如果提供了启动探针,则将禁用所有其他探针,直到启动探针成功。如果启动探针失败,则kubelet将杀死Container,并且Container将接受其重启策略。如果容器未提供启动探针,则默认状态为Success

容器的重启策略包括:Always(正常和异常退出都重启)、OnFailure(异常退出重启)和Never(从不重启),默认值为Always。kubectl explain pod.spec.restartPolicy

每种探测都支持三种探测方法(探针):

  • ExecAction:在Container中执行指定命令。如果命令以状态代码0退出,则认为检查成功。
  • TCPSocketAction:对指定端口上的容器的IP地址执行TCP检查。如果端口打开,则认为检查成功。
  • HTTPGetAction:对指定端口和路径上的容器的IP地址执行HTTP Get请求。如果响应的状态码大于或等于200且小于400,则认为检查成功。

每个探针具有以下三个结果之一:

  • Success:容器通过了检查。
  • Failure:容器无法通过检查。
  • Unknown:检查失败,因此不应采取任何措施。

livenessProbe

容器长时间运行出现故障需要重启恢复时,可用存活探针。

示例:

# exec探针探测
apiVersion: v1
kind: Pod
metadata:
        name: liveness-exec-pod
        namespace: default
spec:
        containers:
                - name: liveness-exec-container
                  image: busybox:latest
                  # 容器启动执行命令
                  command: ['/bin/sh','-c','touch /tmp/healthy; sleep 10;rm -f /tmp/healthy; sleep 50;']
                  livenessProbe:
                        exec:
                        		# 通过检测目录是否存在探测系统是否正常启动
                                command: ['test','-e','/tmp/healthy']
                        # 初始化延迟探测,第一次探测之前等待1s,因为主程序未必启动完成
                        initialDelaySeconds: 1
                        # 每3秒探测一次
                        periodSeconds: 3
                        # 最大失败次数
                        failureThreshold: 2
                        # 探测超时时长
                        timeoutSeconds: 1

生成pod看下,可以看到pod启动成功了,但过会会检测失败,被kill,重启,再检测失败,再重启。。。

# httpGet探针探测
apiVersion: v1
kind: Pod
metadata:
        name: liveness-httpget-pod
        namespace: default
spec:
        containers:
                - name: liveness-httpget-container
                  image: nginx:latest
                  ports:
                  - name: nginx
                    containerPort: 80
                  livenessProbe:
                  		# 访问首页,探测nginx是否正常返回
                        httpGet:
                                port: nginx
                                path: /index.html
                        initialDelaySeconds: 1
                        periodSeconds: 3

生成pod看下,由于探针探测到http会返回404,可以看到第一次pod启动就失败了(killing),然后可以看到根据重启策略(默认always)重启了机器方便恢复(started),但由于配置没变探测还是返回404Unhealthy,所以会循环kill重启。所以这不是个恰当的栗子,因为重启了也不能恢复,所以容器会一直重启,先凑合着看吧。

# kubectl apply -f liveness-httpget.yaml
# kubectl get pods -w
NAME                               READY   STATUS    RESTARTS   AGE
liveness-httpget-pod               1/1     Running   3          26s
liveness-httpget-pod               0/1     CrashLoopBackOff   5          3m13s

# kubectl describe pods liveness-httpget-pod
...
Events:
  Type     Reason     Age               From               Message
  ----     ------     ----              ----               -------
  Normal   Scheduled  22s               default-scheduler  Successfully assigned default/liveness-httpget-pod to node1
  Normal   Pulled     4s (x3 over 21s)  kubelet, node1     Container image "nginx:latest" already present on machine
  Normal   Created    4s (x3 over 21s)  kubelet, node1     Created container liveness-httpget-container
  Normal   Killing    4s (x2 over 13s)  kubelet, node1     Container liveness-httpget-container failed liveness probe, will be restarted
  Normal   Started    3s (x3 over 21s)  kubelet, node1     Started container liveness-httpget-container
  Warning  Unhealthy  1s (x7 over 19s)  kubelet, node1     Liveness probe failed: HTTP probe failed with statuscode: 404

readinessProbe

应用程序可能需要在启动过程中加载大数据或配置文件,或者在启动后依赖于外部服务。在这种情况下,您不想杀死应用程序,但也不想发送请求。Kubernetes提供了准备就绪探针以检测和缓解这些情况。带有容器的容器报告其容器尚未准备就绪,无法通过Kubernetes Services接收流量。

示例:

# httpGet探针探测,readinessProbe 和livenessProbe写法差不多,只不过字段名不同
apiVersion: v1
kind: Pod
metadata:
        name: readiness-httpget-pod
        namespace: default
spec:
        containers:
                - name: readiness-httpget-container
                  image: nginx:latest
                  ports:
                  - name: nginx
                    containerPort: 80
                  readinessProbe:
                        httpGet:
                                port: nginx
                                path: /ihealthy.html
                        initialDelaySeconds: 1
                        periodSeconds: 3

生成个pod看下,可以看到容器创建了,也成功启动了,但启动后执行就绪检测失败,容器unhealthy。然后get pod 看下,readiness-httpget-pod 一直处于unready状态。但为什么没有重启恢复?なぜだ??因为就绪探针的故障处理方式是如果该pod加入了service,仅会从service中剔除pod ip。
这里可以很明确的看到liveness和readiness的区别:前者是在启动时检测容器是否故障,处理方法是重启,可以看到都RESTART了7次了,后者是在启动后检测程序是否就绪,处理方法是剔除pod ip。

# kubectl apply -f readiness-httpget.yaml
# kubectl describe pods readiness-httpget-pod
Events:
  Type     Reason     Age              From               Message
  ----     ------     ----             ----               -------
  Normal   Scheduled  8s               default-scheduler  Successfully assigned default/readiness-httpget-pod to node2
  Normal   Pulled     7s               kubelet, node2     Container image "nginx:latest" already present on machine
  Normal   Created    7s               kubelet, node2     Created container readiness-httpget-container
  Normal   Started    6s               kubelet, node2     Started container readiness-httpget-container
  Warning  Unhealthy  1s (x2 over 4s)  kubelet, node2     Readiness probe failed: HTTP probe failed with statuscode: 404

## kubectl get pods -w
NAME                               READY   STATUS             RESTARTS   AGE
liveness-httpget-pod               0/1     CrashLoopBackOff   7          8m7s
readiness-httpget-pod             0/1     Running            0          5m50s

所以总结: 存活探针和就绪探针可以并行用于同一容器。同时使用这两者可以确保流量不会到达尚未准备就绪的容器,并且可以确保容器在发生故障时重新启动。

startupProbe

直接复制官方的,已放弃治疗。。。

在处理可能在首次初始化时需要额外启动时间的旧版应用程序时,会用到startupProbe。在这种情况下,在不影响对激发此类探测器的死锁的快速响应的情况下,如果设置活动性探测器参数可能很棘手。诀窍是使用相同的命令HTTP或TCP检查来设置启动探针,并使用failThreshold * periodSecond足够长的时间来覆盖最坏情况下的启动时间。

ports:
- name: liveness-port
  containerPort: 8080
  hostPort: 8080

livenessProbe:
  httpGet:
    path: /healthz
    port: liveness-port
  failureThreshold: 1
  periodSeconds: 10

startupProbe:
  httpGet:
    path: /healthz
    port: liveness-port
  failureThreshold: 30
  periodSeconds: 10

补充

健康检测仅做检测,恢复由重启进行,不能检测那块写故障恢复的命令,可能会干扰重启恢复。

参考与扩展

  • 超详细的pod官方介绍

  • probe官方实践

你可能感兴趣的:(k8s)