Pod与Init容器
什么是 Init 容器
Pod 可以包含多个容器,应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。
如果为一个 Pod 指定了多个 Init 容器,这些 Init 容器会按顺序逐个运行。每个 Init 容器都必须运行成功,下一个才能够运行。当所有的 Init 容器运行完成时,Kubernetes 才会为 Pod 初始化应用容器并像平常一样运行。
Init容器与普通的容器非常像,除了以下两点:
-
Init容器总是运行到成功完成且正常退出为止。
-
只有前一个Init容器成功完成并正常退出,才能运行下一个Init容器。
如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启 Pod,直到 Init 容器成功为止。但如果 Pod 对应的 restartPolicy 为 Never,则不会重新启动。
Init 容器的作用
因为 Init 容器是与应用容器分离的单独镜像,其启动相关代码具有如下优势:
-
Init 容器可以包含一些安装过程中应用容器不存在的实用工具或个性化代码。例如,在安装过程中要使用类似 sed、 awk、 python 或 dig 这样的工具,那么放到Init容器去安装这些工具;再例如,应用容器需要一些必要的目录或者配置文件甚至涉及敏感信息,那么放到Init容器去执行。而不是在主容器执行。
-
Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。
-
应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。
-
Init 容器能以不同于Pod内应用容器的文件系统视图运行。因此,Init容器可具有访问 Secrets 的权限,而应用容器不能够访问。
-
由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。一旦前置条件满足,Pod内的所有的应用容器会并行启动。
Init 容器的行为
在 Pod 启动过程中,Init 容器会按顺序在网络和数据卷初始化之后启动。每个容器必须在下一个容器启动之前成功退出。如果由于运行时或失败退出,将导致容器启动失败,它会根据 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 容器可能会被重启、重试或者重新执行,所以 Init 容器的代码应该是幂等的。特别地当写到 EmptyDirs 文件中的代码,应该对输出文件可能已经存在做好准备。
Init 容器具有应用容器的所有字段。除了 readinessProbe,因为 Init 容器无法定义不同于完成(completion)的就绪(readiness)之外的其他状态。这会在验证过程中强制执行。
在 Pod 上使用 activeDeadlineSeconds,在容器上使用 livenessProbe,这样能够避免 Init 容器一直失败。 这就为 Init 容器活跃设置了一个期限。
在 Pod 中的每个 app 和 Init 容器的名称必须唯一;与任何其它容器共享同一个名称,会在验证时抛出错误。
Init 容器使用示例
下面的例子定义了一个具有 2 个 Init 容器的简单 Pod。 第一个等待 myservice 启动,第二个等待 mydb 启动。 一旦这两个 Init容器都启动完成,Pod 将启动spec区域中的应用容器。
init_C_pod.yaml
apiVersion: v1 kind: Pod metadata: name: myapp-busybox-pod labels: app: myapp spec: containers: - name: myapp-container image: registry.cn-beijing.aliyuncs.com/google_registry/busybox:1.24 command: ['sh', '-c', 'echo The app is running! && sleep 3600'] initContainers: - name: init-myservice image: registry.cn-beijing.aliyuncs.com/google_registry/busybox:1.24 command: ['sh', '-c', "until nslookup myservice; do echo waiting for myservice; sleep 60; done"] - name: init-mydb image: registry.cn-beijing.aliyuncs.com/google_registry/busybox:1.24 command: ['sh', '-c', "until nslookup mydb; do echo waiting for mydb; sleep 60; done"]
# 启动这个 Pod,并检查其状态 [root@k8s-master k8s-workspace]# kubectl apply -f init_C_pod.yaml pod/myapp-busybox-pod created [root@k8s-master k8s-workspace]# kubectl get pod myapp-busybox-pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-busybox-pod 0/1 Init:0/2 0 3m24s 10.233.123.25 k8s-node02 <none> <none> [root@k8s-master k8s-workspace]# kubectl describe pod myapp-busybox-pod Name: myapp-busybox-pod Namespace: default [...] Status: Pending [...] Init Containers: init-myservice: [...] State: Running Started: Thu, 10 Nov 2022 23:06:22 +0800 Ready: False [...] init-mydb: [...] State: Waiting Reason: PodInitializing Ready: False [...] Containers: myapp-container: [...] State: Waiting Reason: PodInitializing Ready: False [...] Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 3m48s default-scheduler Successfully assigned default/myapp-busybox-pod to k8s-node02 Normal Pulling 3m47s kubelet Pulling image "registry.cn-beijing.aliyuncs.com/google_registry/busybox:1.24" Normal Pulled 3m46s kubelet Successfully pulled image "registry.cn-beijing.aliyuncs.com/google_registry/busybox:1.24" in 1.410659444s Normal Created 3m46s kubelet Created container init-myservice Normal Started 3m46s kubelet Started container init-myservice # 查看 Pod 内 Init 容器的日志 [root@k8s-master ~]# kubectl logs -f --tail 500 myapp-busybox-pod -c init-myservice nslookup: can't resolve 'myservice' Server: 169.254.25.10 Address 1: 169.254.25.10 ... ... [root@k8s-master ~]# kubectl logs -f --tail 500 myapp-busybox-pod -c init-db error: container init-db is not valid for pod myapp-busybox-pod
此时Init 容器将会等待直至发现名称为mydb和myservice的 Service。
init_C_service.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@k8s-master k8s-workspace]# kubectl apply -f init_C_service.yaml service/myservice created service/mydb created # 查看pod状态和service状态,能看到这些 Init容器执行完毕后,随后myapp-busybox-pod的Pod转移进入 Running 状态 [root@k8s-master k8s-workspace]# kubectl get svc -o wide mydb myservice NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR mydb ClusterIP 10.233.9.54 <none> 80/TCP 74s <none> myservice ClusterIP 10.233.34.185 <none> 80/TCP 3m12s <none> [root@k8s-master k8s-workspace]# kubectl get pod myapp-busybox-pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-busybox-pod 1/1 Running 0 34m 10.233.123.25 k8s-node02 <none> <none>
由上可知:一旦我们启动了 mydb 和 myservice 这两个 Service,我们就能够看到 Init 容器完成,并且 myapp-busybox-pod 被创建。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)