k8s五Pod生命周期
Posted 攻城狮白玉
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了k8s五Pod生命周期相关的知识,希望对你有一定的参考价值。
目录
前言
前面我们部署了k8s容器环境,也知道了怎么书写数据自己的Pod,那本节我们就一起来学习Pod的生命周期。这个是重点来的哦,因为在实际运用的过程中,对于Pod生命周期每个阶段的进行检测,进而分析和排错。
Pod生命周期
上图主要描述了在容器环境初始化完成之后,pod从创建到退出,中间这段时间经历的过程;
从大的方向上看,pod生命周期分两个阶段:
- 第一阶段是初始化容器。
- 第二阶段是主容器的整个生命周期;
在 Pod 启动时,pause容器总是创建的第一个容器。每个pod中都存在一个pause容器。这个是k8s自动创建的。
对于Init Container来说,一个pod中可以定义多个初始化容器,他们必须是串行执行,只有当所有的初始化容器执行完后,对应的主容器才会启动;如上图所示,会按顺序把1、2、3的InitC都执行完成之后,才进入Main Container阶段
Main Container生命周期又分为三个阶段:
- 第一阶段是运行post start hook,这个阶段是主容器运行之后立即需要做的事;
- 第二阶段是主容器正常运行的阶段,在这个阶段中,我们可以定义对容器的健康状态(liveness)检查和就绪状态(readness)检查;
- 第三阶段是运行pre stop hook,这个阶段主要做容器即将退出前需要做的事;
readness——就绪检测,检测成功后,Pod状态改为Ready
liveness——生存检测,
对于对容器的健康状态检查和就绪状态检查,我们也可以定义开始检查的延迟时长;因为有些容器存在容器显示running状态,但内部程序还没有初始化,如果立即做健康状态检查,可能存在健康状态为不健康,从而导致容器重启的状况;
Pod 相位 状态值
首先在介绍 Pod 的生命周期之前,我们先了解下 Pod 的状态,因为 Pod 状态可以反映出当前我们的 Pod 的具体状态信息,也是我们分析排错的一个必备的方式。
我们可以通过命令kubectl explain pod.status
查看到
挂起(Pending)
Pod已被K8s系统接受,但有一个或者多个容器镜像尚未创建,等待时间包括调度Pod的时间和通过网络下载镜像的时间。这可能需要花点时间。
运行中(Running)
该Pod已经绑定到了一个节点上,Pod中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或者重启状态。
成功(Succeeded)
Pod中所有的容器都被成功终止并且不会再重启。
失败(Failed)
Pod中所有容器都已经终止,并且至少有一个容器是因为失败终止。也就是说,至少有一个容器以非0状态退出或者被系统终止。
未知(Unknown)
因为某些原因无法取得Pod的状态,通常是因为与Pod所在主机通信失败。
Init Containers
Init Containers是在Pod的主容器启动之前要运行的容器,主要是做一些主容器的前置工作。
一个Pod能够具有多个容器,应用运行在应用容器里面,但是该Pod中可能有一个或多个先于应用容器启动的Init容器。
Init容器与普通容器非常像,除了以下两点:
- Init容器总是运行到成功完成为止,如果某个初始化容器运行失败,那么kubernetes需要重启它直至成功完成。
- Init容器必须按照定义的顺序执行,每个Init容器都必须在下一个Init容器启动之前成功完成
注意:如果Pod的Init容器失败,Kubernetes会不断重启该Pod,知道Init容器成功位置。然而,如果Pod对应的重启策略restartPolicy为Never时,Pod不会重新启动。
Init Contianers的作用
因为Init容器具有与应用程序容器分离的单独镜像,所以它们的启动相关代码具有如下优势:
- 他们可以包含并运行实用工具,但是出于安全考虑,时不建议在应用程序容器镜像中包含这些实用工具的。
- 特们可以包含实用工具和定制化代码来安装,但是不能出现在应用程序镜像中。例如,创建镜像没必要FROM另一个镜像,只需要在安装过程中使用类似sed、awk、python、dig这样的工具
- 应用程序镜像可以分离出创建和部署的角色,而没有必要联合他们构建一个单独的镜像。
- Init容器使用Linux Namespace,所以相对应用程序容器来说,具有不同的文件系统视图。因此,他们能够具有访问Secret的权限,而应用程序容器则不能。实现分权限来治理。例如,有一个文件夹里面只有一个文件是main容器要用到的,但是又不希望main容器有这个文件夹的访问权限,于是通过init容器来访问该文件,并且把该文件复制到main容器中。
- 他们必须在应用程序容器启动之前运行完成,而应用程序容器时并行运行的,所以,Init容器能够提供一种简单的阻塞或延迟应用容器启动的方法,直到满足了一系列应用容器启动的先决条件。例如我们有两个容器,一个放数据库,一个放应用服务,服务要在数据库启动之后启动,访问才不会报错,那么此时我们可以在应用服务容器的init containers中设置一个条件,用于检测数据库容器是否完成启动,如果数据库完成启动了,则应用服务容器可以正常启动。如下图所示:
Init Contianers实验
下面我们通过实际例子来进一步认识init containers。
# init-pod.yaml
# author: 攻城狮白玉
apiVersion: v1
kind: Pod
metadata:
name: baiyu-pod
namespace: baiyu-learn-k8s
labels:
app: baiyu-app
version: v1
spec:
containers:
- name: baiyu-app-container
image: busybox:1.32
command: ['sh', '-c', 'echo The app is running && sleep 3600']
initContainers:
- name: init-baiyu-service
image: busybox:1.32
command: ['sh', '-c','until nslookup baiyu-service; do echo waiting for baiyu-service; sleep 2;done;']
- name: init-baiyu-db
image: busybox:1.32
command: ['sh', '-c', 'until nslookup baiyu-db; do echo waiting for baiyu-db; sleep 2; done;']
上面的yaml,运行了一个pod。里面有一个main container,有两个init container
kubectl create -f init-pod.yaml
然后执行kubectl get pod -n baiyu-learn-k8s -o wide -w
查看容器状态
此时无论多久,上面这个容器都不会变成running状态的。这是因为我们写了两个init container的条件没有满足。
第一个init container里面,我们执行了下面这句命令,表示在我们能解析到有这个baiyu-service
名称的网络服务就打破循环。
until nslookup baiyu-service;
do
echo waiting for baiyu-service;
sleep 2;
done;
此处补充个小知识点,便是Linux中until的用法。
until跟while类似,都是一个固定循环。
但是until跟while又有不同,则是它们的条件满足不同。
until是直到条件为真时,打破循环。而while是条件为真时一直循环,条件为假时打破循环。
此时,我们通过命令
kubectl logs baiyu-pod -n baiyu-learn-k8s --container init-baiyu-service
查看pod中的init-baiyu-service容器的日志,可以发现它一直在循环检测服务是否起来
为了满足我们init-pod中的init container的条件,我们准备了以下脚本实现两个service,用于满足init C的条件。
# init-service.yaml
# author: 攻城狮白玉
kind: Service
apiVersion: v1
metadata:
name: baiyu-service
namespace: baiyu-learn-k8s
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
---
kind: Service
apiVersion: v1
metadata:
name: baiyu-db
namespace: baiyu-learn-k8s
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
执行命令启动脚本kubectl apply -f init-service.yaml
使用kubectl get pod -n baiyu-learn-k8s -o wide -w
查看我们的pod的状态。结果如下图所示,在两个init容器执行完成之后,main 容器进行执行,最终Pod完成启动Pod状态变为Running
特殊说明
- 在Pod启动过程中,Init容器会按顺序在网络和数据卷初始化(网络和数据卷初始化是在pause中启动的)之后启动。每个容器必须在下一个容器启动之前成功退出。
- 如果由于运行时或失败退出,将导致容器启动失败,它会根据Pod的restartPolicy指定的策略进行重试。然而,如果Pod的
restartPolicy
设置为Always
,Init容器失败时会使用RestartPolicy策略 - 在所有的Init容器没有成功之前,Pod将不会变成
Ready
状态。Init容器的端口将不会再Service中进行聚集。正在初始化中的Pod处于Pending
状态,但应该会将Initializing
状态设置为true - 如果Pod重启,所有Init容器必须重新执行。
- 对于Init容器spec的修改被限制在容器image字段,修改其他字段都不会生效。更改Init容器的image字段等价于重启该Pod。
- Init容器具有应用容器的所有字段,除了
readinessProbe
,因为Init容器无法定义不同于完成(completion)的就绪(readiness)之外的其他状态。这会在验证过程中强制执行。 - 在Pod中的每个app和Init容器的名称必须要唯一;与任何其他容器共享同一个名称,会在验证时抛出错误。
- Init容器执行的效果应该是幂等的。
总结
本文介绍了k8s整体容器的生命周期以及Init Container的基本概念和作用,并通过一个实战例子进一步加深了各位同学对init Containers的理解。限于篇幅,并没有把容器的生命周期所有知识点写完,下一篇我会介绍容器生命周期的两个探针,readness和liveness。以及启停时的动作钩子
写在后面
如果觉得有用的话,麻烦一键三连支持一下攻城狮白玉,并把本文分享给更多的小伙伴。你的简单支持,我的无限创作动力
以上是关于k8s五Pod生命周期的主要内容,如果未能解决你的问题,请参考以下文章