初始化容器

文章目录


一、Init Container

上次学到容器的健康检查的两个探针liveness probe(存活探针)和 readiness probe (可读性探针)的使用方法,我们说在这两个探针是可以影响容器的声明周期,包括我们之前提到的容器的两个钩子函数 PostStartPreStop。今天给大家介绍的是 Init Container(初始化容器)。

Init Container就是用来做初始化工作的容器,可以是一个或者多个,如果有多个的话,这些容器会按定义的顺序依次执行,只有所有的 Init Container执行完后,主容器才会被启动。我们知道一个 Pod 里面的所有容器是共享数据卷和网络命名空间的,所以 Init Container 里面产生的数据可以被主容器使用到的。

是不是感觉 Init Container 和之前的钩子函数有点类似,只是是在容器执行前来做一些工作,是吧?不同的角度看上去的话,初始化容器的确有点像 PreStart,但是钩子函数和我们的Init Container是处在不同阶段的,我们可以通过下面的图来了解一下:
在这里插入图片描述
在这里插入图片描述
从上面的图我们可以直观的看到 PostStartPreStop包括 liveness 和 readiness 属于主容器的生命周期范围内的,而 Init Container是独立于主容器之外的,当然他们都属于 Pod 的生命周期范畴之内的,现在我们应该明白 Init Container和钩子函数之类的区别了吧。

另外我们可以看到上面我们的 Pod 右边还有一个 Infra 的容器,这是一个什么容器呢?我们可以在集群环境中去查看下任意一个 Pod 对应运行的 Docker 容器, 我们可以发现每一个 Pod 下面都包含了一个 pause-amd64 的镜像,这个就是我们的 infra 镜像, 我们知道 Pod 下面的所有容器是共享同一个网络命名空间的,这个镜像就是来做这个事情的,所以每一个 Pod 当中都会包含一个这个镜像。

很多同学最开始 Pod 启动不起来就是因为这个 infra 镜像没有被拉取下来,因为默认该镜像是需要到谷歌服务器上拉取的,所以需要提前拉取到节点上面。

我们说 Init Container 主要是来做初始化容器工作的,那他有什么应用场景呢?

  • 等待其他模块 Ready :这个可以用来解决服务之间的依赖问题,比如我们有一个 Web 服务,该服务又依赖于另一个数据库服务,但是我们启动这个 Web 服务的时候并不能保证依赖的这个数据库服务就已经启动前来了,所以可能出现一段时间内 Web 服务连接数据库异常。要解决这个问题的话我们就可以在 Web 服务的容器 Pod 中使用一个 Init Container,在这个初始化容器中去检查数据库是否已经准备好了,准备好了过后初始化容器就结束退出,然后我们的主容器 Web 服务被启动起来,这个时候去连接数据库就不会有问题了。
  • 做初始化配置:比如集群里检测所有已经存在的成员节点,为主容器准备好集群的配置信息,这样主容器起来后就能用这个配置信息加入集群。
  • 其他场景:如将 pod 注册到一个中央数据库、配置中心等。

我们先来给大家演示下服务依赖的场景下初始化容器的使用方法,如下 Pod 的定义方法

apiVersion: v1
kind: Pod
metadata:
  name: init-pod1
  labels:
    app: init
spec:
  containers:
  - name: init-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;']

Service的对应的 YAML 内容:

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

我们可以先创建上面的 Pod ,然后 查看下 Pod 的状态,然后再创建下面的 Service ,对比下前后状态。

我们在Pod 启动过程中,初始化容器会按顺序在网络和数据卷初始化之后启动。每个容器必须在下一个容器启动之前成功退出。如果由于运行时或失败退出,导致容器启动失败,它会根据 Pod 的 restartPolicy 指定的策略进行重试。然而,如果 Pod 的 restartPolicy 设置为 Always,Init容器失败时会使用 RestartPolicy 策略。

在所有的初始化容器没有成功之前,Pod 将不会变成 Ready 状态。正在初始化中的 Pod 处于 Rending 状态,但应该会将条件 Initializing 设置为 true。

接下来我们再来尝试创建一个初始化配置工作的 Pod :

apiVersion: v1
kind: Pod
metadata:
  name: init-demo
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
    volumeMounts:
    - name: workdir
      mountPath: /usr/share/nginx/html
  initContainers:
  - name: install
    image: busybox
    command:
    - wget
    - "-O"
    - "/work-dir/index.html"
    - http://www.baidu.com
    volumeMounts:
    - name: workdir
      mountPath: "/work-dir"
  volumes:
  - name: workdir
    emptyDir: {}

我们可以看到这里出现了 volumes ,spec.volumes 指的是 Pod 中卷,spec.containers.volumeMounts,是将指定的卷 mount 到容器指定的位置,相当于 docker 里面的 -v 宿主机目录:容器目录,我们前面用到过 hostPath ,我们这里使用的是 emptyDir{} ,这个就相当于一个共享卷,是一个临时的目录,生命周期等同于 Pod 的生命周期。

初始化容器执行完,会下载一个 HTML 文件映射到 emptyDir{},而主容器也是和 spec.volumes 里面的 emptyDir{}进行映射,所以 nginx 容器的 /user/share/nginx/html 目录下会映射 index.html 文件。

我们来创建该 Pod ,然后验证nginx 容器是否运行 :

$ kubectl get pod init-demo

输出显示了nginx 容器正在运行:

NAME      READY     STATUS    RESTARTS   AGE
nginx     1/1       Running   0          43m

在init-demo 容器里的 nginx 容器打开一个 shell :

$ kubectl exec -it init-demo -- /bin/bash

在shell 里,直接查看下 index.html 的内容:

root@nginx:~# cat /usr/share/nginx/html/index.html

如果我们看到有百度相关的信息那么证明我们上面的初始化工作就完成了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值