一、Pod的生命周期

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

在 Pod 运行期间,Kubernetes能够重启容器以处理一些失效场景。 在 Pod 内部,Kubernetes 跟踪不同容器的状态,并确定使 Pod 重新变得健康所需要采取的动作。

当我们运行一个Pod的时候,可以通过如下命令来查看Pod的运行状态:

kubectl get pod

输出结果如下,其中的status字段就是Pod的状态。

[root@kubernetes-master01 ~]# kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
pod-nginx   1/1     Running   3          86m

上面输出结果中的Status字段是一个PodStatus对象,其中包含一个phase字段。下面是phase字段的值与值的定义:

取值

描述

Pending(悬决)

Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。

Running(运行中)

Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。

Succeeded(成功)

Pod 中的所有容器都已成功终止,并且不会再重启。

Failed(失败)

Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。

Unknown(未知)

因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。

Pod是一个或多个容器的封装,那么容器的状态又有哪些呢?容器的状态有三种:

  • Waiting(等待):如果容器并不处在 Running 或 Terminated 状态之一,它就处在 Waiting 状态。 处于 Waiting 状态的容器仍在运行它完成启动所需要的操作:例如,从某个容器镜像 仓库拉取容器镜像,或者向容器应用 Secret 数据等等。 当你使用 kubectl 来查询包含 Waiting 状态的容器的 Pod 时,你也会看到一个 Reason 字段,其中给出了容器处于等待状态的原因。
  • Running(运行中):Running状态表明容器正在执行状态并且没有问题发生。如果配置了 postStart 回调,那么该回调已经执行且已完成。如果你使用 kubectl 来查询包含 Running 状态的容器的 Pod 时,你也会看到 关于容器进入 Running 状态的信息。
  • Terminated(已终止):处于 Terminated 状态的容器已经开始执行并且或者正常结束或者因为某些原因失败。 如果你使用 kubectl 来查询包含 Terminated状态的容器的 Pod 时,你会看到 容器进入此状态的原因、退出代码以及容器执行期间的起止时间。如果容器配置了 preStop 回调,则该回调会在容器进入 Terminated 状态之前执行。

根据容器的运行状态,容器会按照重启策略来进行容器的恢复工作。容器的重启策略是使用restartPolicy这个参数在yaml文件中指定的,Pod的重启策略包括Always、OnFailure和Never,默认值为Always。

  • Always:当容器失效时,由Kubernetes自动重启该容器。
  • OnFailure:当容器终止运行且退出码不为0时,由Kubernetes自动重启该容器。
  • Never:不论容器运行状态如何,Kubernetes都不会重启该容器。

接下来我们来运行一个busybox的容器的Pod,并进行postStart与preStop的设置。

我们编辑一个文件pod-nginx-post-pre.yaml,内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-nginx-post-pre
spec:
   containers:
   - name: nginx
     image: nginx
     lifecycle:
       postStart:
         exec:
           command: ['sh','-c','touch /tmp/file; echo Pod postStart >> /tmp/file;']
       preStop:
         exec:
           command: ['sh','-c','echo Pod preStop >> /tmp/file;']

Pod pod-nginx-post-pre是运行了一个nginx容器,并在其中设置了两个钩子函数:

  • postStart:在容器开始之后,创建一个文件tmp目录下的file了,并打印Pod postStart到文件中。
  • preStop:在容器即将关闭之前,打印Pod preStop到tmp目录下的file文件中。

创建这个Pod:

[root@kubernetes-master01 k8s-yaml]# kubectl apply -f pod-nginx-post-pre.yaml
pod/pod-nginx-post-pre created

登录到这个Pod中,并查看file中的内容:

[root@kubernetes-master01 k8s-yaml]# kubectl exec -it pod-nginx-post-pre -- /bin/sh
# cat /tmp/file
Pod postStart

已经按照要求,在/tmp/file中有内容Pod postStart。

对于preStop的演示,因为容器在关闭之前执行preStop这个函数,容器关闭之后,里面的日志与文件都没了,所以不好演示效果。一般preStop这个钩子函数用于容器在关闭之前需要进行的资源清理工作。

二、配置liveness probe

Kubernetes中使用存活探测器liveness probe来知道什么时候要重启容器。 例如,存活探测器liveness probe可以捕捉到死锁(应用程序在运行,但是无法继续执行后面的步骤)。 这样的情况下重启容器有助于让应用程序在有问题的情况下更可用。

接下来配置一个pod-busy-live.yaml的文件,文件内容如下:

apiVersion: v1
kind: Pod
metadata:
   name: pod-busy-live
spec:
   containers:
   - name: busybox
     image: busybox
     command: ['sh','-c','touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600;']
     livenessProbe:
       exec:
         command: ['cat /tmp/healthy;']
       initialDelaySeconds: 5
       periodSeconds: 5

上面的文件中是busybox的容器,执行的命令如下,起初创建一个文件/tmp/healthy,睡眠30秒后,删除/tmp/healthy,然后睡眠600秒。

['sh','-c','touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600;']

其中的livenessProbe是存活探针,其中的配置的功能如下:

  • command: [‘cat /tmp/healthy;’]:检查是否有文件/tmp/healthy。
  • initialDelaySeconds:第一次探测前,等待的时间,本例子中是5秒。
  • periodSeconds:除了第一次探测外,每次探测的间隔,本例子中是5秒。

