Kubernetes的Pod中进行容器初始化
在很多应用场景中,应用在启动之前都需要进行如下初始化操作:
-
等待其他关联组件正确运行(例如数据库或某个后台服务)。
-
基于环境变量或配置模板生成配置文件。
-
从远程数据库获取本地所需配置,或者将自身注册到某个中央数据库中。
-
下载相关依赖包,或者对系统进行一些预配置操作。
Kubernetes 1.3 引入了一个 Alpha 版本的新特性 init container (初始化容器,在 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文件。
配置文件 033-nginx-init-containers.yaml
的内容为:
apiVersion: v1
kind: Pod
metadata:
name: nginx
annotations:
name: nginx
spec:
# These containers are run during pod initialization
initContainers:
- name: install
image: busybox
command:
- wget
- "-O"
- "/work-dir/index.html"
- http://www.baidu.com
volumeMounts:
- name: workdir
mountPath: "/work-dir"
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: workdir
mountPath: /usr/share/nginx/html
dnsPolicy: Default
volumes:
- name: workdir
emptyDir: {}
创建这个 Pod:
[root@master cha3]# kubectl create -f 033-nginx-init-containers.yaml
pod/nginx created
在运行 init container 的过程中查看 Pod 的状态,可见 init 过程还未完成:
[root@master cha3]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx 0/1 Init:0/1 0 11s
在 init container 成功执行完成后,系统继续启动 Nginx 容器,再次查看 Pod 的状态:
[root@master cha3]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 43s
查看 Pod 的事件,可以看到系统首先创建并运行 init container 容器(名为install),成功后继续创建和运行 Nginx
容器:
[root@master cha3]# kubectl describe pod nginx
Name: nginx
Namespace: default
Priority: 0
Node: slave2/192.168.226.202
Start Time: Mon, 10 Jul 2023 20:11:18 +0800
Labels: <none>
Annotations: name: nginx
Status: Running
IP: 10.244.140.65
IPs:
IP: 10.244.140.65
Init Containers:
install:
Container ID: docker://fed219a6b5bd09f383cfbc353a80cf0a718888f581d7cd15d1d967a65ffa25d5
Image: busybox
Image ID: docker-pullable://busybox@sha256:5acba83a746c7608ed544dc1533b87c737a0b0fb730301639a0179f9344b1678
Port: <none>
Host Port: <none>
Command:
wget
-O
/work-dir/index.html
http://www.baidu.com
State: Terminated
Reason: Completed
Exit Code: 0
Started: Mon, 10 Jul 2023 20:11:36 +0800
Finished: Mon, 10 Jul 2023 20:11:36 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-ml45m (ro)
/work-dir from workdir (rw)
Containers:
nginx:
Container ID: docker://65d365a441cfed5dc5bcf2baba7d7bf3744bf28a6973d16698a079425d03d450
Image: nginx
Image ID: docker-pullable://nginx@sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Mon, 10 Jul 2023 20:11:53 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/usr/share/nginx/html from workdir (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-ml45m (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
workdir:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
Medium:
SizeLimit: <unset>
kube-api-access-ml45m:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 55s default-scheduler Successfully assigned default/nginx to slave2
Normal Pulling 54s kubelet Pulling image "busybox"
Normal Pulled 38s kubelet Successfully pulled image "busybox" in 16.36286751s
Normal Created 37s kubelet Created container install
Normal Started 37s kubelet Started container install
Normal Pulling 37s kubelet Pulling image "nginx"
Normal Pulled 21s kubelet Successfully pulled image "nginx" in 16.261974272s
Normal Created 21s kubelet Created container nginx
Normal Started 20s kubelet Started container nginx
启动成功后,登录进 Nginx 容器,可以看到 /usr/share/nginx/html
目录下的 index.html
文件为 init
container所生成,其内容为:
[root@master cha3]# kubectl exec -ti nginx -- bash
Defaulted container "nginx" out of: nginx, install (init)
root@nginx:/# cd /usr/share/nginx/html/
root@nginx:/usr/share/nginx/html# ls
index.html
root@nginx:/usr/share/nginx/html# cat index.html
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn"></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>©2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必读</a> <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a> 京ICP证030173号 <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
root@nginx:/usr/share/nginx/html# exit
exit
init container 与应用容器的区别如下:
(1)init container 的运行方式与应用容器不同,它们必须先于应用容器执行完成,当设置了多个 init container
时,将按顺序逐个运行,并且只有前一个 init container 运行成功后才能运行后一个 init container。当所有 init
container 都成功运行后,Kubernetes 才会初始化 Pod 的各种信息,并开始创建和运行应用容器。
(2)在 init container 的定义中也可以设置资源限制、Volume 的使用和安全策略,等等。但资源限制的设置与
应用容器略有不同。
-
如果多个 init container 都定义了资源请求/资源限制,则取最大的值作为所有 init container 的资源请求值/资
源限制值。
-
Pod 的有效资源请求值/资源限制值取以下二者中的较大值。
1、所有应用容器的资源请求值/资源限制值之和。
2、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 会重启。