一、容器的初始化 init

image-20240427095919673

⭐️ init c : init contariner 初始化容器,只是用来初始化,初始化完成就会死亡可以大于的等于一也可以没有,每个init只有在前一个 init c执行完成后才可以执行下一个、init容器总是运行到成功完成为止,如果 init运行失败 k8s就会不断的重启该 Pod,直到init容器成功为止,但是如果 Pod对应的 restartPolicyNerver,它就不会重启。

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

  • 它们可以包含并运行实用工具,但是出于安全考虑,是不建议在应用程序容器镜像中包含这些实用工具的
  • 它们可 以包含使用工具和定制化代码来安装,但是不能出现在应用程序镜像中。例如,创建镜像没必要FROM 另-一个镜像,只需要在安装过程中使用类似 sedawkpythondig这样的工具。
  • 应用程序镜像可以分离出创建和部署的角色,而没有必要联合它们构建-一个 单独的镜像。
  • Init 容器使用 Linux Namespace,所以相对应用程序容器来说具有不同的文件系统视图。因此,它们能够具有访问Secret 的权限,而应用程序容器则不能。
  • 它们必须在应用程序容器启动之前运行完成,而应用程序容器是并行运行的,所以 Init 容器能够提供了一种简单的阻塞或延迟应用容器的启动的方法,直到满足了一组先决条件。

二、主容器

  • Main C : 主容器
  • readiness: 就绪检测,他会去判断容器能不能正常提供给外网访问,
  • Liveiness:生存检测

image-20240427100658636

容器运行时接口

⭐️ 每种容器运行时各有所长,许多用户都希望 Kubernetes支持更多的运行时。在Kubernetes 1.5发布版里,我们引入了 CRI–一个能让 kubelet无需编译就可以支持多种容器运行时的插件接口。CRI包含了一组 protocol buffersgRPC API,相关的库,以及在活跃开发下的额外规范和工具。

protocol buffers API包含了两个 gRPC服务:ImageServiceRuntimeServiceImageService提供了从镜像仓库拉取、查看、和移除镜像 RPCRuntimeSerivce包含了Pods和容器生命周期管理的 RPC,以及跟容器交互的调用(exec/attach/port-forward)。一个单块的容器运行时能够管理镜像和容器(例如:DockerRkt),并且通过同一个套接字同时提供这两种服务。这个套接字可以在 Kubelet里通过标识 –container-runtime-endpoint和–image-service-endpoint进行设置。

Pending(悬决) Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间,
Running(运行中) Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。
Succeeded(成功) Pod 中的所有容器都已成功终止,并且不会再重启。
Failed(失败) Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。
Unknown(未知) 因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。

三、init实验

1️⃣我们来通过一个 yaml模板定义一个Pod在定义两个 init,init操作是:

这个init容器的command是一个shell脚本,它执行以下操作:

  1. 使用 nslookup命令检查 testservicetestdb这两个服务是否可用。
  2. 如果 testservicetestdb服务不可用,它会输出"waiting for myservice",然后等待2秒后再次尝试检查。
  3. 这个过程会一直重复,直到 testservicetestdb服务都变得可用为止。
  4. Pod内可以直接使用 Service的名字进行访问
[root@master ~]# cat pod/init.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: test
  labels:
    version: v1
    app: test-app
spec:
  containers:
   - name: mytest
     image: busybox
     command: ['sh','-c','echo runing && sleep 6000']
  initContainers:
   - name: init-service
     image: busybox
     imagePullPolicy: ifNotPresent
     command: ['sh','-c','until nslookup testservice; do echo waiting for myservice; sleep 2; done;']
   - name: init-db
     image: busybox
     imagePullPolicy: ifNotPresent
     command: ['sh','-c','until nslookup testdb; do echo waiting for myservice; sleep 2; donel;']

上文的镜像是虽然没有带后缀但是默认就是latest,k8s中只要镜像后缀是latest就会从远程仓库拉去,可以设置

imagePullPolicy有三种策略

Always:总是从远程仓库拉去

Nerver: 仅使用本地镜像

IfNotPresent: 如果本地有就用,没有就从外部拉去

2️⃣使用编写号的 yaml文档创建 pod,此时 pod正在等待 init容器初始化完成

[root@master ~]# kubectl create -f pod/init.yaml 
pod/test created

