kubenetes Pod生命周期详解 之 initC

发布于:2025-03-13 ⋅ 阅读:(19) ⋅ 点赞:(0)

1.生命周期

就是Pod从创建到销毁的一个过程

initc就是下载容器镜像和配置网络栈的过程,你想 容器都没下载玩,后续怎么运行?

initC 是初始化容器 而且是线性执行 1 执行完了 并且 状态码返回 0 成功了 才能执行2 

因为持续时间短,所以危险系数高的操作一般放里面

initC具有阻塞特性 比如 他可以等待某个 initC 执行成功 之前 一直阻塞,直到那个initC 执行完成 ,他才开始执行它的初始化。比如Java 进程 为一个 Pod  ,Mysql一个 Pod Java进程必须要等待MysqlPod初始化完毕了,才能启动,要不然启动没有数据库会报错的!!!

initC 状态结束 即将进入 MainC 

主容器 更像是 守护进程 一样的  不间断的持续运行 

initC 更像我们所谓的脚本类型 它是有退出时机的

mainC 也可以定义很多

mainC 可以并行运行同时存在

在创建容器的过程中它是并发执行的 ,

mainC 是理论上 设计上是允许共同执行的

当然在一些老的 kubenetes 版本里 ,镜像的下载的动作是线性执行的 就导致一个结果,我们看起来好像这一个pod的mainC,好像是线性执行的,其实是并行的,在新版的 kubenetes 的测试实验性里已经调整了一个实验状态,允许镜像的并发执行,能够达到真正的创建mainC的并行,Ok这个概念别搞混了

2.mainC

1.特性有哪些

  1. 钩子
  2. 探针

当前的每一个mainC里呢有两种类型 

  1. 启动后 
  2. 关闭前

每一个mainC 都有对应它的初始化

初始化完成后执行我们对应的启动命令

1.钩子 

钩子可以钩在启动后 和 关闭前

启动后

但是它是在初始化之后 执行的 命令 官方命名叫做启动后钩子,但是实际是在初始化之后 启动命令执行之前

钩子没有执行完成的时候 启动命令就开始执行了

官方话:我们并不能保证启动命令的执行的时候,启动后钩子已经完毕了

关闭前

关闭前钩子 关闭信号的执行

学Docker的 时候 关闭容器的时候 发送15号信号 如果发送15号信号多次以后没有被关闭 那就会发送9级别信号 强制杀死

所以我们关停我们的pod的时候也是想这些容器发送对应的关闭信号的,这是毋庸置疑的

如果我们里面运行了很重要的一些服务 服务产生很多的数据,我没有及时的把数据保存 就杀死pod 容易造成数据的丢失在这里

关闭前钩子可以处理这个问题

只有在关闭前钩子执行结束后 ,关闭信号才会释放发送给我们的容器

这两个钩子的执行机制是由谁完成的、

答案是 pod所在节点的 kubelet 

2.探针

比如 古代的皇帝用银针试毒 就是一种典型的探针的例子 

mainC容器里 kubernetes 也为我们提供了像探针一样的功能

1.就绪探测

就绪探测一般都会在mainC 启动后延迟一段时间才运行 

就是为了检查所有的 mainC是否都就绪

当就绪探测发送之后 返回都是就绪了 

那么当前这个容器就会标记为可访问状态,当所有的mainC都标记就绪了,那这样的pod才允许通过负载均衡提供给用户去访问 ,但凡当前的任何一个pod 没有标记为就绪 这样的pod 我们是都不允许通过负载均衡提供给用户访问的 所以这就是就绪探测的意义

在kubernetes老版本里:就绪探测并不是伴随着整个容器的生命周期的 也就意味着它可能在探测完成以后就会结束 

新版本就变成整体的都在就绪探测

经过n段时间 如果容器达不到就绪状态了 它依然会标记为未就绪

2.存活探测

检测 容器是否还存活

 判断容器是否还有可用性 可以访问

不可访问就会杀死容器 重建容器去恢复

要保证存活探测的时机不能太前也不能太后  太前会造成程序还没启动就被杀死 太后检测不出中间有哪些报错的地方

所以官方为了解决这个问题提供了 启动探测

