pod的生命周期--init C

目录

Init 容器

Init 容器的作用

Init 容器的模板

总结


问题描述:

比如说,我们运行一个pod,pod里面运行的有两个容器,如果这两个容器它们还在,但是它们里面运行的进程已经死亡了或者说意外中断了,由于某种故障,容器也并没有退出,造成这个pod还处于running状态,这个时候服务已经不可用了,因为进程都已经死了。但是对于整个pod来说,pod还是可以用的,这个时候就出现问题了。这个就引出我们的检测机制了,当然如果了解到k8s的知道,多用的检测机制是liveness和readness,我们的init C其实也可以作为检测的一个方向。

注意:下图中只有一个mainC,其实我们的pod里面可以运行多个主容器,这里的主容器其实就是我们所说的应用。。

init C -----> init Container

初始化容器的含义:

比如说,我们去运行一个pod,里面运行着两个不同的容器,这两个容器运行的前提条件是在本集的存储下面有一个什么什么的文件存在,它们才能正常的运行,这个时候我们就可以通过init C去生成这个文件,注意,这个文件一旦生成的话,即它完成了自己的任务,init C就会死亡,并不会跟随pod一直存在下去。我们的init C可有可与,可以有多个存在,如果有多个init C 的存在,那么必须是前面的init C完成自己的任务之后,才轮到下面的init C开始工作构建,即无法并行构建。

上面初始化工作完成之后,就到了我们的main C(主容器)开始工作,主容器也可以有多个,即我们的pod里面放多个容器服务。在主容器开始工作的时候,先会进行一个START操作,结束的时候会进行STOP操作,即在主容器运行之前,我们可以先执行一个指令(START操作),容器退出的之前也可以执行一个指令(STOP)。当然我们还有一个readiness和liveness检测机制来保证我们的pod里面的服务是可以正常对外提供的,这个后期会讲到。

下面就是我们的容器或者说pod的生命周期流程:

首先我们的kubectl向我们的API接口kubeapi发送指令以后,kubeapi会调度到我们的kublet,调度的过程由etcd存储完成的,kubelet去操作我们对应的CRI,CRI去完成我们的容器初始化,在初始化的过程中会先去启动一个pause的基础容器,它是负责我们的网络和存储卷共享的,接着它要进行一个init C的初始化(这个init C可以是多个,也可以没有),多个初始化完成之后,就可以进行到我们的main C(主容器),主容器在刚运行的时候可以允许它去启动一条命令,或执行一个脚本。主容器结束的时候也可以让它去执行一个stop命令,在这个过程中会有readiness和liveness的参与。只有当readiness或者liveness检测之后,这个检测可以有时间限制,在主容器运行多少时间之后才开始检测,检测成功之后,我们的pod才处于running或者readying状态,才能对外提供服务。

Init 容器

Pod 能够具有多个容器,应用运行在容器里面,但是它也可能有一个或多个先于应用容器启动的Init容器。(像我们上图中mainC启动之前还有多个initC)

Init 容器与普通的容器非常像,除了如下两点:

  1. Init 容器总是运行到成功完成为止(也就是说init C不正常退出的话,无法启动main C,并且pod也是需要对应的流程,比如说,重启,一直到init C正常初始化成功和退出)
  2. 每个 Init 容器都必须在下一个 Init 容器启动之前成功完成(这个对于多个的init C)

如果 Pod 的 Init 容器失败, Kubernetes 会不断地重启该 Pod ,直到 Init 容器成功为止。然而,如果 Pod 对应的 restartPolicy 为 Never(永不重启,但是一般我们默认的是always,总是重启) ,它不会重新启动。

Init 容器的作用

因为 Init 容器具有与应用程序容器分离的单独镜像,所以它们的启动相关代码具有如下优势:

1. 它们可以包含并运行实用工具,但是出于安全考虑,是不建议在应用程序容器镜像中包含这

些实用工具的。(也就是说,若我们需要提前在主容器启动之前,我们需要有一些文件被创建,有一些数据被梳理,但是梳理这些数据或者文件的工具呢,加载到我们的main C之后,又会造成我们的main C冗余,因为这些工具不会一直被用的到。随着我们的工具越来越多,main C的稳定性就得不到保障。这个时候我们可以把工具写入到init C,让它在初始化的过程中提前把我们main C用到的数据或者文件准备好)

2. 它们可以包含使用工具和定制化代码来安装,但是不能出现在应用程序镜像中。例如,创建

镜像没必要 FROM 另一个镜像,只需要在安装过程中使用类似 sed 、 awk 、 python 或 dig

这样的工具。

3. 应用程序镜像可以分离出创建和部署的角色,而没有必要联合它们构建一个单独的镜像。

