在Kubernetes
中,Init Container
(初始化容器)是一种特殊类型的容器,它在Pod中的其他容器之前运行。Init Container
用于在主容器启动之前执行一些初始化任务,例如配置文件的下载、数据库的初始化等。
Init Container与普通容器一样,但它们具有以下几个特点:
顺序执行
:在同一个Pod中,所有的Init Container会按照定义的顺序依次执行,只有当前Init Container成功退出(即返回状态码为0)后,下一个Init Container才会开始执行。容器间共享文件系统卷
:Init Container可以与其他容器共享相同的卷(volume),使它们能够访问相同的文件或配置信息。生命周期独立
:Init Container的生命周期与Pod中的其他容器是独立的。它们可以在主容器正在运行时继续执行,也可以在主容器结束后继续执行。新建配置文件:init-container.yaml
apiVersion: v1
kind: Pod
metadata:
name: init-container-pod
spec:
containers:
- name: main-container-nginx
image: nginx:1.7.9
# 主容器的定义
initContainers:
- name: init-container-1
image: busybox:latest
command: ['sh', '-c', 'echo Init Container 1']
# 第一个Init Container的定义
- name: init-container-2
image: busybox:latest
command: ['sh', '-c', 'echo Init Container 2']
# 第二个Init Container的定义
在上面的示例中,我们定义了一个Pod,其中包含一个名为 main-container-nginx
的主容器和两个Init Container:init-container-1
和init-container-2
。它们将按照定义的顺序依次执行。
每个Init Containerk可以使用不同的镜像(这里使用了Busybox
镜像),并通过command字段指定了要执行的命令。在这个示例中,Init Container只是打印一些文本信息。
当Pod启动时,Kubernetes将首先创建并运行init-container-1
,待其成功退出后,再创建并运行init-container-2
。最后,Kubernetes会创建并运行main-container-nginx
。
接着我们操作下看下执行的流程:kubectl create -f init-container.yaml
[root@docker-54 jobs]# kubectl create -f init-container.yaml
pod/init-container-pod created
[root@docker-54 jobs]#
[root@docker-54 jobs]# kubectl get po
NAME READY STATUS RESTARTS AGE
init-container-pod 0/1 Init:0/2 0 6s
[root@docker-54 jobs]#
[root@docker-54 jobs]# kubectl get po
NAME READY STATUS RESTARTS AGE
init-container-pod 0/1 Init:1/2 0 6s
[root@docker-54 jobs]#
[root@docker-54 jobs]# kubectl get po
NAME READY STATUS RESTARTS AGE
init-container-pod 0/1 PodInitializing 0 6s
[root@docker-54 jobs]#
[root@docker-54 jobs]# kubectl get po
NAME READY STATUS RESTARTS AGE
init-container-pod 1/1 Running 0 6s
[root@docker-54 jobs]#
可以看到,Pod 创建成功后,READY
显示 0/1
表示未就绪状态,并且STATUS
显示有两个 Init Container 在初始化,然后等待初始化完成后,容器状态变为 Running;
接着看下描述事件的内容:
[root@docker-54 jobs]# kubectl describe po init-container-pod
Name: init-container-pod
Namespace: default
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 87s default-scheduler Successfully assigned default/init-container-pod to docker-56
Normal Pulling 87s kubelet Pulling image "busybox:latest"
Normal Pulled 48s kubelet Successfully pulled image "busybox:latest" in 39.045941073s
Normal Created 48s kubelet Created container init-container-1
Normal Started 48s kubelet Started container init-container-1
Normal Pulling 47s kubelet Pulling image "busybox:latest"
Normal Pulled 16s kubelet Successfully pulled image "busybox:latest" in 31.46613887s
Normal Created 16s kubelet Created container init-container-2
Normal Started 16s kubelet Started container init-container-2
Normal Pulled 15s kubelet Container image "nginx:1.7.9" already present on machine
Normal Created 15s kubelet Created container main-container-nginx
Normal Started 14s kubelet Started container main-container-nginx
[root@docker-54 jobs]#
可以看到,首先是任务调度到 docker-56
节点上,然后拉取了 "busybox:latest"
的镜像,这里有两个 Init Container
但是用了同一个版本的镜像,却拉取了两次,就有点神奇了。
这是因为当Pod被调度到节点上并开始执行时,Kubernetes
会按顺序为每个Init Container创建一个容器实例。每个容器实例需要从镜像仓库中拉取镜像,以便在节点上运行。
所以,在上面示例中,第一个Init Container(init-container-1
)在开始时拉取了busybox:latest
镜像,然后在成功退出后,第二个Init Container(init-container-2
)也会拉取相同的镜像。这是因为每个Init Container都是独立
的,它们之间没有共享镜像的缓存。
主容器(main-container-nginx
)则是另一个独立的容器,它使用的是不同的镜像(nginx:1.7.9
)。由于该镜像已经存在于节点上,所以在事件信息中显示为Container image "nginx:1.7.9" already present on machine
,表示不需要再次拉取该镜像。
接着看下节点上容器的执行情况:
[root@docker-56 ~]# docker ps -a | grep init
8962da1d4913 84581e99d807 "nginx -g 'daemon of…" 11 minutes ago Up 11 minutes k8s_main-container-nginx_init-container-pod_default_c8984746-7c8e-4724-82da-4bb7376ec560_0
d29abaa670cd busybox "sh -c 'echo Init Co…" 11 minutes ago Exited (0) 11 minutes ago k8s_init-container-2_init-container-pod_default_c8984746-7c8e-4724-82da-4bb7376ec560_0
1cc8c7423c64 busybox "sh -c 'echo Init Co…" 12 minutes ago Exited (0) 12 minutes ago k8s_init-container-1_init-container-pod_default_c8984746-7c8e-4724-82da-4bb7376ec560_0
[root@docker-56 ~]# docker logs -f --tail 20 k8s_init-container-1_init-container-pod_default_c8984746-7c8e-4724-82da-4bb7376ec560_0
Init Container 1
[root@docker-56 ~]#
确实可以看到,这里运行了三个容器,Init Container 执行完成,已经是停止的状态了,并且查看对应 Init Container 的日志,也是可以正常看到的。
使用Init Container可以实现一些初始化任务,确保主容器在启动之前具备所需的条件。例如,可以使用Init Container
来下载配置文件
、初始化数据库
、执行数据迁移
等操作。
需要注意的是,如果Init Container
失败退出(即返回状态码非零),Kubernetes
将会重启整个Pod
,以便重新执行Init Container
和主容器
。因此,在编写Init Container
时,应确保其能够处理错误情况,并保证在正常情况下能够成功退出。