4. Kubernetes 资源版本管理:Deployment、StatefulSet、DaemonSet 的更新策略与 Revision 历史机制

在基于 Helm 的发布流水线中,回滚操作的核心依赖是 Kubernetes 工作负载资源的版本管理能力。Deployment、StatefulSet 和 DaemonSet 各自拥有不同的更新策略与 Revision 历史机制,理解这些差异是设计可靠回滚策略的前提。

4.1 更新策略对比

三种工作负载资源支持不同的更新策略,直接影响回滚时的行为与速度。

资源类型 默认更新策略 可选策略 回滚粒度
Deployment RollingUpdate Recreate Pod 级别,支持逐步回滚
StatefulSet RollingUpdate OnDelete Pod 级别,按序回滚
DaemonSet RollingUpdate OnDelete 节点级别,逐节点回滚
关键差异: Deployment 支持 maxSurge 和 maxUnavailable 参数控制滚动速率;StatefulSet 按 Pod 序号从高到低更新;DaemonSet 按节点逐个更新。这些差异决定了回滚时的 Pod 替换顺序与并发度。

4.2 Revision 历史机制

Kubernetes 通过 ControllerRevision 资源记录每个工作负载的版本历史。每次 Pod 模板发生变化时,系统会自动创建一个新的 Revision,并保留历史版本用于回滚。

# 查看 Deployment 的 Revision 历史
kubectl rollout history deployment/nginx-deployment

# 输出示例
deployment.apps/nginx-deployment
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
3         <none>
注意: 默认情况下,Kubernetes 只保留 10 个 Revision。超过限制后,最旧的 Revision 会被自动清理。在生产环境中,建议根据回滚需求调整 revisionHistoryLimit 参数。

4.3 Revision 历史管理参数

参数 默认值 说明
revisionHistoryLimit 10 保留的 Revision 数量上限
change-cause 无 通过 annotation 记录变更原因
rollback-to 无 指定回滚的目标 Revision

4.4 更新策略与 Revision 关系图

更新策略与 Revision 历史关系 更新策略 RollingUpdate Recreate / OnDelete Revision 历史 Revision 1 (当前) Revision 2 Revision 3 Revision N 回滚操作 kubectl rollout undo helm rollback 指定 Revision 回滚 Revision 历史管理要点 • 每次 Pod 模板变更自动创建新 Revision • 默认保留 10 个 Revision,可通过 revisionHistoryLimit 调整 • 回滚操作本质是切换到指定 Revision 的 Pod 模板 • Helm 管理自己的 Release 版本,与 Kubernetes Revision 独立

4.5 三种资源的更新策略详解

4.5.1 Deployment 更新策略

Deployment 支持两种更新策略:

  • RollingUpdate(默认): 逐步替换旧 Pod,支持 maxSurge(最大超出期望副本数)和 maxUnavailable(最大不可用副本数)参数控制滚动速率。
  • Recreate: 先删除所有旧 Pod,再创建新 Pod,适用于无法同时运行两个版本的场景。
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  revisionHistoryLimit: 15  # 保留 15 个 Revision
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      annotations:
        kubernetes.io/change-cause: "升级到 nginx:1.21"  # 记录变更原因
    spec:
      containers:
      - name: nginx
        image: nginx:1.21

4.5.2 StatefulSet 更新策略

StatefulSet 支持两种更新策略:

  • RollingUpdate(默认): 按 Pod 序号从高到低逐个更新,保证有状态应用的顺序性。
  • OnDelete: 仅当手动删除 Pod 后才触发更新,适用于需要精确控制更新时机的场景。
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql
  replicas: 3
  revisionHistoryLimit: 10
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      partition: 0  # 分区更新,0 表示全部更新
  template:
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
分区更新: StatefulSet 支持 partition 参数,只有序号大于等于 partition 的 Pod 才会被更新。这在灰度发布和回滚中非常有用。

4.5.3 DaemonSet 更新策略

DaemonSet 支持两种更新策略:

  • RollingUpdate(默认): 逐节点更新 DaemonSet Pod,支持 maxSurge 和 maxUnavailable 参数。
  • OnDelete: 仅当手动删除 Pod 后才触发更新。
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
spec:
  revisionHistoryLimit: 5
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1  # 最多 1 个节点不可用
  template:
    spec:
      containers:
      - name: fluentd
        image: fluentd:v1.14

4.6 Revision 历史操作命令

操作 命令 说明
查看历史 kubectl rollout history deployment/<name> 列出所有 Revision 及变更原因
查看详情 kubectl rollout history deployment/<name> --revision=<N> 查看指定 Revision 的详细信息
回滚到上一版本 kubectl rollout undo deployment/<name> 回滚到上一个 Revision
回滚到指定版本 kubectl rollout undo deployment/<name> --to-revision=<N> 回滚到指定 Revision
查看回滚状态 kubectl rollout status deployment/<name> 监控回滚进度

4.7 Revision 历史与 Helm Release 的关系

Helm Release 与 Kubernetes Revision 关系 Helm Release 版本 Release 1 Release 2 Release 3 Kubernetes Revision Rev 1 Rev 2 Rev 3 关键理解 • 一个 Helm Release 可能对应多个 Kubernetes Revision(多次 helm upgrade) • Helm 回滚操作会触发 Kubernetes 创建新的 Revision,而不是直接跳转到历史 Revision

4.8 回滚策略设计建议

最佳实践:
  • 设置合理的 revisionHistoryLimit,建议 15-20 个,平衡存储与回滚需求
  • 使用 change-cause annotation 记录每次变更原因,便于快速定位回滚目标
  • StatefulSet 优先使用分区更新进行灰度发布,降低回滚风险
  • DaemonSet 设置 maxUnavailable: 1 确保节点级回滚的稳定性
  • 定期清理无用的 Revision 历史,避免 Secret/ConfigMap 引用过期
常见陷阱:
  • Revision 历史被自动清理后,无法回滚到被清理的版本
  • Helm 回滚不会自动清理 Kubernetes 中多余的 Revision
  • StatefulSet 回滚时 Pod 序号不会重置,可能导致数据不一致
  • DaemonSet 回滚需要逐节点进行,耗时较长