Kubernetes 系列【11】控制器:Deployment(无状态部署控制器)

文章目录

  • 1. 概述
  • 2. 无状态应用
  • 3. 工作原理
    • 3.1 首次创建
    • 3.2 滚动更新发布
    • 3.3 故障自愈流程
    • 3.4 水平扩缩容
    • 3.5 版本回滚
  • 4. 运行状态
    • 4.1 发布中 Progressing
    • 4.2 发布完成 Complete
    • 4.3 发布失败 Failed
  • 5. 资源清单编写规范
    • 5.1 通用顶层基础规范
    • 5.2 更新策略
      • 5.2.1 Recreate 重建更新
      • 5.2.2 RollingUpdate 滚动更新(默认)
    • 5.3 扩展配置字段
    • 5.4 历史版本清理策略

1. 概述

DeploymentK8s 最常用的控制器,专门管理无状态应用,比如,NginxSpringBoot后端、网关等。

Deployment不直接管理Pod,而是创建、管理多个ReplicaSet,由ReplicaSet真正管控Pod副本。ReplicaSet提供副本维持标签筛选管控缩容清理等能力。

核心能力:

  • 故障自愈:持续比对replicas期望副本数,Pod异常丢失时自动新建补齐,无需人工操作。
  • 水平扩缩容:修改spec.replicas手动调整实例,搭配HPA可基于指标自动弹性扩缩。
  • 滚动更新:更新配置生成新ReplicaSet,先启动新Pod就绪,再逐步销毁旧Pod,服务不中断。
  • 版本回滚:自动留存历史ReplicaSet,发布故障时一键切回稳定版本快速恢复业务。
  • 多版本历史留存:持久保存各发布版本ReplicaSet,用于发布记录追溯、故障复盘。布对应的ReplicaSet,支持查看历次发布配置、Pod版本,用于发布记录追溯、故障复盘。

✅ 适合:无状态应用,业务无本地持久化数据,数据存外部Redis/MySQL

❌ 不适合:有状态业务,MySQLRedis集群、ZooKeeper等,这类业务使用StatefulSet

注意:请勿手动管理Deployment所属的ReplicaSet。如果你的业务场景不在本文覆盖范围内,可以前往Kubernetes官方代码仓库提交issue

2. 无状态应用

无状态应用Stateless Application)指服务实例本身不保存用户会话、业务上下文与持久业务数据,单次请求不依赖上一次请求留存的信息,所有状态数据统一交由数据库、缓存等外部组件存储,各实例完全对等、可任意替换的应用程序。

关键特征:

  1. 无本地存储依赖:不在容器/服务器本地磁盘存业务数据、用户会话、缓存;本地磁盘仅放程序二进制、日志(日志可收集到外部)。
  2. 请求独立无上下文绑定:用户第一次请求到实例 A ,第二次调度到实例 B ,结果完全一致,不需要粘滞会话。
  3. 实例完全可替换:任意销毁、新增、重启实例,业务不受影响;扩容缩容简单。
  4. 水平扩展友好:直接多副本部署,负载均衡分发流量。
  5. 故障自愈成本低:实例挂了,调度器直接新建Pod顶替,无需同步状态。

和有状态应用对比:

维度无状态应用有状态应用(StatefulSet)
数据存储数据外置(DB/Redis)本地持久卷、实例专属存储
实例标识无固定身份,随机Pod名稳定网络标识、有序域名
扩缩容随时增减,无序有序创建/删除,有启动顺序
典型组件Nginx、SpringBoot接口、微服务网关MySQL、Redis集群、Zookeeper、Elasticsearch

无状态典型例子:

  • 后端API服务(SpringBootNode.js接口)
  • 静态资源服务器Nginx
  • 网关、鉴权服务、定时任务worker
  • 图片处理、文件转换临时服务

不属于无状态(有状态)典型例子:

  • 单机MySQLRedis本地持久化集群
  • 分布式注册中心ZooKeeperetcd
  • 需要本地持久卷存数据的中间件

云原生K8s无状态应用最佳实践:

  1. 配置、密钥外置:使用ConfigMapSecret,不打包进镜像
  2. 持久数据全部外置:会话存Redis,业务数据存数据库
  3. 日志输出:由EFK/Loki统一采集,不落地本地盘
  4. 不使用本地缓存做持久会话
  5. 使用Deployment部署,多副本,随时滚动更新、重启
  6. 健康检查只校验服务端口/接口,不依赖本地数据

