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。
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 状态。
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 启动并成功完成后:
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 健康检查点.
serviceB:portB/pathB/
docker logs 4fd58bf54f76
waiting for serviceB service
waiting for serviceB service
等待一段时间后,再次通过 kubectl get po -o wide 查看 pod 处于 Running 状态
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 启动的时间。