什么是initContainers?

初始化容器,顾名思义容器启动的时候,会先启动可一个或多个容器,如果有多个,那么这几个initContainers按照定义的顺序依次执行,只有所有的initContainers执行完成功(返回状态为0)后,主容器才会启动。如果Pod的initContainers失败,Kubernetes会不断地重启该Pod,直到initContainers容器成功为止。但是,如果Pod对应的restartPolicy值为Never,它是不会重新启动。

初始化容器特性

  • 主要负责初始化工作
  • 不支持readiness类型探针
  • 与主容器共享存储卷(同一Pod),数据可以被主容器使用到
  • 定义初始化容器与普通应用容器的语法相同
  • 初始化容器与普通容器有各自独立的image,本质上是将初始化逻辑与主体业务逻辑分离并放置在不同的image中。
  • initContainers的重启策略:当初始化容器执行失败时,如果restart policy是OnFailure或者Always,那么会重复执行失败的初始化容器一直到成功,如果restart policy是Never,则不会重启失败的初始化容器。如果初始化容器执行成功,那么无论restart policy是什么,即使是Always,也不会再次被重启。
  • 当初始化容器正在运行时,整个pod处于pending阶段,状态为Initializing。如果整个pod被restart,则所有容器包括初始化容器也要再运行一次。
  • 初始化容器可以被重启、重复运行多次。因些注意解决"幂等"问题,如初始化容器第一次运行时创建文件并写入内容,那么第二次运行时文件已经存在并且已经有内容,要注意解决这类问题。
  • 网络与volume的初始化要先于初始化容器,或者说pod的pause根容器先于初始化容器启动。

初始化容器的状态可以通过pod的.status.initContainerStatuses字段查看,它的值是一个数组,分别表示每个初始化容器的状态。数组中每个成员的结果与表示普通应用容器状态的结构一样,字段含义相同。

与普通容器不同之处

initContainers支持应用容器的全部字段和特性配置,包括资源限制、数据卷和安全设置。 但它对资源请求和限制的处理稍有不同,而且initContainers不支持Readiness Probe(就绪探针),因为它们必须在Pod就绪之前运行完成。

如果为一个Pod指定了多个initContainers,那些容器会按顺序一次运行一个。每个initContainers必须运行成功,下一个才能够运行。当所有的 initContainers运行完成时,Kubernetes才会开始初始化应用Pod。

使用场景

  • 初始化容器可以包含不能随普通容器一起发布出去的敏感信息。
  • 初始化容器可以包含用户自定义的代码、工具,如sed、awk、python等方便完成初始化、设置工作。
  • 因为初始化逻辑与主体业务逻辑分布在不同的image中,因此image构建者与主体业务逻辑开发者可以各自独立的工作。
  • 初始化容器使用Linux namespace,不同于普通应用容器,具有不同的文件系统视图,并且对于低层的操作系统有更在的访问权限。
  • 当应用启动的前置条件不具备时,初始化容器可以阻止普通应用容器启动,避免在条件不具备时反复启动注定会失败的容器而浪费系统资源。(问题:同一个pod中的多个普通应用容器是否可以编排它们的启动顺序?)

最后一个为我们最常用的场景 ,即按序依次启动服务,若前面的服务未启动成功,后序服务不会创建。

使用示例

myapp.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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;']

其中关于initContainers的配置

1
2
3
4
5
6
7
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;']

参数解析:

  • name: 名称
  • image:镜像名,一般可采用busybox这类小体积低资源占用的镜像
  • command:自定义的检查命令,通过返回值是否为0来判断成功或失败,继而决定后续容器是否启动。

启动顺序:init-myservice --> init-mydb --> myapp-container

初始化容器若指定volumeMounts,默认为emptyDir卷,可以与主容器共享卷(主容器挂载此emptyDir),这样可以为主容器做更多的准备工作。

资源

为initContainers配置资源使用规则:

  • 在所有initContainers上定义的,任何特殊资源请求或限制的最大值,是有效初始请求/限制
  • Pod对资源的有效请求/限制要高于:
    • 所有应用容器对某个资源的请求/限制之和
    • 对某个资源的有效初始请求/限制
  • 基于有效请求/限制完成调度,这意味着initContainers能够为初始化预留资源,这些资源在Pod生命周期过程中并未被使用。
  • initContainers和应用容器具有相同的有效QoS。

注意事项

  • 修改初始化容器的image会导致整个pod重启,但是,更新应用容器的image只会导致相应的容器重启,而不是整个pod。
  • 根容器重启导致整个pod重启,初始化容器也会重启。这种情况很少见。
  • 初始化容器执行成功记录丢失也会导致初始化容器重启