深入掌握Pod
- 10、Init Container(初始化容器)
10、Init Container(初始化容器)
在很多应用场景中,应用在启动之前都需要进行如下初始化操作。
- 等待其他关联组件正确运行(例如数据库或某个后台服务)。
- 基于环境变量或配置模板生成配置文件。
- 从远程数据库获取本地所需配置,或者将自身注册到某个中央数据库中。
- 下载相关依赖包,或者对系统进行一些预配置操作。
Kubernetes 1.3引入了一个Alpha版本的新特性initcontainer(初始化容器,在Kubernetes 1.5时被更新为 Beta版本),用于在启动应用容器(app container)之前启动一个或多个初始化容器,完成应用容器所需的预置条件,如图所示。init container与应用容器在本质上是一样的,但它们是仅运行一次就结束的任务,并且必须在成功执行完成后,系统才能继续执行下一个容器。根据Pod的重启策略(RestartPolicy),当init container执行失败,而且设置了RestartPolicy=Never时,Pod将会启动失败;而设置RestartPolicy=Always时,Pod将会被系统自动重启。
下面以Nginx应用为例,在启动Nginx之前,通过初始化容器busybox为Nginx创建一个index.html主页文件。这里为init container和Nginx设置了一个共享的Volume,以供Nginx访问init container设置的index.html文件:
apiVersion:v1kind:Podmetadata:name:nginxannotations:{}spec:# 初始化容器(initContainers):在主容器启动前运行,用来做准备工作initContainers:-name:installimage:busyboxcommand:-wget-"-O"-"/work-dir/index.html"-http://kubernetes.io# 使用 wget 下载网页并保存到共享目录的 index.html 中volumeMounts:-name:workdirmountPath:"/work-dir"# 将共享卷挂载到初始化容器的 /work-dir 目录# 主容器(containers):提供核心服务containers:-name:nginximage:nginxports:-containerPort:80# 暴露容器的 80 端口volumeMounts:-name:workdirmountPath:/usr/share/nginx/html# 将同一个共享卷挂载到 Nginx 的网页根目录,这样 Nginx 就能直接访问初始化容器下载的页面dnsPolicy:Defaultvolumes:-name:workdiremptyDir:{}# 定义一个生命周期与 Pod 相同的临时共享存储卷(emptyDir),供初始化容器和主容器共享数据创建这个Pod:
# kubectl create -f nginx-init-containers.yamlpod"nginx"created在运行init container的过程中查看Pod的状态,可见init过程还未完成:
# kubectl get podsNAME READY STATUS RESTARTS AGE nginx0/1 Init:0/101m在init container成功执行完成后,系统继续启动Nginx容器,再次查看Pod的状态:
# kubectl get podsNAME READY STATUS RESTARTS AGE nginx1/1 Running07s查看Pod的事件,可以看到系统首先创建并运行initcontainer容器(名为install),成功后继续创建和运行Nginx容器:
# kubectl describe pod nginxName: nginx Namespace: default......(略) Events: FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 3s 3s1default-scheduler Normal Scheduled Successfully assigned init-demo to k8s-node-1 3s 3s1kubelet, k8s-node-1 spec.initContainers{install}Normal Pulled Container image"busybox"already present on machine 3s 3s1kubelet, k8s-node-1 spec.initContainers{install}Normal Created Created container withid93d98cbc0251c60d43c2d8d0a6a9bb65f432344fe6f04561c4a940b79bcff74a 3s 3s1kubelet, k8s-node-1 spec.initContainers{install}Normal Started Started container withid93d98cbc0251c60d43c2d8d0a6a9bb65f432344fe6f04561c4a940b79bcff74a 2s 2s1kubelet, k8s-node-1 spec.containers{nginx}Normal Pulled Container image"nginx"already present on machine 2s 2s1kubelet, k8s-node-1 spec.containers{nginx}Normal Created Created container withida388bbb9f1fe247cf42e61449328ab20f7c54a7c271590548d3d8610a28a6048 1s 1s1kubelet, k8s-node-1 spec.containers{nginx}Normal Started Started container withida388bbb9f1fe247cf42e61449328ab20f7c54a7c271590548d3d8610a28a6048启动成功后,登录进Nginx容器,可以看到/usr/share/nginx/html目录下的index.html文件为initcontainer所生成,其内容为:
<htmlid="home"lang="en"class=""><head>......<title>Kubernetes | Production-Grade Container Orchestration</title>...... "url": "http://kubernetes.io/"}</script></head><body>......init container与应用容器的区别如下。
- (1)init container的运行方式与应用容器不同,它们必须先于应用容器执行完成,当设置了多个init container时,将按顺序逐个运行,并且只有前一个init container运行成功后才能运行后一个init container。当所有initcontainer都成功运行后,Kubernetes才会初始化Pod的各种信息,并开始创建和运行应用容器。
- (2)在init container的定义中也可以设置资源限制、Volume的使用和安全策略,等等。但资源限制的设置与应用容器略有不同。
- 如果多个init container都定义了资源请求/资源限 制,则取最大的值作为所有init container的资源请求值/资源限制值。
- Pod的有效(effective)资源请求值/资源限制值取以下二者中的较大值。a)所有应用容器的资源请求值/资源限制值之和。b)init container的有效资源请求值/资源限制值。
- 调度算法将基于Pod的有效资源请求值/资源限制值进行计算,也就是说init container可以为初始化操作预留系统资源,即使后续应用容器无须使用这些资源。
- Pod的有效QoS等级适用于init container和应用容器。
- 资源配额和限制将根据Pod的有效资源请求值/资源限制值计算生效。
- Pod级别的cgroup将基于Pod的有效资源请求/限制,与调度机制一致。
- (3)init container不能设置readinessProbe探针,因为必须在它们成功运行后才能继续运行在Pod中定义的普通容器。
在Pod重新启动时,init container将会重新运行,常见的Pod重启场景如下。
- init container的镜像被更新时,init container将会重新运行,导致Pod重启。仅更新应用容器的镜像只会使得应用容器被重启。
- Pod的infrastructure容器更新时,Pod将会重启。
- 若Pod中的所有应用容器都终止了,并且RestartPolicy=Always,则Pod会重启。