3.启动探测

就绪探测和存活探测都会在启动探测之后才开始执行计数

探测的是我们的应用程序是否启动完成

这些钩子和探针是程序员可以根据自己不同的需求去 用的

这些依然是通过当前pod节点的kubelet去进行执行动作的

3.initC

4.小实验

1.检测initC的阻塞性

创建文件起名为 3.pod.yaml

apiVersion: v1
kind: Pod
metadata:
 name: initc-1
 labels:
   app: initc
spec:
 containers:
   - name: myapp-container
     image: wangyanglinux/tools:busybox
     command: ['sh', '-c', 'echo The app is running! && sleep 3600']
 initContainers:
   - name: init-myservice
     image: wangyanglinux/tools:busybox
     command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
   - name: init-mydb
     image: wangyanglinux/tools:busybox
     command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']

让initContainers 阻塞 直到我们创建myservice对象 和 mydb对象

 kubectl create -f 3.pod.yaml

并没有创建 initdb 还在被第一个 阻塞呢  再一次验证了 initC是一个线性的过程

1.创建 service

官方给了很多别名机制 

 service : svc

deploy : deploy

pod : po 

kubectl create svc clusterip myservice --tcp=80:80
kubectl create svc clusterip mydb --tcp=80:80

向集群外暴露一个端口,能访问到集群内部服务

kubectl get svc

2. 用golang语言 去改变initC 的执行结束的返回码

编译成可执行文件 通过dockerfile 封装成镜像 

package main
import (
 "flag"
 "fmt"
 "math/rand"
 "os"
 "time"
)
func main() {
 sleepTime := flag.Int("sleeptime", 4, "休眠时间")
 exitcode := flag.Int("exitcode", 2, "返回码")
 flag.Parse()
 sleeptimeDing := *sleepTime
 // 处理休眠逻辑
 for *sleepTime >= 0 {
 time.Sleep(time.Second * 1)
 *sleepTime--
 }
 // 产生随机返回码
 // exitcode 值为 0, 返回码为 0
 // exitcode 值为 1,返回码为 1
 // 否则随机产生返回码
 if *exitcode == 0 {
 fmt.Printf("休眠 %v 秒,返回码为 %v!\n", sleeptimeDing, 0)
 os.Exit(0)
 } else  if *exitcode == 1 {
 fmt.Printf("休眠 %v 秒,返回码为 %v!\n",sleeptimeDing, 1)
 os.Exit(1)
 } else {
 rand.Seed(time.Now().UnixNano())
 num := rand.Intn(100)
 if num >= 50 {
 fmt.Printf("休眠 %v 秒,产生的随机数为 %v,大于等于 50 ,返回码为 %v!
\n",sleeptimeDing , num, 1)
 os.Exit(1)
 } else {
 fmt.Printf("休眠 %v 秒,产生的随机数为 %v,小于等于 50 ,返回码为 %v!
\n",sleeptimeDing , num, 0)
 os.Exit(0)
 }
 }
}
FROM alpine
ADD ./randexit /root
RUN chmod +x /root/randexit
CMD ["--sleeptime=5"]  
ENTRYPOINT ["/root/randexit"]

4.pod.yaml 

apiVersion: v1
kind: Pod
metadata:
 name: myapp-pod
 labels:
   app: myapp
spec:
 containers:
   - name: myapp
     image: wangyanglinux/myapp:v1.0
 initContainers:
   - name: randexit
     image: wangyanglinux/tools:randexitv1
     args: ["--exitcode=1"]
kubectl create -f 4.pod.yaml

 

3.创建 5.pod.yaml

apiVersion: v1
kind: Pod
metadata:
 name: myapp-pod-0
 labels:
  app: myapp
spec:
 containers:
   - name: myapp
     image: wangyanglinux/myapp:v1.0
 initContainers:
   - name: randexit
     image: wangyanglinux/tools:randexitv1
     args: ["--exitcode=0"]

 这回状态码返回0 看看能不能成功创建

 总结

从这里我们可以验证 必须要返回码 为 0 才可以正常结束 initC 才能进入 mainC的过程

必须线性启动 返回码必须为0