3. 工作原理

极简流程总结:

  • 初次创建Deployment→ 生成ReplicaSet-v1ReplicaSet创建指定数量Pod,维持副本稳定。
  • 滚动更新:修改Pod模板 → 新建ReplicaSet-v2→ 分批启动新Pod、销毁旧Pod,零停机切换。
  • 故障自愈Pod异常消失 → 对应ReplicaSet自动新建Pod,补齐replicas数量。
  • 水平扩缩容:调整spec.replicas→ 活跃ReplicaSet增减Pod,实现弹性扩容缩容。
  • 版本回滚:指定历史版本 → 切换至旧ReplicaSet→ 逐步下线新版本Pod,恢复业务。

3.1 首次创建

  1. 用户提交DeploymentYAML声明期望状态replicas副本数、Pod模板、更新策略等;
  2. APIServer存储资源对象至etcdDeployment控制器持续监听资源变更;
  3. Deployment控制器检测到无对应ReplicaSet,自动创建第一个副本集ReplicaSet-v1
  4. ReplicaSet-v1执行调谐循环,根据标签匹配创建对应数量Pod
  5. 持续循环校验ReplicaSet保证Pod数量等于配置副本数,完成初始部署。

3.2 滚动更新发布

  1. 修改DeploymentPod模板(镜像、环境变量、资源限制等)并提交;
  2. Deployment控制器感知配置变更,生成全新副本集ReplicaSet-v2
  3. 控制器按更新策略(maxSurge/maxUnavailable)执行分步调度:
    • 先扩容新版本ReplicaSet-v2,启动新Pod,等待就绪探针就绪;
    • 逐步缩容旧版本ReplicaSet-v1,删除旧Pod
  4. 交替完成新旧实例切换,全过程新旧Pod并行,业务不中断;
  5. 更新完成后保留历史ReplicaSet-v1,用于后续版本回滚。

3.3 故障自愈流程

  1. Node节点故障、Pod OOMPod被驱逐,导致运行Pod数量少于replicas
  2. 对应ReplicaSet实时比对期望副本数与实际Pod数量,发现差值;
  3. ReplicaSet自动新建同规格Pod,补齐至目标副本数;
  4. Deployment无需干预,由底层ReplicaSet完成自愈动作。

3.4 水平扩缩容

  1. 修改Deploymentspec.replicas数值;
  2. Deployment将副本数同步给所有关联ReplicaSet
  3. 当前活跃版本的ReplicaSet根据差值新增/删除Pod,完成扩容/缩容;
  4. 搭配HPA时可自动触发该流程,基于监控指标动态调整副本。

3.5 版本回滚

  1. 执行回滚命令,指定历史稳定版本;
  2. Deployment控制器切换活跃副本集为历史ReplicaSet-v1
  3. 逐步缩容新版本ReplicaSet-v2,扩容旧版本ReplicaSet-v1
  4. 完成新旧Pod切换,业务快速恢复至发布前状态。

HPA全称Horizontal Pod Autoscaler,中文:Pod水平自动扩缩控制器,它会根据指定指标,自动管理所有实现了scale子资源的资源对象的副本数量。是扩缩控制器,只负责自动修改副本数,不运行任何业务容器、不产生Pod,因此不属于工作负载。

4. 运行状态

Deployment发布生命周期分为三种核心状态:

  • 发布中Progressing
  • 发布完成Complete
  • 发布停滞Failed

4.1 发布中 Progressing

触发场景(任意一种即进入该状态):

  1. 创建全新ReplicaSet(首次部署/镜像更新)
  2. 扩容当前最新ReplicaSet
  3. 缩容历史旧ReplicaSet
  4. Pod就绪,且稳定运行满足minReadySeconds

控制器在status.conditions写入状态标识:type: Progressing, status: True

4.2 发布完成 Complete

全部条件同时满足才判定发布完成:

  1. 所有Pod已更新至最新Pod模板
  2. 全部副本标记为可用Available
  3. 集群无旧版本Pod运行

状态标识:Progressing: True,reason: NewReplicaSetAvailable,该状态会持续保留,直到下一次更新触发。

4.3 发布失败 Failed

发布超时无法完成,进入停滞失败状态。

