《k8s权威指南》读书笔记-Pod生命周期&健康检查

4.Pod的生命周期和重启策略

  • 生命周期

    • Pod 遵循一个预定义的生命周期,起始于 Pending 阶段,如果至少 其中有一个主要容器正常启动,则进入 Running,之后取决于 Pod 中是否有容器以 失败状态结束而进入 Succeeded 或者 Failed 阶段。
  • Pod状态

    • Pending(悬决)

      • Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。

      • 此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。

    • Running(运行中)

      • Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。

      • 至少有一个容器仍在运行,或者正处于启动或重启状态。

    • Succeeded(成功)

      • Pod 中的所有容器都已成功终止,并且不会再重启。
    • Failed(失败)

      • Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。

      • 也就是说,容器以非 0 状态退出或者被系统终止。

      • 如果某节点死掉或者与集群中其他节点失联,Kubernetes 会实施一种策略,将失去的节点上运行的所有 Pod 的 phase 设置为 Failed

    • Unknown(未知)

      • 因为某些原因无法取得 Pod 的状态。

      • 这种情况通常是因为与 Pod 所在主机通信失败。

  • Pod重启策略

    • Pod的重启策略(RestartPolicy)应用于Pod内的所有容器,并且仅在Pod所处的Node上由kubelet进行判断和重启操作。

    • 当某个容器异常退出或者健康检查失败时,kubelet将根据RestartPolicy的设置来进行相应的操作。

    • Pod的重启策略包括Always、OnFailure和Never,默认值为Always。

      • Always:当容器失效时,由kubelet自动重启该容器。

      • OnFailure:当容器终止运行且退出码不为0时,由kubelet自动重启该容器。

      • Never:不论容器运行状态如何,kubelet都不会重启该容器。

    • kubelet重启失效容器的时间间隔以sync-frequency乘以2n来计算,例如1、2、4、8倍等,最长延时5min,并且在成功重启后的10min后重置该时间。

    • Pod的重启策略与控制方式息息相关,当前可用于管理Pod的控制器包括ReplicationController、Job、DaemonSet及直接通过kubelet管理(静态Pod)。每种控制器对Pod的重启策略要求如下:

      • RC和DaemonSet:必须设置为Always,需要保证该容器持续运行。

      • Job:OnFailure或Never,确保容器执行完成后不再重启。

      • kubelet:在Pod失效时自动重启它,不论将RestartPolicy设置为什么值,也不会对Pod进行健康检查。

    • 结合Pod的状态和重启策略,列出一些常见的状态转换场景:

image.png

5.Pod健康检查和服务可用性检查

5.1 Kubernetes 对 Pod 的健康状态可以通过探针来检查

  Kubernetes 对 Pod 的健康状态可以通过探针来检查,kubelet定期执行探针来诊断容器的健康状况。

  • LivenessProbe探针:

    • 用于判断容器是否存活(Running状态)

      • 如果LivenessProbe探针探测到容器不健康,则kubelet将杀掉该容器,并根据容器的重启策略做相应的处理。

      • 如果一个容器不包含LivenessProbe探针,那么kubelet认为该容器的LivenessProbe探针返回的值永远是Success。

  • ReadinessProbe探针:

    • 用于判断容器服务是否可用(Ready状态),达到Ready状态的Pod才可以接收请求。

      • 对于被Service管理的Pod,Service与Pod Endpoint的关联关系也将基于Pod是否Ready进行设置。

      • 如果在运行过程中Ready状态变为False,则系统自动将其从Service的后端Endpoint列表中隔离出去,后续再把恢复到Ready状态的Pod加回后端Endpoint列表。

      • 这样就能保证客户端在访问Service时不会被转发到服务不可用的Pod实例上。

  • startupProbe探针:

    • 指示容器中的应用是否已经启动。

      • 如果提供了启动探针,则所有其他探针都会被 禁用,直到此探针成功为止。

      • 如果启动探测失败,kubelet 将杀死容器,而容器依其 重启策略进行重启。

      • 如果容器没有提供启动探测,则默认状态为 Success

5.2 LivenessProbe和ReadinessProbe均可配置以下三种实现方式

(1)定义存活命令

ExecAction:在容器内部执行一个命令,如果该命令的返回码为0,则表明容器健康。

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy             # kubelet 在容器内执行命令 `cat /tmp/healthy` 来进行探测
      initialDelaySeconds: 5       # `initialDelaySeconds` 字段告诉 kubelet 在执行第一次探测前应该等待 5 秒
      periodSeconds: 5             # `periodSeconds` 字段指定了 kubelet 应该每 5 秒执行一次存活探测

  在这个配置文件中,可以看到 Pod 中只有一个容器。 periodSeconds 字段指定了 kubelet 应该每 5 秒执行一次存活探测。 initialDelaySeconds 字段告诉 kubelet 在执行第一次探测前应该等待 5 秒。 kubelet 在容器内执行命令 cat /tmp/healthy 来进行探测。 如果命令执行成功并且返回值为 0,kubelet 就会认为这个容器是健康存活的。 如果这个命令返回非 0 值,kubelet 会杀死这个容器并重新启动它。

