zoukankan      html  css  js  c++  java
  • Kubernetes的初始化容器initContainers

    initContainers是一种专用的容器,在应用程序容器启动之前运行,可以包括一些应用程序镜像中不存在的实用工具和安装脚本,可以完成应用的必要数据初始化等工作。总的来说就是在正式的容器启动之前做一些准备工作的。

            例如一个应用容器挂载的volume目录需要一些必不可少的初始化文件,不加init容器的时候直接挂载volume应用容器的那个目录是空的(因为docker挂载一个volume时,会用volume的内容覆盖容器内挂载目录的内容),这就需要让init容器也跟应用容器挂载同一个volume目录,将初始化文件放进去,然后在启动应用容器就能正常看到那些初始化文件了,我也正是遇到了这样的问题,才来研究和学习init容器的。

    1、一个pod可以运行多个容器,同样的一个pod也可能有一个或多个先于应用容器启动的 Init 容器,每个容器启动失败后都会根据你配置的重启策略进行重启,直到运行成功。Init 容器与普通的基本一样,主要区别如下

    • Init 容器总是运行到成功运行完为止。
    • 前面的 Init 容器必须已经运行完成,才会开始运行下一个init容器,而应用程序容器时并行运行的。

    2、因为 Init 容器具有与应用程序容器分离的单独镜像,所以使用他们可以具有如下优势:

    • 它们可以包含并运行实用工具,但是出于安全考虑,是不建议在应用程序容器镜像中包含这些实用工具的。
    • 它们可以包含使用工具和定制化代码来安装,但是不能出现在应用程序镜像中。例如,创建镜像没必要 FROM 另一个镜像,只需要在安装过程中使用类似 sed、 awk、 python 或 dig 这样的工具。
    • 应用程序镜像可以分离出创建和部署的角色,而没有必要联合它们构建一个单独的镜像。
    • Init 容器使用 Linux Namespace,所以相对应用程序容器来说具有不同的文件系统视图。因此,它们能够具有访问 Secret 的权限,而应用程序容器则不能。
    • 它们必须在应用程序容器启动之前运行完成,而应用程序容器是并行运行的,所以 Init 容器能够提供了一种简单的阻塞或延迟应用容器的启动的方法,直到满足了一组先决条件。

    3、下面是一些如何使用 Init 容器的思路:

    • 等待一个 Service 创建完成,通过类似如下 shell 命令:
        for i in {1..100}; do sleep 1; if dig myservice; then exit 0; fi; exit 1
      
    • 将 Pod 注册到远程服务器,通过在命令中调用 API,类似如下:
        curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register -d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'
      
    • 在启动应用容器之前等一段时间,使用类似 sleep 60 的命令。
    • 克隆 Git 仓库到数据卷。
    • 将配置值放到配置文件中,运行模板工具为主应用容器动态地生成配置文件。例如,在配置文件中存放 POD_IP 值,并使用 Jinja 生成主应用配置文件。

    4、 init容器使用示例,

           Kubernetes 1.6 版本后使用新语法,把 Init 容器的声明移到 spec 中,只需要添加 initContainers 即可,下面列一个具有 2 个 Init 容器的简单 Pod。 第一个等待 myservice 启动,第二个等待 mydb 启动。 一旦这两个 Service 都启动完成,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;']

    下面的 yaml 文件展示了 mydb 和 myservice 两个 Service:

    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
    $ kubectl describe -f myapp.yaml 
    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

    一旦我们启动了 mydb 和 myservice 这两个 Service,我们能够看到 Init 容器完成,并且 myapp-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 上使用 activeDeadlineSeconds,在容器上使用 livenessProbe,这样能够避免 Init 容器一直失败, 这就为 Init 容器活跃设置了一个期限。在 Pod 中的每个 app 和 Init 容器的名称必须唯一,与任何其它容器共享同一个名称,会在验证时抛出错误。

            在 Pod 启动过程中,Init 容器会按顺序在网络和数据卷初始化之后启动。 每个容器必须在下一个容器启动之前成功退出。 如果由于运行时或失败退出,导致容器启动失败,它会根据 Pod 的 restartPolicy 指定的策略进行重试,在所有的 Init 容器没有成功之前,Pod 将不会变成 Ready 状态,如果 Pod 重启,所有 Init 容器必须重新执行。

            因为 Init 容器可能会被重启、重试或者重新执行,所以 Init 容器的代码应该是幂等的(即任意多次执行所产生的影响与一次执行的影响相同)。 特别地,被写到 EmptyDirs 中文件的代码,应该对输出文件可能已经存在做好准备。

    5、Pod 能够重启,会导致 Init 容器重新执行,重启主要有如下几个原因:

    • 用户更新 PodSpec 导致 Init 容器镜像发生改变。更改 Init 容器的 image 字段,等价于重启该 Pod,应用容器镜像的变更只会重启应用容器。
    • Pod 基础设施容器被重启。这不多见,但某些具有 root 权限可访问 Node 的人可能会这样做。
    • 当 restartPolicy 设置为 Always,Pod 中所有容器会终止,强制重启,由于垃圾收集导致 Init 容器完成的记录丢失。
  • 相关阅读:
    激活第一个CPU
    每CPU变量
    在 Vue中使用layui日历控件,标注重要日子
    手机号,银行卡断开方式
    下载文件流
    使用class关键字创建类组件、props参数
    class继承关键字extends和super
    用于判断文件是已什么结尾的
    flex一些属性
    类组件
  • 原文地址:https://www.cnblogs.com/yanh0606/p/11395920.html
Copyright © 2011-2022 走看看