Pod 可以包含多个容器,应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。
Init Container 是一种特殊容器,顾名思义是用来做初始化工作的容器,可以是一个或者多个,如果有多个的话,这些容器会按定义的顺序依次执行,只有所有的Init Container执行完后,主容器才会被启动。
我们知道一个Pod里面的所有容器是共享数据卷和网络命名空间的,所以Init Container里面产生的数据可以被主容器使用到的。Init Container与应用容器本质上是一样的,除了以下两点:
如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止。如果 Pod 对应的 restartPolicy 为 Never,它不会重新启动。
Pod 的生命周期:
从上面这张图我们可以直观的看到 Init Container 是独立于主容器之外的,但他们都属于Pod的生命周期。
应用容器定义在 Pod.Spec.Containers,是必填字段,而 init 是定义在 Pod.Spec.initContainers 中,是可选字段。
下面的例子定义了一个具有 2 个 Init 容器的简单 Pod。第一个等待 myservice 启动, 第二个等待 mydb 启动。一旦这两个 Init 容器都启动完成,Pod 将启动 spec 节中的应用容器。
myapp.yaml:
apiVersion: v1kind: Podmetadata: name: myapp-pod labels: app.kubernetes.io/name: MyAppspec: 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"]
创建:
[root@localhost ~]# kubectl apply -f myapp.yamlpod/myapp-pod created
查看状态:
[root@localhost ~]# kubectl get -f myapp.yaml NAME READY STATUS RESTARTS AGEmyapp-pod 0/1 Init:0/2 0 8s
输出详细信息:
[root@localhost ~]# kubectl describe -f myapp.yaml Name: myapp-podNamespace: default[...]Labels: app.kubernetes.io/name=MyAppAnnotations: <none>Status: Pending[...]Init Containers: init-myservice:[...] State: Running[...] 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 20s default-scheduler Successfully assigned default/myapp-pod to localhost.localdomain Normal Pulling 17s kubelet Pulling image "busybox:1.28" Normal Pulled 8s kubelet Successfully pulled image "busybox:1.28" in 9.30472043s Normal Created 7s kubelet Created container init-myservice Normal Started 6s kubelet Started container init-myservice
查看 Pod 内 Init 容器的日志:
[root@localhost ~]# kubectl logs myapp-pod -c init-myservice # 查看第一个 Init 容器nslookup: can't resolve 'myservice.default.svc.cluster.local'Server: 10.96.0.10Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local waiting for myservice [root@localhost ~]# kubectl logs myapp-pod -c init-mydb # 查看第二个 Init 容器Error from server (BadRequest): container "init-mydb" in pod "myapp-pod" is waiting to start: PodInitializing
此时,init-mydb容器会等待 init-myservice 执行完成后再执行。如下为创建这些 Service 的配置文件:services.yaml:
---apiVersion: v1kind: Servicemetadata: name: myservicespec: ports: - protocol: TCP port: 80 targetPort: 9376---apiVersion: v1kind: Servicemetadata: name: mydbspec: ports: - protocol: TCP port: 80 targetPort: 9377
创建:
[root@localhost ~]# kubectl apply -f services.yamlservice/myservice createdservice/mydb created
再次查看状态:变成 了 Running:
[root@localhost ~]# kubectl get podNAME READY STATUS RESTARTS AGEmyapp-pod 1/1 Running 0 2m35s
此时再次查看详细信息,发现两个 init-myservice 和 init-mydb 已经 Terminated 了:
Init Containers: init-myservice:[...] State: Terminated Reason: Completed Exit Code: 0[...] init-mydb:[...] State: Terminated Reason: Completed Exit Code: 0
随着Kubernetes发布了1.28,支持了不少重磅特性,其中最令人感慨的莫过于新的Sidecar,目前是alpha版本。之前Sidecar的称谓只是一种多容器的设计模式,在K8s看来和普通容器没什么不一样。但由于其生命周期与业务容器并不一致,对于Sidecar的生命周期管理一直是个问题。
新版本的Sidecar是放置在initContainers中,指定restartPolicy为Always便开启Sidecar,其生命周期以及重启管理与普通容器也是一样的,此特性也可用于运行 Job 。
下面是一个带有Sidecar的Deployment示例,log Sidecar容器用来输出日志到终端,main容器模拟写入日志: sidecar.yaml:
apiVersion: apps/v1kind: Deploymentmetadata: name: myapp labels: app: myappspec: replicas: 1 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: myapp image: alpine:latest command: ['sh', '-c', 'while true; do echo "logging" >> /opt/logs.txt; sleep 1; done'] volumeMounts: - name: data mountPath: /opt initContainers: - name: logshipper # sidecar 容器 image: alpine:latest restartPolicy: Always # 必须指定restartPolicy为Always才能开启sidecar command: ['sh', '-c', 'tail -f /opt/logs.txt'] volumeMounts: - name: data mountPath: /opt volumes: - name: data emptyDir: {}
部署到K8s集群中,可以看到initContainers[*].restartPolicy字段:
[root@localhost ~]# kubectl create -f sidecar.yamldeployment.apps/myapp created [root@localhost ~]# kubectl get po -l app=myapp -ojsonpath='{.items[0].spec.initContainers[0].restartPolicy}'Always [root@localhost ~]# kubectl get po -l app=myapp NAME READY STATUS RESTARTS AGEmyapp-215h3248d-p4z6 2/2 Running 0 1m5s
myapp Pod中两个容器都是Ready(2/2),查看日志可以看到log Sidecar一直在输出日志。
[root@localhost ~]# kubectl logs -l app=myapp -c logshipper -flogginglogging
本文链接:http://www.28at.com/showinfo-26-16635-0.html如何在Kubernetes中使用Init Container
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
上一篇: 18 个非常有用的网站,有一天你会用上它