首发于 Kubernetes

Pod生命周期

1,概述

我们一般将pod对象从创建至终的这段时间范围内称为pod生命周期,它主要包含下面过程:
pod创建过程
运行初始化容器过程(init container)
运行主容器过程(main container)
容器启动钩子(post start),容器终止前钩子(pre stop)(这两个钩子的作用就是,如果你想让容器启动之后做一些事情,你可以传递一些参数或者命令给容器启动钩子这个节点,当然如果你想在终止之前执行一些命令,你可以传递一些参数和一些命令给终止前这个节点)
容器的存活性探测(liveness probe),就绪性探测(readliness probe)(这两个作用就是子过程)
pod终止过程

在整个生命周期终,pod会出现5种状态(相位),分别如下:
挂起:apiserver已经创建了pod资源对象,但它尚未被调度完成或者仍处于下载镜像的过程中
运行中:pod已经被调度至某节点,并且所有容器都已经被kubectkl创建完成
成功:pod中所有的容器都已经成功终止并且不会被重启
失败: 所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非0值的退出状态
未知: apiserver无法正常获取到pod对象的状态信息,通常由网络通信失败所导致。

2,创建和终止

1)用户通过kubectl或其他api客户端提交所需要创建的pod信息给server。
2)apiserver开始生成pod对象的信息,并将信息存入etcd,然后返回确认信息至客户端。
3)apiServer开始反映etcd中的pod对象变化,其它组件使用watch机制来跟踪检查apiServer上的变动。
4)scheduler发现有新的pod对象要创建,开始为pod分配主机并将结果信息更新至apiServer。
5)node节点上的kubectl发现有pod调度过来,尝试调用docker启动容器,并将结果回送至apiServer。
6)apiServer将接收到的pod状态信息存入etcd中。

pod的终止过程
1)用户向apiServer发送删除pod对象的命令
2)apiServer中的pod对象信息会随着时间的推移而更新,在宽限期内(默认30s),pod被视为dead
3)将pod标记为terminating状态
4)kubelet在监控到pod对象转为terminating状态的同时启动pod关闭过程
5)端点控制器监控到pod对象的关闭行为时将其从所有匹配到此端点的service资源的端点列表中移除
6)如果当前pod对象定义了preStop钩子处理器,则在其标记为terminating后即会以同步的方式启动执行
7)pod对象中的容器进程受到停止信号
8)宽限期结束后,若pod中还存在仍在运行的进程,那么pod对象会收到立即终止的信号。
9)kubelet请求apiServer将此pod资源的宽限期设置为0从而完成删除操作,此时pod对于用户已不可见。

3,初始化容器

初始化容器是在pod的主容器启动之前要运行的容器,主要是做一些主容器的前置工作,它具有两大特征:
1)初始化容器必须运行完成直至结束,若某初始化容器运行失败,那么kubernetes需要重启它直到成功完成。
2)初始化容器必须按照定义的顺序执行,当且仅当前一个成功之后,后面的一个才能运行。

初始化容器有很多的应用场景,下面列出的是最常见的几个:
1)提供主容器镜像中不具备的工具程序或自定义代码。
2)初始化容器要先于应用容器串行启动并运行完成,因此可用于延后应用容器的启动直至其依赖的条件得到满足。

接下来做一个案例,模拟下面这个需求:
假设要以主容器来运行nginx,但是要求在运行nginx之前先要能够连接上mysql和redis所在的服务器
为了简化测试,事先规定好mysql和redis服务器的地址

创建pod-initcontainer.yaml

我们看下面那个initContainers和containers是同一级的,格式和containers有点像,这就是初始化的容器

我们创建一下然后查看一下

我们发现这个过程是初始化1个初始化2个然后初始化完成,然后主容器运行成功

4,钩子函数

钩子函数能够感知自身生命周期中的事件,并在相应的时刻到来时运行用户指定的程序代码。
kubernetes在主容器的启动之后和停止之前提供了两个钩子函数:
post start:容器创建之后执行,如果失败了会重启容器
pre stop:容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作
钩子处理器支持使用下面三种方式定义动作:
Exec命令:在容器内执行一次命令
..........
lifecycle:
postStart:
exec:
command:
- cat
- /tmp/healthy
..........

TCPSocket:在当前容器尝试访问指定的socket
..........
lifecycle:
postStart:
tcpSocket:
port:8080
..........

HTTPGet:在当前容器中向某url发起http请求
..........
lifecycle:
postStart:
httpGet:
path: / #URI地址
port:80 #端口
host:192.168.109.100
scheme: HTTP #支持的协议,http或者https
..........

接下来,以exec方式为例,演示下钩子函数的使用,创建pod-hook-exec.yaml文件,内容如下

创建pod

访问端口,看下内容变没

已经变化

5,容器探测

