Init Container(Init 容器)
是一种特殊容器,在 Pod 内的应用容器启动之前运行,执行相关的初始化操作。Init 容器可以包括一些应用镜像中不存在的 实用工具
和 安装脚本
。
每个 Pod 中可以包含一个或多个容器, App 应用运行在这些 Container 容器里面,同样 Pod 中的 Init 容器
也可以有一个或多个(先于应用容器启动),用于完成应用容器所需的预置条件,如下图所示:
Init 容器与 应用容器非常像(在本质上是一样的),除了以下特点:
Init Container
都必须在下一个启动之前成功完成才能继续执行。说明:多个 Init 容器 存在的情况,这些 Init 容器 会按先后顺序
线性执行
,并且每个 Init 容器 必须成功完成,下一个 Init 容器 才能执行;而多个应用容器可并行执行
。
依据 Pod 的重启策略(RestartPolicy
),如果 Pod 的 Init 容器失败,并且Pod 设置了 RestartPolicy=Never
时,则 Kubernetes 会将整个 Pod 状态设置为失败。而设置了 RestartPolicy=Always
时,kubelet 会不断地重启该 Init 容器直到该容器成功为止。
讲解了 Init Container 的使用,接下来介绍 Init Container 有哪些应用场景。
在很多的应用场景中,应用在启动之前都需要执行如下初始化操作:
关于这些应用场景的示例,这里不再详述,生产环境中依据自己的实际情况按照示例配置使用即可。
为 Pod 设置 Init Container
需要在 Pod spec 规约
中添加 initContainers
字段, 该字段以 Container 类型对象数组的形式组织,和应用的 containers
数组同级相邻。
Init Container
的状态在 status.initContainerStatuses
字段中以容器状态数组的格式返回 (类似 status.containerStatuses
字段)。
举例:定义一个具有 2 个 Init Container
的简单 Pod。 第一个等待 myservice 启动, 第二个等待 mydb 启动。 一旦这两个 Init Container
都启动完成,Pod 将启动 spec
节中的应用容器。 myapp-pod.yaml
文件定义如下所示:
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app.kubernetes.io/name: MyApp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
执行命令创建上面定义的 Pod:
kubectl apply -f myapp-pod.yaml
pod/myapp-pod created
检查该 Pod 状态信息:
kubectl get -f myapp-pod.yaml
输出信息:
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 6m
查看 Pod 更多详细信息:
kubectl describe -f myapp-pod.yaml
查看 Pod 内 Init 容器的日志:
kubectl logs myapp-pod -c init-myservice # 查看第一个 Init 容器
kubectl logs myapp-pod -c init-mydb # 查看第二个 Init 容器
通过查看 Pod 状态、详细信息或者内部的 Init 容器日志,可以进一步的排查 Pod 异常的原因。
从上面输出的信息中,可以看到 STATUS
的值为 Init:0/2
,说明该 Pod 内有 2 个 Init Container
,并且 Pod 的 READY
为 0/1
未就绪态,原因是由于我们定义的 2 个 Init Container
需要对应的 Service
依赖,接下来我们继续创建对应的 Service
,myapp-pod-initc-svc.yaml
文件定义如下:
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
---
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
执行命令 创建 mydb 和 myservice 服务:
kubectl create -f myapp-pod-initc-svc.yaml
输出信息:
service "myservice" created
service "mydb" created
然后我们再次查看 Pod 状态信息:
kubectl get -f myapp-pod.yaml
输出信息:
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 9m
看到 Pod 的 STATUS
的值为 Running
并且 READY
为 1/1
,此时说明该 Pod 创建成功,就绪态可提供服务了。
以 Init:
开头的 Pod 状态汇总了 Init 容器
执行的状态。 下表介绍调试 Init 容器时可能看到的一些状态值示例。
状态 | 含义 |
---|---|
Init:N/M | Pod 包含 M 个 Init 容器,其中 N 个已经运行完成。 |
Init:Error | Init 容器已执行失败。 |
Init:CrashLoopBackOff | Init 容器执行总是失败。 |
Pending | Pod 还没有开始执行 Init 容器。 |
PodInitializing or Running | Pod 已经完成执行 Init 容器。 |
以 Nginx 为例,在启动 Nginx 之前,通过初始化容器 busybox 为 Nginx 创建一个 index.html 主页文件。
说明:
此处 init container 和 Nginx 设置了一个共享的 Volume,提供 Nginx 访问 init container 设置的 index.html 文件。
nginx-initc.yaml
文件定义如下:
apiVersion: v1
kind: Pod
metadata:
name: myNginx
labels:
app.kubernetes.io/name: myNginx
spec:
initContainers:
- name: init-install
image: busybox:1.34.1
command:
- wget
- "-O"
- "/workdir/index.html"
- http://kubernetes.io
volumeMounts:
- mountPath: "/workdir"
name: workdir
containers:
- name: myNginx-container
image: nginx:1.23.1-alpine
ports:
- containerPort: 80
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: workdir
dnsPolicy: Default
volumes:
- name: workdir
emptyDir: {}
创建 nginx-initc.yaml
文件定义的 Pod:
kubectl create -f nginx-initc.yaml
输出信息:
pod "myNginx" created
查看 Pod 信息:
kubectl get pods
查看 Pod 详细信息:
kubectl describe pod myNginx
启动成功后,登录 Nginx 容器,可以看到 /usr/share/nginx/html
目录下的 index.html
文件为 init container 所生成,其内容为(如下伪代码)Kubernetes 的官网首页:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kubernetestitle>
head>
<body>
<H1>Production-Grade Container OrchestrationH1>
<script src="/js/xxx.js">script>
body>
html>
Init 容器
支持应用容器的全部字段和特性,包括资源限制、数据卷和安全设置。 然而,Init 容器对资源请求和限制的处理稍有不同,在下面资源节有说明。
同时 Init 容器
不支持 lifecycle、livenessProbe、readinessProbe
和 startupProbe
, 因为它们必须在 Pod 就绪之前运行完成。
如果为一个 Pod 指定了多个 Init 容器,这些容器会 按顺序逐个运行
。 每个 Init 容器必须运行成功,下一个才能够运行。当所有的 Init 容器运行完成时, Kubernetes 才会为 Pod 初始化应用容器并像平常一样运行。
Init Container 与 普通应用容器他们之间的区别总结如下:
(1) init container 的 运行方式
与 应用容器不同,它们必须先于应用容器执行完成,当 Pod 设置了多个 init container
时,将按顺序逐个运行(线性执行),并且只有前一个 init container 运行成功才能运行后一个 init container。当所有 init container 都成功运行后,Kubernetes 才会初始化 Pod 的各种信息,并开始创建和运行应用容器。
(2) 在 init container 的定义中也可以设置资源限制、Volume 的使用和 安全策略 等等。但 资源限制
的设置与应用容器略有不同。
如果多个 init container 都定义了资源请求/资源限制,则取最大的值作为所有 init container 的资源请求值/资源限制值。
Pod 的有效(effective) 资源请求值/资源限制值取以下二者中的较大值。
a) 所有应用容器的资源请求值/资源限制值之和。
b) init container 的有效资源请求值/资源限制值。
调度算法将基于 Pod 的有效资源请求值/资源限制值进行计算,也就是说 init container 可以为初始化操作预留系统资源,即使后续应用容器无须使用这些资源,Pod 的有效 Qos(Quality of Service,服务等级) 等级适用于 init container 和应用容器。
资源配额和限制将根据 Pod 的有效资源请求值/资源限制值计算生效。
Pod 级别的 cgroup 将基于 Pod 的有效资源请求/限制,与调度机制一致。
(3) init container 不能设置 readinessProbe
探针,因为必须在它们成功运行后才能继续运行在 Pod 中定义的普通容器。
在Pod重新启动时,init container 将会重新运行,常见的 Pod 重启场景如下:
init container
的镜像被更新时,init container 将会重新运行,导致 Pod重启。仅更新应用容器的镜像只会使得应用容器被重启。infrastructure
容器更新时,Pod 将会重启。RestartPolicv=Alwavs
时,则 Pod 会重启。关于Pod 的其他属性配置,如上面的【Pod 生命周期】图中的更多信息请查看: