1. 引言:当容器崩溃时,Kubernetes如何“急救”?

想象一下你正在运营一家7x24小时营业的连锁餐厅,每个服务员(容器)负责处理顾客请求。如果某个服务员突然晕倒(容器崩溃),你是立刻换人顶替(重启容器)、等他自己缓过来再干活(仅在失败时重启),还是干脆让他回家(不重启)?Kubernetes的重启策略(AlwaysOnFailureNever)就像这家餐厅的应急预案,本文将用真实场景解析其设计哲学和配置技巧。


2. 三种重启策略的核心逻辑

2.1 Always:无脑重启的“永动机模式”

核心行为:无论容器以什么状态退出(成功或失败),都会无限重启。
适用场景:长期运行的Web服务、API服务器等需要高可用的场景。

示例:使用Deployment部署的Web服务

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-server
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: nginx
        image: nginx:1.21
        livenessProbe:
          httpGet:
            path: /
            port: 80
      restartPolicy: Always  # 无论成功或失败,始终保持容器运行

陷阱预警:如果容器因代码逻辑错误频繁崩溃,可能导致无限重启循环。此时需结合资源限制(如livenessProberesource.limits)防止雪崩。


2.2 OnFailure:理性修复的“智能管家模式”

核心行为:仅当容器以非0状态码退出时(即程序主动报错),才会触发重启。
适用场景:离线批处理任务、数据分析任务等需要容错的场景。

示例:单次数据分析任务

apiVersion: batch/v1
kind: Job
metadata:
  name: data-processor
spec:
  template:
    spec:
      containers:
      - name: processor
        image: python:3.9
        command: ["python", "batch_processing.py"]
        # 设置重试次数上限(避免无限重试)
        restartPolicy: OnFailure  # 仅在处理失败时重启
      backoffLimit: 4  # 最多尝试4次(含初次运行)

关键细节

  • backoffLimitrestartPolicy: OnFailure配合使用,控制最大重试次数。
  • 若脚本以sys.exit(0)退出(即使逻辑错误),不会触发重启!需严格规范错误码设计。

2.3 Never:放任自由的“甩手掌柜模式”

核心行为:无论成功或失败,容器退出后都不重启。
适用场景:一次性任务、调试场景或由外部系统管理生命周期的场景。

示例:临时数据备份任务

apiVersion: batch/v1
kind: Job
metadata:
  name: nightly-backup
spec:
  template:
    spec:
      containers:
      - name: backup-agent
        image: alpine/s3-cp
        command: ["./backup.sh"]
        restartPolicy: Never  # 执行一次后无论结果如何都不重启
      restartPolicy: Never  # Job的Pod模板必须显式声明Never!

特殊限制

  • Deployment/DaemonSet不支持Never策略(因为与控制器职责冲突)。
  • 可用于创建“一次性”Pod(直接通过kubectl run),例如临时调试:
kubectl run debug-pod --image=busybox --restart=Never -- -- /bin/sh -c "sleep 30"

3. 重启策略的隐形搭档:那些必须了解的关联技术

3.1 健康检查(Liveness/Readiness Probe)

重启策略的“指挥官”——如果容器进程还在运行但实际已瘫痪,只有健康检查能发现并触发重启。

livenessProbe:
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 15  # 容器启动后15秒开始探测
  periodSeconds: 5         # 每5秒检查一次
  failureThreshold: 3      # 连续失败3次判定为不健康

经典错误

  • 忘记设置initialDelaySeconds,导致容器在启动阶段被误杀。
  • 探测频率过高(periodSeconds: 1)引发性能问题。

3.2 资源配额(Resource Limits)

避免无限重启的核心防线:限制CPU/内存用量,防止单个Pod占用过多资源。

resources:
  limits:
    memory: "512Mi"
    cpu: "1"
  requests:
    memory: "256Mi"
    cpu: "0.5"

经验法则

  • 当容器因OOM(内存溢出)被杀死时,会触发重启(具体行为由策略决定)。
  • 资源配置不合理可能导致频繁OOM,叠加Always策略形成死循环。

4. 策略选型的三大黄金法则

法则1:区分“瞬时故障”与“永久故障”
  • 瞬时故障(如网络抖动):适合AlwaysOnFailure自动恢复。
  • 永久故障(如代码缺陷):需人工介入,否则重启只会掩盖问题。

法则2:Controller类型决定策略选项
  • Deployment/DaemonSet:只能选择Always(控制器负责维持副本数)。
  • Job/CronJob:可选OnFailureNever
  • 裸Pod:三者皆可,但实际生产环境极少直接使用。

法则3:监控重启次数,防止“无效劳动”

通过kubectl describe pod查看重启历史:

Containers:
  my-container:
    Restart Count:  5  # 重要指标!突然飙升可能预示问题

诊断命令合集

# 查看Pod重启次数
kubectl get pods --field-selector=status.phase=Running --show-labels

# 查看最近5次重启的Pod事件
kubectl get events --sort-by=.metadata.creationTimestamp | grep "BackOff"

5. 高频问题攻防战:避坑指南

问题1:Job任务失败后持续重启,无法终止

根本原因:未设置backoffLimit或阈值过大(默认6次)。
解决步骤

  1. 为Job添加backoffLimit: 3等明确上限。
  2. 在日志中查找Error: job has failed...确认退出原因。

问题2:Pod频繁重启但无错误日志

排查路径

  1. 检查livenessProbe配置是否过于敏感(例如检测路径错误)。
  2. 通过kubectl logs --previous查看崩溃前最后一次日志。
  3. 检查节点资源是否充足(kubectl describe node)。

6. 总结:重启策略的设计哲学

  • Always是默认的安全网,但需配合健康检查防止滥用。
  • OnFailure在自动化和人工干预间找到平衡点。
  • Never将控制权完全交还给开发者,适合高阶场景。

通过合理选择策略,你的Kubernetes集群将像一支训练有素的特种部队——既能在故障面前快速反应,又不会因盲目行动浪费资源。