容器探测用于检测容器中的应用实例是否正常工作,是保障业务可用性的一种传统机制。如果经过探测,实例的状态不符合预期,那么kubernetes就会把该问题实例摘除,不承担业务流量。kubernetes提供了两种探针来实现容器探测,分别是:

liveness probes:存活性探针,用于检测应用实例当前是否处于正常运行状态,如果不是,k8s会重启容器。
readliness probes:就绪性探针,用于检测应用实例当前是否可以接收请求,如果不能,k8s不会转发流量

livenessProbe 决定是否重启容器,readlinessProbe决定是否将请求转发给容器。

上面两种探针目前均支持三种探测方式:
Exec命令:在容器内执行一次命令,如果命令执行的退出码为0,则认为程序正常,否则不正常
.........
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
..........

TCPSocket:将会尝试访问一个用户容器的端口,如果能够建立这条连接,则认为程序正常,否则不正常

.........
livenessProbe:
tcpSocket:
port: 8080
.........

HTTPGet:调用Web应用的URL,如果返回的状态码在200到399之间,则认为程序正常,否则不正常
.........
livenessProbe:
httpGet:
path: / #URl地址
port: 80 端口号
host: 127.0.0.1 #主机地址
scheme:HTTP#支持的协议,http或者https
..........

下面以liveness Probes为例,做几个演示:

方式一:Exec
创建pod-liveness-exec.yaml

然后我们创建一下试试

我们知道,并没有hello.txt这个文件,所以在最后我们看到了,它重启了一次,我们用describe命令看下详细信息

kubectl describe pod pod-liveness-exec -n dev

可能会有同学说,为什么不能找个正面的例子呢,我们把yaml文件中的内容给改一下

然后我们创建一下,再看看它是否重启

我们发现并没有重启

我们用下describe命令看下是否探测成功

我们发现里面并没有任何的反应

方式二:TCPSocket

创建pod-liveness-tcpScoker.yaml

注意,我这里是8080端口并不是80端口,所以肯定不能成功,这个时候我们看下会不会重启

已经出现重启现象了,然后我们用describe命令查看一下有没有详细信息

我们看最后一行出现了,访问失败正在重启

当然,如果你想让他访问成功,直接在yaml文件里面修改端口即可

方式三:HTTPGet

创建pod-liveness-httpget.yaml

这个方式的本质就是请求一个url路径,如果能访问成功,那么就正常创建

我们这里的nginx里面是没有hello这个路径的,那么是不是会出现问题,出现问题是不是会尝试重启,我们看一下是否有重启现象

我们创建,然后看下是否有重启现象

出现了重启现象,我们再用describe命令查看一下里面有没有探测失败的信息

出现了404,如果你想改正确,那么你就将yaml文件里面的路径书写正确即可,这里就不再演示

至此,已经使用了liveness Probe演示了三种探测方式,但是查看livenessProbe的子属性,会发现除了这三种方式,还有一些其他的配置,在这里一并解释一下:

这里我简短的进行一下解释

exec <object>
tcpSocket <Object>
httpGet<Object>
initialDelaySeconds <integer> 容器启动后等待多少秒执行第一次探测
timeoutSeconds <integer> 探测超时事件。默认1秒,最小1秒
periodSeconds <integer> 执行探测的频率,默认是10秒,最小1秒
failureThreshold <integer> 连续探测失败多少次才被认定为失败。默认是3,最小值是1
successThreshold <integer> 连续探测成功多少次才被认定成功。默认是1

6,重启策略

在上一节中,一旦容器探测出现了问题,kubernetes就会对容器所在的pod进行重启,其实这是由pod的重启策略决定的,pod的重启策略分三种,反别如下:
Always:容器失效时,自动重启该容器,这也是默认值
OnFaliure:容器终止运行且退出码不为0时重启
Never: 不论状态为什么,都重启该容器

重启策略适用于pod对象中的所有容器,首次需要重启的容器,将在其需要时进行立即重启,随后再次需要重启的操作将由kubelet延迟一段时间后进行,且反复的重启操作的延迟时长以此为10s,20s,40s,80s,160s和300s,300s是最大延迟时长。

创建pod-restartpolicy.yaml

我们知道这个nginx的url是不存在的,这时我运行的化会进行重启,一旦进行重启,那么就会执行我的策略,不重启,我们创建一下试试

都35秒了,上面显示的状态是completed状态,ready为0,配置完成的状态,并没有进行重启,我们用describe命令查看一下什么情况

我们看到,没有找到连接那个url出现了错误,然后下面出现了停止重启这个日志,那么这就告诉我们当前的策略生效了


码字不易,还望点个赞点个关注多多支持一下!后续会继续更新关于kubernetes有关的内容,我们一起加油!

编辑于 2022-07-23 15:52

文章被以下专栏收录