例子:

下面例子中,通过删除/tmp/healthy,展示pod通过探针检查健康状态和重启的过程。

当容器启动时,执行如下的命令:


/bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600"

这个容器生命的前 30 秒, /tmp/healthy 文件是存在的。 所以在这最开始的 30 秒内,执行命令 cat /tmp/healthy 会返回成功代码。 30 秒之后,执行命令 cat /tmp/healthy 就会返回失败错误码。

创建 Pod:


kubectl apply -f exec-liveness.yaml

在 30 秒内,查看 Pod 的事件:


kubectl describe pod liveness-exec

输出结果表明还没有存活探测器失败:


FirstSeen    LastSeen    Count   From            SubobjectPath           Type        Reason      Message

--------- --------    -----   ----            -------------           --------    ------      -------

24s       24s     1   {default-scheduler }                    Normal      Scheduled   Successfully assigned liveness-exec to worker0

23s       23s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Pulling     pulling image "k8s.gcr.io/busybox"

23s       23s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Pulled      Successfully pulled image "k8s.gcr.io/busybox"

23s       23s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Created     Created container with docker id 86849c15382e; Security:[seccomp=unconfined]

23s       23s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Started     Started container with docker id 86849c15382e

35 秒之后,再来看 Pod 的事件:


#kubectl describe pod liveness-exec

//在输出结果的最下面,有信息显示存活探测器失败了,这个容器被杀死并且被重建了。

FirstSeen LastSeen    Count   From            SubobjectPath           Type        Reason      Message

--------- --------    -----   ----            -------------           --------    ------      -------

37s       37s     1   {default-scheduler }                    Normal      Scheduled   Successfully assigned liveness-exec to worker0

36s       36s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Pulling     pulling image "k8s.gcr.io/busybox"

36s       36s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Pulled      Successfully pulled image "k8s.gcr.io/busybox"

36s       36s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Created     Created container with docker id 86849c15382e; Security:[seccomp=unconfined]

36s       36s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Started     Started container with docker id 86849c15382e

2s        2s      1   {kubelet worker0}   spec.containers{liveness}   Warning     Unhealthy   Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory

再等另外 30 秒,检查看这个容器被重启了:


#kubectl get pod liveness-exec

//输出结果显示 RESTARTS 的值增加了 1。

NAME            READY     STATUS    RESTARTS   AGE

liveness-exec   1/1       Running   1          1m

(2)定义TCP的存活探测

  TCPSocketAction:通过容器的IP地址和端口号执行TCP检查,如果能够建立TCP连接,则表明容器健康。

apiVersion: v1
kind: Pod
metadata:
  name: goproxy
  labels:
    app: goproxy
spec:
  containers:
  - name: goproxy
    image: k8s.gcr.io/goproxy:0.1
    ports:
    - containerPort: 8080
    readinessProbe:        # 就绪探针
      tcpSocket:   #tcp
        port: 8080
      initialDelaySeconds: 5  
      periodSeconds: 10
    livenessProbe:        #存活探针
      tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20

就绪探针:kubelet 会在容器启动 5 秒后发送第一个就绪探测。 这会尝试连接 goproxy 容器的 8080 端口。 如果探测成功,这个 Pod 会被标记为就绪状态,kubelet 将继续每隔 10 秒运行一次检测。

存活探针:kubelet 会在容器启动 15 秒后进行第一次存活探测。 与就绪探测类似,会尝试连接 goproxy 容器的 8080 端口。 如果存活探测失败,这个容器会被重新启动。

(3)定义一个存活态HTTP请求接口

  HTTPGetAction:通过容器的IP地址、端口号及路径调用HTTP Get方法,如果响应的状态码大于等于200且小于400,则认为容器健康。

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/liveness
    args:
    - /server
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
        httpHeaders:
        - name: Custom-Header
          value: Awesome
      initialDelaySeconds: 3   #启动容器后进行首次健康检查的等待时间,单位为s。
      periodSeconds: 3         #每隔3s检查一次  
      timeoutSeconds:1         #健康检查发送请求后等待响应的超时时间,单位为s。当超时发生时,kubelet会认为容器已经无法提供服务,将会重启该容器。

  在这个配置文件中,可以看到 Pod 也只有一个容器。 periodSeconds 字段指定了 kubelet 每隔 3 秒执行一次存活探测。 initialDelaySeconds 字段告诉 kubelet 在执行第一次探测前应该等待 3 秒。 kubelet 会向容器内运行的服务(服务会监听 8080 端口)发送一个 HTTP GET 请求来执行探测。 如果服务器上 /healthz 路径下的处理程序返回成功代码,则 kubelet 认为容器是健康存活的。 如果处理程序返回失败代码,则 kubelet 会杀死这个容器并且重新启动它。

  任何大于或等于 200 并且小于 400 的返回代码标示成功,其它返回代码都标示失败。

你可能感兴趣的:(《k8s权威指南》读书笔记-Pod生命周期&健康检查)