Init Container的应用场景

当我们在运用一个服务之前,通常会做一些初始化的工作,而这些工作一般只需要运行一次,成功后就不再运行。为此kubernetes 引入了Init Container,用于在启动应用容器之前启动一个或多个“初始化”容器,完成应用容器的所需的预制条件。

Init Containers与常规的容器非常类似,但是它一些独有的特征:

  • 他们仅运行一次,成功后就会退出。
  • 每个容器必须在成功执行完成后,系统才能继续执行下一个容器。
  • 如果Init Container运行失败,kubernetes 将会重复重启Pod,直到Init Container 成功运行,但是如果 Pod的重启策略(restartPolicy)设置为Never,则Pod不会重启。
  • Init Container支持普通应用Container的所有参数,包括资源限制,挂载卷,安全设置等。但是Init Container 在资源的申请和限制上略有不同,同时,由于Init Container必须在Pod ready之前完成并退出,所以它不支持 readiness 探针。

Init Container 通常有如下应用方式:

  • 处于安全的考虑,可以将自定义的代码和工具使用Init Container运行,而不必添加到 应用 容器的镜像中。
  • 应用程序映像的构建和部署者角色可以彼此独立,无需共同构建单个应用程序映像
  • 使用不同的Linux命名空间,可以使它们具有来自应用容器的不同文件系统权限。 因此,Init Container可以获得应用程序容器无法访问的Secrets。
  • Init Container在任何应用程序容器启动之前运行完毕,而应用程序容器通常是并行运行的,因此初始容器提供了一种简单的方法来阻止或延迟应用程序容器的启动,直到满足一些前提条件。

具体的应用场景示例:

  • 如使用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=$()&ip=$()’
  • 在启动应用之前,等待一段时间:sleep 60
  • 从git仓库拉取配置或代码到指定的挂载卷中
  • 使用模板工具动态的生成配置,并给配置文件添加合适的参数。如使用Jinja模板将POD IP添加到应用容器的配置中。

定义Init Container

这里定义一个nginx,在nginx容器启动前更改默认起始页面内容:

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  initContainers:
  - name: init-myservice
    image: busybox
    command: ['sh', '-c', 'echo "this init-container test page" > /html/index.html']
    volumeMounts:
    - name: index-dir
      mountPath: "/html"
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
    volumeMounts: 
    - name: index-dir
      mountPath: /usr/share/nginx/html
  volumes:
  - name: index-dir
    emptyDir: {}

创建容器后,可以看到,先执行初始化操作:

# kubectl  get pod
NAME        READY     STATUS     RESTARTS   AGE
myapp-pod   0/1       Init:0/1   0          12s

# 显示正在初始化:
# kubectl  get pod
NAME        READY     STATUS            RESTARTS   AGE

myapp-pod   0/1       PodInitializing   0          22s

# kubectl  get pod -o wide
NAME        READY     STATUS    RESTARTS   AGE       IP          NODE
myapp-pod   1/1       Running   0          38s       10.2.74.5   10.0.0.3

#日志信息:
# kubectl  describe pod
Events:
  Type    Reason                 Age   From               Message
  ----    ------                 ----  ----               -------
  Normal  Scheduled              29s   default-scheduler  Successfully assigned myapp-pod to 10.0.0.3
  Normal  SuccessfulMountVolume  29s   kubelet, 10.0.0.3  MountVolume.SetUp succeeded for volume "index-dir"
  Normal  SuccessfulMountVolume  29s   kubelet, 10.0.0.3  MountVolume.SetUp succeeded for volume "default-token-hmvnc"
  Normal  Pulling                28s   kubelet, 10.0.0.3  pulling image "busybox"
  Normal  Pulled                 16s   kubelet, 10.0.0.3  Successfully pulled image "busybox"
  Normal  Created                16s   kubelet, 10.0.0.3  Created container
  Normal  Started                16s   kubelet, 10.0.0.3  Started container
  Normal  Pulling                15s   kubelet, 10.0.0.3  pulling image "nginx"
  Normal  Pulled                 1s    kubelet, 10.0.0.3  Successfully pulled image "nginx"
  Normal  Created                1s    kubelet, 10.0.0.3  Created container
  Normal  Started                1s    kubelet, 10.0.0.3  Started container

注意事项

Pod中的每个应用程序和Init Container的名称必须是唯一的; 任何Container与另一个Container共享一个名称都会引发验证错误。

在Pod重新启动时, init Container 将会重新运行,那么所执行的初始化操作也会再次执行,这就要求Init Container的操作是可以重复执行的。例如上面的示例中,在对挂载目录中文件的添加前,可以先判断文件是否已经存在的处理,来防止出错。
常见的Pod重启场景如下:

  • init container的镜像被更新时, init Container将会重新运行,导致Pod重启。仅更新应用容器的镜像,只会使得应用容器被重启。
  • Pod的 pause镜像更新时, Pod将会重启。
  • 若Pod 中的所有应用容器都终止了,并且restartPolicy=always, 则Pod将会重启。