常见故障诱因:镜像拉取失败、就绪探针故障、资源配额不足、权限缺失、容器参数异常、镜像名称错误。

超时控制:

  • spec.progressDeadlineSeconds发布超时阈值,默认600秒(10分钟);
  • 超时后:Progressing: False,reason: ProgressDeadlineExceeded

关键说明:

  1. Kubernetes仅标记失败状态,不会自动回滚,需上层CI/CD工具监听状态实现自动回滚;
  2. Deployment处于paused: true暂停状态时,不计算发布超时;
  3. 临时故障修复后,控制器自动继续发布,状态恢复正常;
  4. 命令执行失败返回非0退出码1

发布失败不限制操作,支持:扩缩容、版本回滚、暂停发布、修改Pod模板。

5. 资源清单编写规范

Nginx Deployment模板(覆盖全部规约字段)示例:

# Deployment API 稳定版本apiVersion:apps/v1# 资源类型固定Deploymentkind:Deploymentmetadata:name:nginx-deploymentlabels:app:nginxspec:# 期望运行副本数,可选,默认1replicas:3# 标签选择器,创建后不可修改,必须匹配template标签selector:matchLabels:app:nginx# Pod模板,spec内必填项template:metadata:labels:app:nginx# 与selector标签严格一致spec:# 重启策略仅允许AlwaysrestartPolicy:Alwayscontainers:-name:nginximage:nginx:1.24-alpineports:-containerPort:80# 滚动更新策略配置strategy:type:RollingUpdaterollingUpdate:maxUnavailable:1maxSurge:1# Pod就绪后稳定5秒才算可用minReadySeconds:5# 发布超时10分钟progressDeadlineSeconds:600# 保留5个历史版本用于回滚revisionHistoryLimit:5# 不暂停发布,修改模板自动触发更新paused:false

5.1 通用顶层基础规范

所有K8s资源通用三要素:apiVersionkindmetadata

核心配置段spec不可省略:

  1. spec内两个强制字段:spec.templatePod模板、spec.selector标签筛选器;
  2. Pod模板语法与独立Pod完全一致,无需填写apiVersion/kind
  3. Pod模板强制配置标签、重启策略;restartPolicy仅允许Always(默认);
  4. spec.replicas可选,期望副本数,默认1
  5. selector约束:必须与Pod模板标签完全匹配;创建后不可修改;禁止多控制器共用同一selector,避免争抢Pod

5.2 更新策略

spec.strategy.type二选一:Recreate/RollingUpdate(默认滚动更新)

5.2.1 Recreate 重建更新

逻辑:先销毁全部旧Pod,再创建新版本Pod

缺点:发布期间服务完全中断;

补充:手动删除Pod时,ReplicaSet会立刻重建,不会等待旧Pod终止;若需要严格限制最大实例数,选用StatefulSet

5.2.2 RollingUpdate 滚动更新(默认)

两个核心参数控制发布节奏:

  • maxUnavailable:更新期间最大不可用副本;支持数值/百分比,百分比向下取整,默认25%
  • maxSurge:发布峰值可额外扩容的副本;支持数值/百分比,百分比向上取整,默认25%

5.3 扩展配置字段

扩展配置字段说明:

  1. progressDeadlineSeconds:发布超时秒数,数值必须大于minReadySeconds
  2. minReadySecondsPod就绪后稳定运行时长,达标才判定可用,默认0
  3. terminatingReplicasv1.35 Beta,默认开启)
    • 开启特性门控DeploymentReplicaSetTerminatingReplicas
    • 缩容删除Pod进入Terminating销毁阶段,短期总Pod数会临时超过replicas
    • Deploymentstatus中查看正在销毁的实例数量。
  4. paused:布尔值,true=暂停发布,修改Pod模板不会触发滚动更新;false=正常发布。

5.4 历史版本清理策略

spec.revisionHistoryLimit:控制保留可回滚的旧 ReplicaSet 数量,超出自动 GC 回收,默认10

  1. 设为0:全部清理历史副本集,无法执行回滚
  2. 长期卡住的发布,历史ReplicaSet数量可能临时超出该阈值。

查看历史版本命令:

kubectl rollouthistorydeployment/nginx-deployment# 回滚到指定版本kubectl rollout undo deployment/nginx-deployment --to-revision=2