bigywater.tech
Kubernetes · 32

init 容器:顺序执行和失败重试

init 容器怎么保证先于应用容器运行?失败了会怎样?它们的资源请求算不算?应用容器崩溃重启时会不会再来一遍?这篇用带时间戳的共享卷、STATUS 变化和调度结果,把这些问题一一量出来。

8.75 s
三个各睡 2 秒的 init 容器之后,应用容器真正启动的时刻(init 结束于 7.75 秒)
Init:CrashLoopBackOff
init 容器失败后的 STATUS;restartCount=2、第三次成功后 14.1 秒进入 Running
setup ×1、app ×3
应用容器重启 2 次后共享卷日志里 init 与应用各自的运行次数

按顺序、一个接一个

实测 · 本机执行输出
  kubectl get pod seq 的 STATUS 变化:Init:0/3(+0.1s) → Init:1/3(+3.5s) → Init:2/3(+6.6s) → Running(+9.4s)
  共享卷里的日志(时间是相对第一行的秒数):
    i1   start + 0.00s
    i1   end   + 2.00s
    i2   start + 2.96s
    i2   end   + 4.96s
    i3   start + 5.74s
    i3   end   + 7.75s
    app  start + 8.75s
  initContainerStatuses:i1=terminated(exitCode=0); i2=terminated(exitCode=0); i3=terminated(exitCode=0);Initialized=True

三个 init 容器各睡 2 秒,往共享的 emptyDir 里写带时间的日志:i1 在 0.00~2.00 秒、i2 在 2.96~4.96 秒、i3 在 5.74~7.75 秒,应用容器 8.75 秒才启动。每个容器之间还有约 1 秒的启动开销。kubectl get 的 STATUS 显示 Init:0/3 → Init:1/3 → Init:2/3 → Running,三个 init 容器都以 exitCode=0 结束,Initialized 条件为 True。

失败了就重试

实测 · 本机执行输出
  init 容器前两次 exit 1、第三次成功(用 emptyDir 里的计数文件实现):STATUS 变化:Init:0/1(+0.1s) → Init:Error(+1.8s) → Init:CrashLoopBackOff(+12.8s) → Init:0/1(+13.3s) → PodInitializing(+13.7s) → Running(+14.1s)
  initContainerStatuses.restartCount=2;最终 phase=Running;应用容器 app 状态=running
  restartPolicy=Never 的 Pod,init 容器 exit 1:phase=Failed;STATUS 列=Init:Error;应用容器 app 状态=waiting(从未启动)

一个前两次 exit 1、第三次成功的 init 容器:STATUS 经过 Init:Error、Init:CrashLoopBackOff,等退避结束再重试,第三次成功后 PodInitializing → Running,restartCount=2,应用容器全程没有启动。restartPolicy: Never 的 Pod 里 init 容器失败一次,整个 Pod 就是 Failed(STATUS Init:Error),应用容器从未启动。

资源请求也算

实测 · 本机执行输出
  req-app(init 10m、应用 100m):phase=Running;PodScheduled=True;nodeName=kx-main-worker2
  req-init-big(init 100 核、应用 100m):phase=Pending;PodScheduled=False reason=Unschedulable;0/3 nodes are available: 1 node(s) had untolerated taint(s), 2 Insufficient cpu. preemption: 0/
  (每个节点 allocatable cpu=10 核)

调度器按“所有 init 容器里最大的请求”和“所有应用容器请求之和”两者的较大值来算 Pod 的有效请求。init 容器 10m、应用 100m 的 Pod 正常调度;init 容器请求 100 核、应用只要 100m 的 Pod 保持 Pending,reason Unschedulable,message 里 2 Insufficient cpu(每个节点 10 核)——尽管 init 容器很快就会退出。

只运行一次

实测 · 本机执行输出
  应用容器 2 秒后 exit 1,28 秒内重启了 2 次;最近一次应用容器 cat 出的共享卷日志里 setup-ran 出现 1 次、app-start 出现 3 次(每次启动应用容器都追加一行);init 容器 setup 的 restartCount=0

应用容器 2 秒后 exit 1 反复重启(28 秒内 2 次),共享卷日志里 setup-ran 只有 1 行、app-start 有 3 行,init 容器 setup 的 restartCount 仍是 0。init 容器是给 Pod 启动做准备的一次性步骤,应用容器重启不会重新运行它们;要让它们重做只能重建 Pod。

分步演示

init 容器
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0);容器之间用 emptyDir 共享日志文件,时间戳取自 /proc/uptime(同一节点上的容器共享内核,可以直接比较,busybox 的 date 不支持 %N);STATUS 取自 kubectl get pod 的第 3 列,每 0.3 秒轮询;失败重试用 emptyDir 里的计数文件实现“前两次失败第三次成功”;每个节点 allocatable cpu 为 10 核;每种情形各一次
    • 没有验证:原生 sidecar(restartPolicy: Always 的 init 容器,后面有专门的文章);init 容器的 securityContext 与镜像拉取失败时的 Init:ImagePullBackOff;activeDeadlineSeconds 对 init 阶段的限制;Pod 重建、节点重启(沙箱被重建)时 init 容器是否重跑;init 容器日志的保留;有效请求在 describe node 的 Allocated resources 里的体现
    京ICP备2026067502号-1京公网安备11010502063487号