创建这个Pod:

[root@kubernetes-master01 k8s-yaml]# kubectl apply -f pod-busy-live.yaml
pod/pod-busy-live created

查看这个Pod的状态:

[root@kubernetes-master01 k8s-yaml]# kubectl get pod
NAME            READY   STATUS    RESTARTS   AGE
pod-busy-live   1/1     Running   0          11s

持续的查看Pod的状态,当过了30秒后,Pod的状态中的RESTARTS字段变为了1,说明Pod重启过了。

[root@kubernetes-master01 k8s-yaml]# kubectl get pod
NAME            READY   STATUS    RESTARTS   AGE
pod-busy-live   1/1     Running   1          54s

通过如下指令,查看Pod中的具体运行情况:

[root@kubernetes-master01 k8s-yaml]# kubectl describe pod pod-busy-live

在输出结果的最下面,显示容器因为liveness probe检测失败,所以重启了。

Events:
  Type     Reason     Age                  From                          Message
  ----     ------     ----                 ----                          -------
  Normal   Scheduled  <unknown>            default-scheduler             Successfully assigned default/pod-busy-live to kubernetes-worker01
  Normal   Pulled     15m (x3 over 17m)    kubelet, kubernetes-worker01  Successfully pulled image "busybox"
  Normal   Created    15m (x3 over 17m)    kubelet, kubernetes-worker01  Created container busybox
  Normal   Started    15m (x3 over 17m)    kubelet, kubernetes-worker01  Started container busybox
  Normal   Killing    14m (x3 over 16m)    kubelet, kubernetes-worker01  Container busybox failed liveness probe, will be restarted
  Normal   Pulling    14m (x4 over 17m)    kubelet, kubernetes-worker01  Pulling image "busybox"
  Warning  Unhealthy  12m (x16 over 17m)   kubelet, kubernetes-worker01  Liveness probe failed: OCI runtime exec failed: exec failed: container_linux.go:367: starting container process caused: exec: "cat /tmp/healthy;": stat cat /tmp/healthy;: no such file or directory: unknown

三、配置readiness probe

Kubernetes使用就绪探测器readiness probe可以知道容器什么时候准备好了并可以开始接受请求流量,例如一个Java应用,是否可以正常的给消费者调用? 这可以用于对慢启动容器进行检测,以使容器满足对外服务的状态了,才提供服务。 当一个 Pod 内的所有容器都准备好了,才能把这个 Pod 看作就绪了。 这种信号的一个用途就是控制哪个 Pod 作为 Service 的后端。 在 Pod 还没有准备好的时候,会从 Service 的负载均衡器中被剔除的。

就绪探针的例子如下,我们一个文件pod-nginx-ready.yaml,内容如下:

apiVersion: v1
kind: Pod
metadata:
   name: pod-nginx
spec:
   containers:
   - name: nginx
     image: nginx
     ports:
     - containerPort: 80
       hostPort: 80
     readinessProbe:
       httpGet:
         path: /
         port: 80

在这个Pod中,我们运行了一个nginx,并启动了就绪检查readiness probe,其中采用的方式是http的检查。

创建这个Pod:

[root@kubernetes-master01 k8s-yaml]# kubectl apply -f pod-nginx-ready.yaml
pod/pod-nginx created

查看Pod的运行状态:

[root@kubernetes-master01 k8s-yaml]# kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
pod-nginx   0/1     Running   0          5s

接下来,我们登陆到Pod中,关闭nginx:

[root@kubernetes-master01 k8s-yaml]# kubectl exec -it pod-nginx -- sh
# nginx -s stop
2021/03/16 08:46:54 [notice] 34#34: signal process started
# command terminated with exit code 137

现在,我们来查看Pod的运行状态,发现RESTARTS为1,容器已经重启了一次:

[root@kubernetes-master01 k8s-yaml]# kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
pod-nginx   1/1     Running   1          96s

容器探针是由Kubernetes容器执行的定期诊断。 要执行诊断,Kubernetes需要调用由容器实现的处理程序,有三种类型的处理程序:

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

每次探测都将获得以下三种结果之一:

  • Success(成功):容器通过了诊断。
  • Failure(失败):容器未通过诊断。
  • Unknown(未知):诊断失败,因此不会采取任何行动。

针对运行中的容器,Kubernetes可以选择是否执行以下三种探针,以及如何针对探测结果作出反应:

  • liveness Probe:指示容器是否正在运行。如果存活态探测失败,则 kubelet 会杀死容器, 并且容器将根据其重启策略决定未来。如果容器不提供存活探针, 则默认状态为 Success。
  • readiness Probe:指示容器是否准备好为请求提供服务。如果就绪态探测失败, 端点控制器将从与 Pod 匹配的所有服务的端点列表中删除该 Pod 的 IP 地址。 初始延迟之前的就绪态的状态值默认为 Failure。 如果容器不提供就绪态探针,则默认状态为 Success。
  • startup Probe: 指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被禁用,直到此探针成功为止。如果启动探测失败,Kubernetes将杀死容器,而容器依其重启策略进行重启。 如果容器没有提供启动探测,则默认状态为 Success。