kubernetes通过容器主进程非零exit码识别异常并触发自愈,需配合restartpolicy(onfailure/always)和livenessprobe实现全场景恢复。

Kubernetes 通过容器的 exit 状态码识别异常,并结合重启策略和探针机制触发自愈。关键不是“用 exit 码主动触发”,而是让容器在真正出错时返回非零状态码,K8s 才能据此判断失败并执行恢复动作。
exit 状态码是 K8s 自愈的“信号源”
K8s 不会监控进程内部逻辑,只看容器主进程(PID 1)退出时返回的整数状态码:
-
exit code == 0:K8s 认为容器“正常结束”(比如批处理完成),按
restartPolicy决定是否重启(Never就不启,Always仍会启) -
exit code ≠ 0(如 1、137、255):K8s 视为“异常终止”,若 restartPolicy 是
OnFailure或Always,就会立即重建 Pod(即拉起新容器)
注意:
137通常表示被 OOMKilled(内存超限被系统 kill),255常见于脚本中exit -1转换而来——这些都会被 K8s 捕获为失败信号。
如何让 exit 码真正驱动自愈
✅ 正确配置 Pod 的 restartPolicy
在 YAML 中显式声明,不要依赖默认(虽默认是 Always,但显式写更可靠):
spec:
restartPolicy: OnFailure # 或 Always
containers:
- name: app
image: my-app:v2
-
OnFailure:仅当容器以非 0 码退出才重启 → 适合需区分“成功结束”和“崩溃”的场景(如 Job) -
Always:不管 0 还是非 0 都重启 → 适合长期服务(如 API),但注意:它也会重启“正常退出”的容器(例如你主动调用exit 0)
✅ 在应用中主动返回有意义的 exit 码
不要让程序静默崩溃。例如:
在 Linux 上通过 Docker 运行 OpenClaw,并使用 Tailscale 实现远程访问。⚠️ 涉及 sudo、Docker、Tailscale和凭证挂载——请先查阅安全章节...
- Go 程序检测到数据库连不上,不要 panic 后由 runtime 返回随机码,而是:
log.Fatal("DB connection failed") // 默认 exit 1 - Shell 脚本启动服务前做预检:
if ! nc -z localhost 8080; then echo "Health check failed" >&2 exit 128 # 明确传递失败语义 fi exec "$@"
这样 kubectl describe pod xxx 的 Last State 字段会显示:
Last State: Terminated Reason: Error Exit Code: 128 Started: ... Finished: ...
K8s 就会按策略触发重建。
✅ 配合 livenessProbe 实现“非退出式”自愈
有些问题不会导致进程退出(如死锁、goroutine 泄漏),这时单靠 exit 码不够。要用存活探针:
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
failureThreshold: 3 # 连续3次失败 → kill 容器 → 触发 restartPolicy
探针失败后,kubelet 主动发送 SIGTERM 终止容器,主进程退出时返回系统默认码(通常是 143),K8s 再根据 restartPolicy 决定是否拉起新实例。
⚠️ 容易踩坑的点
-
Docker 层 exit 码被掩盖:如果你用
docker run启动容器再手动exit 1,这个码对 K8s 无效——K8s 管的是 Pod 里的容器,不是你本地 docker CLI 的 session。 -
initContainer 失败不走主容器 restartPolicy:init 容器失败默认会重试(受
restartPolicy影响小),但主容器不会因此重启;要让它生效,得让 init 失败导致整个 Pod 启动失败,从而触发 Pod 级重建。 -
exit 0 被误用:比如健康检查脚本里
curl -f http://... || exit 0——这会让失败也返回 0,K8s 认为“一切正常”,自愈机制完全失效。
总结一句话
让 exit 状态码驱动 K8s 自愈,本质是:让业务代码在确定不可恢复时明确 exit N(N≠0),配合 restartPolicy: OnFailure 或 Always,K8s 自然会重建 Pod。再叠加 livenessProbe,就能覆盖“不退出但已卡死”的情况。










