kubernetes之初始容器(init container)

系列目录html

理解初始容器

一个pod里能够运行多个容器,它也能够运行一个或者多个初始容器,初始容器先于应用容器运行,除了如下两点外,初始容器和普通容器没有什么两样:python

  • 它们老是run to completionlinux

  • 一个初始容器必须成功运行另外一个才能运行git

若是pod中的一个初始容器运行失败,则kubernetes会尝试重启pod直到初始容器成功运行,若是pod的重启策略设置为从不(never),则不会重启.docker

建立容器时,在podspec里添加initContainers字段,则指定容器即为初始容器,它们的返回状态做为数组保存在.status.initContainerStatuses里(与普通容器状态存储字段.status.containerStatuses相似)shell

初始容器和普通容器的不一样:

初始容器支持全部普通容器的特征,包括资源配额限制和存储卷以及安全设置.可是对资源申请和限制处理初始容器略有不一样,下面会介绍.此外,初始容器不支持可用性探针(readiness probe),由于它在ready以前必须run to completionapi

若是在一个pod里指定了多个初始容器,则它们会依次启动起来(pod内的普通容器并行启动),而且只有上一个成功下一个才能启动.当全部的初始容器都启动了,kubernetes才开始启普通应用容器.数组

初始容器能作什么

因为初始容器和普通应用容器是分开的镜像,所以他在作一些初始化工做颇有优点:安全

  • 它们能够包含而且运行一些出于安全考虑不适合和应用放在一块的小工具.bash

  • 它们能够一些小工具和自定义代码来作些初始化工做,这样就不须要在普通应用容器里使用sed,awk,python或者dig来作初始化工做了

  • 应用构建者和发布者能够独立工做,而没必要再联合起来处理同一个pod

  • 它们使用linux namespaces所以它们和普通应用pod拥有不一样的文件系统视图.所以他们能够被赋予普通应用容器获取不到的secrets

  • 它们在应用容器启动前运行,所以它们能够阻止或者延缓普通应用容器的初始化直到须要的条件知足

示例:

  • 经过执行shell命令来等待一个服务建立完成,命令以下:
for i in {1..100}; do sleep 1; if dig myservice; then exit 0; fi; done; exit 1
  • 经过downward API把当前pod注册到远程服务器,命令以下:
curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register -d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'
  • 在容器启动以前等待必定时间:例如sleep 60

  • 克隆一个git仓库到存储目录

  • 经过模板工具动态把一些值写入到主应用程序的配置文件里.

更多详细示例请查看pod应用环境布置指南

初始容器使用

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox
    command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
  - name: init-mydb
    image: busybox
    command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']

以上pod定义包含两个初始容器,第一个等待myservice服务可用,第二个等待mydb服务可用,这两个pod执行完成,应用容器开始执行.

下面是myservicemydb两个服务的yaml文件

kind: Service
apiVersion: v1
metadata:
  name: myservice
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376
---
kind: Service
apiVersion: v1
metadata:
  name: mydb
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9377

上面定义的pod能够经过如下使用初始化和调试

kubectl create -f myapp.yaml
pod/myapp-pod created
kubectl get -f myapp.yaml

NAME        READY     STATUS     RESTARTS   AGE
myapp-pod   0/1       Init:0/2   0          6m
Name:          myapp-pod
Namespace:     default
[...]
Labels:        app=myapp
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:
  FirstSeen    LastSeen    Count    From                      SubObjectPath                           Type          Reason        Message
  ---------    --------    -----    ----                      -------------                           --------      ------        -------
  16s          16s         1        {default-scheduler }                                              Normal        Scheduled     Successfully assigned myapp-pod to 172.17.4.201
  16s          16s         1        {kubelet 172.17.4.201}    spec.initContainers{init-myservice}     Normal        Pulling       pulling image "busybox"
  13s          13s         1        {kubelet 172.17.4.201}    spec.initContainers{init-myservice}     Normal        Pulled        Successfully pulled image "busybox"
  13s          13s         1        {kubelet 172.17.4.201}    spec.initContainers{init-myservice}     Normal        Created       Created container with docker id 5ced34a04634; Security:[seccomp=unconfined]
  13s          13s         1        {kubelet 172.17.4.201}    spec.initContainers{init-myservice}     Normal        Started       Started container with docker id 5ced34a04634
kubectl logs myapp-pod -c init-myservice # Inspect the first init container
kubectl logs myapp-pod -c init-mydb      # Inspect the second init container

当咱们启动mydbmyservice两个服务后,咱们能够看到初始容器完成而且myapp-pod pod被建立.

kubectl create -f services.yaml

service/myservice created
service/mydb created
kubectl get -f myapp.yaml
NAME        READY     STATUS    RESTARTS   AGE
myapp-pod   1/1       Running   0          9m

这些示例很是简单可是应该能为你建立本身的初始容器提供一些灵感

行为细节

  • 在启动pod的过程当中,在存储卷和网络建立之后,初始容器依次建立.上一个容器必须返回成功下一个才能启动,若是因为运行时错误或者其它异常退出,它会依照restartPolicy来重试,然而,若是restartPolicy设置为Always,初始容器实际上使用的是OnFailure策略

  • 若是pod重启了,则全部的初始容器要从新执行

  • 对初始容器的spec的更改仅限于镜像(image)字段的修改,更改了初始容器的镜像字段至关于重启pod

  • 因为初始容器能够被重启,重试和从新执行,所以它里面的代码应当是幂等的,尤为是写入文件到EmptyDirs的代码应当注意文件可能已经存在

  • 容器中的全部初始容器和普通容器名称必须唯一.

资源

基于初始容器的执行顺序,如下关于资源的规则适用:

  • 对于特定资源,全部初始容器申请的最高的生效

  • 对于pod,相同资源申请取如下二者较高的一个:

    1) 全部普通应用容器申请的资源总和
    2) 初始容器申请的生效的资源(上面说到,初始容器申请资源取全部初始容器申请最大的一个)

  • 调度基于生效的初始请求,这就意味着初始容器能够申请预留资源,即使在pod之后的整个生命周期都用不到

pod重启缘由

一个pod基于如下列出的缘由,会重启,从新执行初始容器:

  • 用户更新初始容器的PodSpec致使镜像发生改变.普通应用容器改变只会使应用容器重启

  • 因为restartPolicy被设置为Always,致使全部容器均被停止,强制重启,因为垃圾回收初始容器的初始状态记录丢失

相关文章
相关标签/搜索