Skip to content

Kubernetes服务启动依赖问题

一个 pod 中可以有一或多个 Init Container。Pod 的中多个 Init Container 启动顺序为 yaml 文件中的描述顺序,且串行方式启动,下一个 Init/app Container 必须等待上一个 Init Container 完成后方可启动。例如,Init Container1-> … -> Init Containern -> app Container[1-n]。Init Container1 成功启动并且完成后,后续的 Init Container 和 app Container 才可以启动,如 Init Container 启动或执行相关检查失败,后续的 init Container 和应用 Container 将不会被执行启动命令。

因此可利用 Init Container 来判断 app Container 中被依赖的服务是否成功启动。如被依赖的 app Container 服务启动失败,那么利用 Init Container 启动失败可以阻止后续 app Container 服务的启动。

由于 Init Container 必须要在 pod 状态变为 Ready 之前完成,所以其不需要 readiness 探针。另外在资源的 requests 与 limits 上与普通 Container 有细微差别,除以上 2 点外,Init Container 与普通 Container 并无明显区别。

Init Containers 用途

  • 前文已经提及,由于 Init Container 必须在 app Containers 启动之前完成,所以可利用其特性,用作服务依赖处理。比如某一个服务 A,需依赖 db 或 memcached,那么可以利用服务 A pod 的 Init Container 判断 db/memcached 是否正常提供服务,如果启动服务失败或工作异常,设置 Init Container 启动失败,那么 pod 中的服务 A 就不会被启动了。
  • 应用镜像因安全原因等没办法安装或运行的工具,可放到 Init Container 中运行。另外,Init Container 独立于业务服务,与业务无关的工具如 sed, awk, python, dig 等也可以按需放到 Init Container 之中。最后,Init Container 也可以被授权访问应用 Container 无权访问的内容。

Init Container 处理服务依赖应用举例

serviceA 服务依赖 serviceB,而 serviceB 采用 Readness 探针的 HTTPGetAction Handler。

yaml
spec:
  initContainers:
    - name: init-serviceA
      image: registry.docker.dev.fwmrm.net/busybox:latest
      command:
        [
          "sh",
          "-c",
          "curl --connect-timeout 3 --max-time 5 --retry 10 --retry-delay 5 --retry-max-time 60 serviceB:portB/pathB/",
        ]
  containers:

如果启动 serviceA Pod 时,serviceB 还没有 ready,通过 kubectl get po -o wide 查看 pod 处于 Init 状态。

bash
NAME                        READY     STATUS    RESTARTS   AGE       IP          .l  NODE
serviceA-3071943788-8x27q            0/1       Init:0/1   0          20s       10.244.1.172   bjo-ep-svc-017.dev.fwmrm.net

通过 kubectl describe po serviceA-3071943788-g03wt 查看,可以看出 app Container 的启动时在 init Container 启动并成功完成后:

bash
Events:
FirstSeen LastSeen    Count   From                    SubObjectPath               Type        Reason  Message
--------- --------    -----   ----                    -------------               --------    ------  -------
25s       25s     1   default-scheduler                               Normal      ScheduledSuccessfully assigned serviceA-3071943788-g03wt to bjo-ep-dep-040.dev.fwmrm.net
25s       25s     1   kubelet, bjo-ep-dep-040.dev.fwmrm.net                       Normal      SuccessfulMountVolume   MountVolume.SetUp succeeded for volume "serviceA-config-volume"
25s       25s     1   kubelet, bjo-ep-dep-040.dev.fwmrm.net                       Normal      SuccessfulMountVolume   MountVolume.SetUp succeeded for volume "default-token-2c9j1"
24s       24s     1   kubelet, bjo-ep-dep-040.dev.fwmrm.net   spec.initContainers{init-myservice} Normal      Pulling pulling image "registry.docker.dev.fwmrm.net/ui-search-solr-data:latest"
24s       24s     1   kubelet, bjo-ep-dep-040.dev.fwmrm.net   spec.initContainers{init-myservice} Normal      Pulled  Successfully pulled image "registry.docker.dev.fwmrm.net/busybox:latest"
24s       24s     1   kubelet, bjo-ep-dep-040.dev.fwmrm.net   spec.initContainers{init-myservice} Normal      Created Created container
24s       24s     1   kubelet, bjo-ep-dep-040.dev.fwmrm.net   spec.initContainers{init-myservice} Normal      Started Started container
20s       20s     1   kubelet, bjo-ep-dep-040.dev.fwmrm.net   spec.containers{is}         Normal      Pulling pulling image "registry.docker.dev.fwmrm.net/infra/is:latest"
20s       20s     1   kubelet, bjo-ep-dep-040.dev.fwmrm.net   spec.containers{is}         Normal      Pulled  Successfully pulled image "registry.docker.dev.fwmrm.net/infra/is:latest"
20s       20s     1   kubelet, bjo-ep-dep-040.dev.fwmrm.net   spec.containers{is}         Normal      Created Created container
19s       19s     1   kubelet, bjo-ep-dep-040.dev.fwmrm.net   spec.containers{is}         Normal      Started Started container

查看 docker Container log,init Container 正在按照预先的设定,每 3 秒轮询验证 serviceB 健康检查点.

bash
serviceB:portB/pathB/
docker logs 4fd58bf54f76
waiting for serviceB service
waiting for serviceB service

等待一段时间后,再次通过 kubectl get po -o wide 查看 pod 处于 Running 状态

bash
NAME                        READY     STATUS    RESTARTS   AGE       IP          .l  NODE
serviceA-3071943788-g03wt   1/1       Running   0          1m        10.244.2.68   bjo-ep-dep-040.dev.fwmrm.net

如果 pod 重启了,所有 init Container 都需重新运行。Kubernetes 禁止 Init Container 使用 readiness 探针,可以使用 Pod 定义 activeDeadlineSeconds 和 Container 的 livenessProbe 防止 init containers 一直重复失败. activeDeadlineSeconds 包含了 init container 启动的时间。

最近更新