假如在我们主容器运行的时候,它可能需要有一部分把这个代码构建出来,一部分运行这个代码,有这么两套流程,第一套走完之后,才能进行第二套,第二套是一个持续的过程,即运行代码。那么这个时候我们就可以把第一套抽离成我们的init C。

4. Init 容器使用 Linux Namespace ,所以相对应用程序容器来说具有不同的文件系统视图。因

此,它们能够具有访问 Secret 的权限,而应用程序容器则不能。

假如说我们有一个文件目录,假如这个文件目录里面的某个文件是我们main C后期要调用的,但是这个文件目录我们的main C没有权限访问到,若我们main C有访问权限的话,那么main C后期就可以调用这个目录里面的所有文件,这样安全性肯定出现隐患的。这种情况下,我们可以把权限赋予给我们的init C,让init C获取到这个文件之后,写入到main C,因为init C 任务完成之后就退出了。

5. 它们必须在应用程序容器启动之前运行完成,而应用程序容器是并行运行的,所以 Init 容

器能够提供了一种简单的阻塞或延迟应用容器的启动的方法,直到满足了一组先决条件。

下面演示一下init容器的应用案例

Init 容器的模板

[root@master1 test]# cat init-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod      #这个pod的名字
  labels:               #标签
    app: myapp
spec:                    #详细的描述信息
  containers:             #容器
  - name: myapp-container   #第一个容器的名字
    image: busybox
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:         #初始化容器
  - name: init-myservice      #第一个初始化容器的名字
    image: busybox
    command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2;done;']
  - name: init-mydb           #第二个初始化容器的名字
    image: busybox
    command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
[root@master1 test]# 

分析:上面的是定义了两个不同的init 容器

  1. 第一个init C:until表示条件为真的时候退出循环
  2. 第二个init C:检测mydb这样的一个域名,如果域名解析成功就退出循环,如果没有解析成功,就输出“waiting for mydb”,然后等待2秒,再循环。

第一个init C先初始化,再到第二个。

上面的yaml文件创建好之后,容器并不能成功,因为我们的init C还有完成任务

[root@master1 test]# kubectl get pod 
NAME        READY   STATUS     RESTARTS   AGE
myapp-pod   0/1     Init:0/2   0          86s
[root@master1 test]# 

我们可以通过logs命令查看容器为啥起不来,因为上面的测试pod里面跑了三个容器,我们可以通过-c参数指定看哪个容器的log

此时我们得创建init C对应的任务来唤醒对应的init C,以至于它们可以完成自己的任务,然后正常退出,这样我们的主容器才能处于running状态。

[root@master1 test]# cat init-svc.yaml 
kind: Service
apiVersion: v1
metadata:
  name: myservice
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
---
kind: Service
apiVersion: v1
metadata:
  name: mydb
spec: 
  ports: 
  - protocol: TCP
    port: 80 
    targetPort: 9377
[root@master1 test]# 

 经过比较长的时间等待,我们的init C 完成自己的任务之后,main C就起来了

[root@master1 test]# kubectl get pod 
NAME        READY   STATUS    RESTARTS   AGE
myapp-pod   1/1     Running   0          7m56s
[root@master1 test]# 
[root@master1 test]# kubectl get svc 
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.1.0.1      <none>        443/TCP   37m
mydb         ClusterIP   10.1.208.32   <none>        80/TCP    6m45s
myservice    ClusterIP   10.1.144.48   <none>        80/TCP    6m45s

总结

  1. 在 Pod 启动过程中, Init 容器会按顺序在网络和数据卷初始化(在pause中完成的)之后启动。每个容器必须在下一个容器启动之前成功退出。
  2. 如果由于运行时或失败退出,将导致容器启动失败,它会根据 Pod 的 restartPolicy 指定的策略进行重试。然而,如果 Pod 的 restartPolicy 设置为 Always , Init 容器失败时会使用RestartPolicy 策略。
  3. 在所有的 Init 容器没有成功之前, Pod 将不会变成 Ready 状态。 Init 容器的端口将不会在Service 中进行聚集。 正在初始化中的 Pod 处于 Pending 状态,但应该会将 Initializing 状态设置为 true。
  4. 如果   Pod  重启,所有 Init 容器必须重新执行。
  5. 对 Init 容器 spec 的修改被限制在容器 image 字段,修改其他字段都不会生效。更改 Init容器的 image 字段,等价于重启该 Pod。(kubectl edit pod xxxx)
  6. Init 容器具有应用容器的所有字段。除了 readinessProbe ,即我们的init C没有就绪和生存检测机制,因为 Init 容器无法定义不同于完成( completion )的就绪( readiness)之外的其他状态。这会在验证过程中强制执行.
  7. 在 Pod 中的每个 app 和 Init 容器的名称必须唯一;与任何其它容器共享同一个名称,会在验证时抛出错误

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值