[root@master ~]# kubectl get pod
NAME                     READY   STATUS     RESTARTS   AGE
nginx-6b48575596-bsdt2   1/1     Running    1          42h
nginx-6b48575596-fbdjf   1/1     Running    1          42h
nginx-6b48575596-wzmdp   1/1     Running    1          42h
test                     0/1     Init:0/2   0          8s
website                  1/1     Running    0          17h

3️⃣ 要使得 init容器初始化完成,就需要我们来创建两个个 Service ,让 pod可以解析到,这里先创建第一个

[root@master ~]# cat pod/service.yaml 
apiVersion: v1
kind: Service
metadata:
  name: testservice
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9999

4️⃣ 创建好后如果init还没未启动就可以为容器配置域名解析信息

可以使用下面这条命令来修改pod的设置

kubectl edit pod [podname]   

**打开后我们可以看见**
dnsPolicy: ClusterFirst 
  • Default“:从节点继承 DNS相关配置,对节点依赖性强。
  • ClusterFirst“:如果 DNS查询与配置好的默认集群域名前缀不匹配,则将查询请求转发到从节点继承而来,作为查询的上游服务器。默认则是这个
  • ClusterFirstWithHostNet“:如果pod工作在主机网络,就将 dnsPolicy设置成“ClusterFirstWithHostNet”,这样效率更高。
  • None“:1.9版本引入的新特性(Beta in v1.10)。完全忽略 kubernetes系统提供的 DNS,以 pod SpecdnsConfig配置取而代之。

当然也可以直接改 DNSspec中加入

 dnsPolicy: "None"
  dnsConfig:
    nameservers:
      - 1.2.3.4

5️⃣ 此时我们在查看就会发现 init容器已经准备好一个了

[root@master ~]# kubectl get pod
NAME   READY   STATUS     RESTARTS   AGE
test   0/1     Init:1/2   0          29m
[root@master ~]# kubectl get svc
NAME          TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes    ClusterIP   10.96.0.1    <none>        443/TCP   2d18h
testservice   ClusterIP   10.98.62.1   <none>        80/TCP    53m

6️⃣ 运行第二个service

[root@master ~]# cat pod/service2.yaml 
apiVersion: v1
kind: Service
metadata:
  name: testdb
spec:
  ports:
   - protocol: TCP
     port: 3366
     targetPort: 9998

[root@master ~]# kubectl get svc
NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
kubernetes    ClusterIP   10.96.0.1       <none>        443/TCP    2d18h
testdb        ClusterIP   10.97.182.149   <none>        3366/TCP   7s
testservice   ClusterIP   10.98.62.1      <none>        80/TCP     55m

可以看见pod变running了

[root@master ~]# kubectl get pod
NAME   READY   STATUS    RESTARTS   AGE
test   1/1     Running   0          57m


⭐️ 特殊说明

  • 在Pod启动过程中,Init 容器会按顺序在网络和数据卷初始化之后启动(pause)。每个容器必须在下-一个容器启动之前成功退出,也就是说 init容器不是先被启动的先被启动的是 pause容器
  • 如果由于运行时或失败退出,将导致容器启动失败,它会根据Pod的 restartPolicy 指定的策略进行重试。然而,如果Pod的 restartPolicy 设置为 Always, Init 容器失败时会使用 RestartPolicy策略 可以看上一章笔记
  • 在所有的 Init 容器没有成功之前,Pod 将不会变成 Ready状态。Init容器的端口将不会在 Service中进行聚集。正在初始化中的 Pod处于 Pending 状态,但应该会将 Initializing 状态设置为 true ,ps:就是说你的 mian container 或者i nit container 都没有完成,那么他们的端口和 ip地址将不会出现在 service
  • 如果 Pod重启,所有 Init 容器必须重新执行
  • #对
    
    Init容器 spec 的修改被限制在容器 image 字段,修改其他字段都不会生效。更改 Init容器的 image 字段,等价于重启该 Pod ps:
  • Init 容器具有应用容器的所有字段。除了 readinessProbe, 因为 Init 容器无法定义不同于完成(completion)的就绪(readiness) 之外的其他状态。这会在验证过程中强制执行,ps:也就是说container下面写入的字段,initcontainer下面也可以写
  • 在Pod 中的每个 appInit容器的名称必须唯一-; 与任何其它容器共享同一个名称,会在验证时抛出错误.