【K8s-Day 22】深入解析 Kubernetes Deployment:现代应用部署的基石与滚动更新的艺术
Langchain系列文章目录
01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
08-【万字长文】MCP深度解析:打通AI与世界的“USB-C”,模型上下文协议原理、实践与未来
Python系列文章目录
PyTorch系列文章目录
机器学习系列文章目录
深度学习系列文章目录
Java系列文章目录
JavaScript系列文章目录
Python系列文章目录
Go语言系列文章目录
Docker系列文章目录
01-【Docker-Day 1】告别部署噩梦:为什么说 Docker 是每个开发者的必备技能?
02-【Docker-Day 2】从零开始:手把手教你在 Windows、macOS 和 Linux 上安装 Docker
03-【Docker-Day 3】深入浅出:彻底搞懂 Docker 的三大核心基石——镜像、容器与仓库
04-【Docker-Day 4】从创建到删除:一文精通 Docker 容器核心操作命令
05-【Docker-Day 5】玩转 Docker 镜像:search, pull, tag, rmi 四大金刚命令详解
06-【Docker-Day 6】从零到一:精通 Dockerfile 核心指令 (FROM, WORKDIR, COPY, RUN)
07-【Docker-Day 7】揭秘 Dockerfile 启动指令:CMD、ENTRYPOINT、ENV、ARG 与 EXPOSE 详解
08-【Docker-Day 8】高手进阶:构建更小、更快、更安全的 Docker 镜像
09-【Docker-Day 9】实战终极指南:手把手教你将 Node.js 应用容器化
10-【Docker-Day 10】容器的“持久化”记忆:深入解析 Docker 数据卷 (Volume)
11-【Docker-Day 11】Docker 绑定挂载 (Bind Mount) 实战:本地代码如何与容器实时同步?
12-【Docker-Day 12】揭秘容器网络:深入理解 Docker Bridge 模式与端口映射
13-【Docker-Day 13】超越默认Bridge:精通Docker Host、None与自定义网络模式
14-【Docker-Day 14】Docker Compose深度解析
15-【Docker-Day 15】一键部署 WordPress!Docker Compose 实战终极指南
16-【Docker-Day 16】告别单机时代:为什么 Docker Compose 不够用,而你需要 Kubernetes?
17-【Docker-Day 17】K8s 架构全解析:深入理解 Kubernetes 的大脑 (Master) 与四肢 (Node)
18-【Docker-Day 18】告别选择困难症:一文掌握 Minikube、kind、k3d,轻松搭建你的第一个 K8s 集群
19-【Docker-Day 19】万物皆 YAML:掌握 Kubernetes 声明式 API 的艺术
20-【Docker-Day 20】揭秘 Kubernetes 的原子单位:深入理解 Pod
21-【Docker-Day 21】Pod的守护神:ReplicaSet与ReplicationController,轻松实现应用高可用
22-【K8s-Day 22】深入解析 Kubernetes Deployment:现代应用部署的基石与滚动更新的艺术
文章目录
- Langchain系列文章目录
- Python系列文章目录
- PyTorch系列文章目录
- 机器学习系列文章目录
- 深度学习系列文章目录
- Java系列文章目录
- JavaScript系列文章目录
- Python系列文章目录
- Go语言系列文章目录
- Docker系列文章目录
- 摘要
- 一、从 ReplicaSet 到 Deployment:为什么需要 Deployment?
- 1.1 回顾 ReplicaSet 的局限性
- 1.2 Deployment 的诞生:声明式应用管理的王者
- 1.3 Deployment、ReplicaSet 与 Pod 的关系
- 二、Deployment 核心实践:创建与管理
- 2.1 编写第一个 Deployment YAML 文件
- 2.1.1 YAML 文件关键字段解析
- 2.2 部署与验证
- (1)查看 Deployment 状态
- (2)查看 ReplicaSet
- (3)查看 Pod
- 三、应用生命周期的核心:滚动更新 (Rolling Update)
- 3.1 什么是滚动更新?
- 3.2 触发一次滚动更新
- 3.3 监控更新过程
- 3.4 控制滚动更新的速度:`maxSurge` 与 `maxUnavailable`
- 四、救命稻草:应用回滚
- 4.1 为什么要回滚?
- 4.2 查看更新历史
- 4.3 执行回滚操作
- (1)回滚到上一个版本
- (2)回滚到指定版本
- 4.4 回滚的背后原理
- 五、总结
摘要
在 Kubernetes 的世界里,如果说 Pod 是构建应用的“砖块”,那么 Deployment 就是指挥工匠如何砌墙并进行翻新维护的“总工程师”。作为 Kubernetes 中最核心、最常用的资源对象之一,Deployment 为我们提供了管理无状态应用(Stateless Application)的强大能力。它不仅能确保应用实例的高可用性,更重要的是,它引入了声明式的更新和回滚机制,彻底改变了我们对应用生命周期管理的认知。本文将从 ReplicaSet 的局限性出发,深入剖析 Deployment 的核心概念、工作原理,并通过详尽的实战示例,带你掌握如何使用 Deployment 实现应用的平滑滚动更新与一键回滚,为你的应用穿上“不死”与“不老”的铠甲。
一、从 ReplicaSet 到 Deployment:为什么需要 Deployment?
在上一篇文章中,我们学习了 ReplicaSet,它能够像一个忠诚的管家,时刻确保集群中运行着指定数量的 Pod 副本,实现了应用的高可用。但这位管家也有其力所不及之处,尤其是在面对应用“升级”这一核心运维场景时。
1.1 回顾 ReplicaSet 的局限性
ReplicaSet 的核心职责是“维稳”,即维持 Pod 副本数量的稳定。假设我们有一个运行着 app:v1
版本的 ReplicaSet,现在需要将其升级到 app:v2
。使用 ReplicaSet 我们该怎么做呢?
通常,我们需要手动执行以下步骤:
- 创建一个新的 ReplicaSet,其 Pod 模板使用
app:v2
镜像。 - 手动将新的 ReplicaSet 的副本数从 0 逐渐增加。
- 同时,手动将旧的 ReplicaSet 的副本数逐渐减少。
- 等待所有
v2
版本的 Pod 启动并运行正常后,将旧的 ReplicaSet 副本数减为 0,并最终删除它。
这个过程不仅繁琐、易出错,而且在更新过程中,我们需要小心翼翼地管理流量,以避免服务中断。这是一种典型的命令式操作,我们告诉 Kubernetes “如何做”,而不是“我们想要什么”。
1.2 Deployment 的诞生:声明式应用管理的王者
为了解决上述痛点,Deployment 应运而生。Deployment 是一个更高层次的抽象,它站在 ReplicaSet 的“肩膀”上,为其赋予了应用更新和历史版本管理的超能力。
使用 Deployment,我们不再需要关心底层的 ReplicaSet 是如何创建、扩容或缩容的。我们只需向 Deployment 声明(Declare) 我们期望的最终状态(Desired State),例如:“我需要 3 个副本,并且它们的应用版本是 app:v2
”。
Deployment 控制器会持续监控当前状态与我们声明的期望状态,一旦发现不一致,它会自动采取行动,智能地编排底层 ReplicaSet 和 Pod,使系统最终达到我们声明的状态。这正是 Kubernetes 声明式 API 的精髓所在。
一个生动的类比:
- ReplicaSet:像一位工头,他的任务就是确保工地上始终有 10 个工人在干活。如果有人累倒了,他会立刻找个新工人替上。但他不知道如何让工人们学习新技能(版本升级)。
- Deployment:像一位项目经理,他不仅告诉工头需要保持 10 个工人,还负责制定培训和轮换计划。当需要升级工人技能时,他会带一批掌握新技能的工人(
v2
),然后有条不紊地替换掉旧工人(v1
),整个过程对项目(服务)的进展影响最小。如果发现新技能有问题,他还能迅速让旧工人们回来返工(回滚)。
1.3 Deployment、ReplicaSet 与 Pod 的关系
Deployment 并不直接管理 Pod,而是通过管理 ReplicaSet 来间接控制 Pod。它们之间形成了一个清晰的层级关系。
- Deployment:定义应用的期望状态,包括副本数、Pod 模板(镜像版本、端口等)以及更新策略。
- ReplicaSet:由 Deployment 创建和管理,负责根据自身的 Pod 模板确保指定数量的 Pod 正常运行。Deployment 的每一次更新,通常都会创建一个新的 ReplicaSet。
- Pod:由 ReplicaSet 创建和管理,是应用运行的最终实体。
二、Deployment 核心实践:创建与管理
理论结合实践是最好的学习方式。现在,让我们动手创建一个 Deployment。
2.1 编写第一个 Deployment YAML 文件
我们将部署一个包含 3 个副本的 Nginx 服务。创建一个名为 nginx-deployment.yaml
的文件,内容如下:
# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deploymentlabels:app: nginx
spec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx:1.14.2 # 指定了 nginx 镜像的版本ports:- containerPort: 80
2.1.1 YAML 文件关键字段解析
apiVersion: apps/v1
:Deployment 资源对象当前稳定版本的 API 路径。kind: Deployment
:指明这是一个 Deployment 类型的资源。metadata
:元数据,包含 Deployment 的名称nginx-deployment
和标签labels
。spec
:定义了 Deployment 的期望状态,这是核心部分。replicas: 3
:声明我们期望有 3 个 Pod 副本。selector
:选择器,定义了此 Deployment 管理哪些 Pod。matchLabels
中的app: nginx
意味着它会寻找并管理所有带有app: nginx
标签的 Pod。template
:Pod 模板,这部分是 Deployment 创建新 Pod 的“蓝图”。metadata.labels
: Pod 模板中的标签。极其重要:这里的标签app: nginx
必须与spec.selector.matchLabels
中的标签匹配,否则 Deployment 会创建失败。spec.containers
: 定义了 Pod 中容器的配置,包括容器名nginx
、使用的镜像nginx:1.14.2
和暴露的端口80
。
2.2 部署与验证
现在,使用 kubectl
命令将这个 YAML 文件应用到集群中。
# 应用 YAML 文件创建 Deployment
$ kubectl apply -f nginx-deployment.yaml
deployment.apps/nginx-deployment created
创建成功后,我们可以通过一系列命令来验证部署状态。
(1)查看 Deployment 状态
$ kubectl get deployments
# 或者简写 kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 20s
输出列解析表:
列名 | 解释 |
---|---|
NAME | Deployment 的名称。 |
READY | 当前可用的副本数 / 期望的副本数 (current/desired )。3/3 表示已就绪。 |
UP-TO-DATE | 已更新到最新模板的副本数。 |
AVAILABLE | 当前可用的副本数。 |
AGE | Deployment 已创建的时间。 |
(2)查看 ReplicaSet
你会发现 Deployment 自动创建了一个 ReplicaSet。
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-7686485989 3 3 3 1m
这个 ReplicaSet 的名字由 Deployment 名称 nginx-deployment
加上一个随机的哈希值构成。
(3)查看 Pod
最后,查看由 ReplicaSet 创建的 Pod。
$ kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-7686485989-5qjjp 1/1 Running 0 2m app=nginx,pod-template-hash=7686485988
nginx-deployment-7686485989-j4k7l 1/1 Running 0 2m app=nginx,pod-template-hash=7686485988
nginx-deployment-7686485989-q8zcl 1/1 Running 0 2m app=nginx,pod-template-hash=7686485988
注意,Pod 的名称由 ReplicaSet 名称加上一个随机字符串构成,并且它们都带上了我们定义的 app: nginx
标签,以及一个由 Kubernetes 添加的 pod-template-hash
标签,用于区分不同版本的 ReplicaSet。
三、应用生命周期的核心:滚动更新 (Rolling Update)
Deployment 最强大的功能之一就是滚动更新,它能保证在应用升级过程中服务不中断。
3.1 什么是滚动更新?
滚动更新(Rolling Update)是一种逐个替换旧版本 Pod 为新版本 Pod 的策略。Kubernetes 会先创建一个新版本的 Pod,等它成功启动并准备好接收流量后,再销毁一个旧版本的 Pod。这个过程会一直持续,直到所有的旧 Pod 都被新 Pod 替换完毕。
这种方式的巨大优势在于,在整个更新过程中,始终有可用的 Pod 在提供服务,从而实现了**零停机时间(Zero Downtime)**的部署。
3.2 触发一次滚动更新
触发滚动更新最常见的方式就是修改 Deployment 的 Pod 模板 (spec.template
)。最典型的场景是更新容器镜像的版本。
我们将 nginx
的镜像从 1.14.2
更新到 1.16.1
。
方法一:声明式(推荐)
修改 nginx-deployment.yaml
文件:
# ... (其他部分不变) ...spec:containers:- name: nginximage: nginx:1.16.1 # <--- 修改这里的版本号
# ... (其他部分不变) ...
然后再次执行 apply
命令:
$ kubectl apply -f nginx-deployment.yaml
deployment.apps/nginx-deployment configured
方法二:命令式
对于快速测试或紧急修复,也可以使用 kubectl set image
命令:
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
deployment.apps/nginx-deployment image updated
这种方式虽然快捷,但不易于版本控制和追踪,在生产环境中推荐使用声明式的方式(即将 YAML 文件纳入 Git 管理)。
3.3 监控更新过程
在更新触发后,我们可以使用 rollout status
命令来实时监控进度。
$ kubectl rollout status deployment/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out
在更新过程中,新开一个终端查看 ReplicaSet 和 Pod,你会看到有趣的景象:
# 查看 ReplicaSet
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-7686485989 1 1 1 10m
nginx-deployment-559d575459 3 3 2 1m # <--- 新的 RS 正在扩容# 查看 Pod
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-7686485989-j4k7l 1/1 Running 0 10m # <--- 旧 Pod
nginx-deployment-559d575459-abcde 1/1 Running 0 1m # <--- 新 Pod
nginx-deployment-559d575459-fghij 1/1 Running 0 45s # <--- 新 Pod
nginx-deployment-559d575459-klmno 1/1 ContainerCreating 0 10s # <--- 新 Pod
nginx-deployment-7686485989-q8zcl 1/1 Terminating 0 10m # <--- 旧 Pod 正在被终止
这清晰地展示了新旧 ReplicaSet 的交替过程。
3.4 控制滚动更新的速度:maxSurge
与 maxUnavailable
Deployment 允许我们通过 spec.strategy.rollingUpdate
字段来精细控制滚动更新的行为。
maxSurge
:更新过程中,允许的超出期望副本数的最大 Pod 数量。可以是绝对数字(如1
)或百分比(如25%
)。默认值为25%
。maxUnavailable
:更新过程中,允许的最大不可用 Pod 数量。可以是绝对数字或百分比。默认值为25%
。
示例解析:
假设 replicas: 10
,并采用默认策略 (maxSurge: 25%
, maxUnavailable: 25%
)。
maxSurge
计算结果为ceil(10 * 0.25) = 3
。这意味着在更新过程中,集群中最多可以有10 + 3 = 13
个 Pod。Kubernetes 会先创建新的 Pod,再销毁旧的。maxUnavailable
计算结果为floor(10 * 0.25) = 2
。这意味着在更新过程中,必须保证至少有10 - 2 = 8
个 Pod 处于可用状态。
通过调整这两个参数,你可以在更新速度和资源消耗/服务稳定性之间做出权衡。
- 追求快速更新:可以适当调高
maxSurge
。 - 资源紧张或对服务稳定性要求极高:可以调低
maxSurge
并将maxUnavailable
设置为 0(这意味着必须先启动新 Pod 并就绪后,才能销毁旧 Pod)。
# ...
spec:replicas: 10strategy:type: RollingUpdaterollingUpdate:maxSurge: 1 # 每次最多只增加1个PodmaxUnavailable: 0 # 保证更新过程中可用Pod数量不低于10个
# ...
四、救命稻草:应用回滚
如果新发布的版本存在严重 Bug,Deployment 提供的回滚功能可以让你迅速恢复到上一个稳定版本,堪称“救命稻草”。
4.1 为什么要回滚?
回滚是应对发布失败的标准操作。常见的回滚场景包括:
- 新版本应用引入了严重的 Bug,导致程序崩溃 (
CrashLoopBackOff
)。 - 新版本存在性能问题,导致延迟升高或资源消耗激增。
- 配置错误,导致应用无法正常启动或连接到依赖服务。
4.2 查看更新历史
Deployment 会为每一次成功的更新(即 Pod 模板的变更)保存一个修订版本(Revision)。我们可以查看这些历史记录。
$ kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 <none> # 对应 nginx:1.14.2 版本
2 <none> # 对应 nginx:1.16.1 版本
专业提示:默认情况下
CHANGE-CAUSE
列是<none>
。你可以在执行kubectl apply
时加上--record
标志(已废弃但部分版本仍可用),或者在 Deployment 的metadata.annotations
中添加kubernetes.io/change-cause
来说明本次变更的原因,这对于追踪历史非常有帮助。
4.3 执行回滚操作
回滚操作非常简单。
(1)回滚到上一个版本
这是最常用的回滚命令。
$ kubectl rollout undo deployment/nginx-deployment
deployment.apps/nginx-deployment rolled back
执行后,Deployment 会将 Pod 模板恢复到 REVISION 1
的状态,并再次触发一次“滚动更新”,将 nginx:1.16.1
的 Pod 替换回 nginx:1.14.2
。
(2)回滚到指定版本
如果你想跳过某个版本,直接回滚到更早的版本,可以指定 --to-revision
。
$ kubectl rollout undo deployment/nginx-deployment --to-revision=1
deployment.apps/nginx-deployment rolled back
4.4 回滚的背后原理
回滚的实现机制非常巧妙。它本质上是利用 Deployment 的更新机制来完成的。当你执行 rollout undo
时,Kubernetes 做了以下事情:
- 从历史版本中找到你指定的回滚目标版本(如
REVISION 1
)的 Pod 模板。 - 将 Deployment 的
spec.template
修改为这个旧的 Pod 模板。 - 这个修改行为本身又触发了一次标准的滚动更新流程。
- 于是,Kubernetes 创建了一个新的 ReplicaSet(其模板是旧版本的),并逐步替换掉当前运行中的、有问题的 Pod。
理解了这一点,你就会明白,回滚并非什么“黑魔法”,而是对 Deployment 核心能力的复用,整个过程同样是平滑和受控的。
五、总结
经过本文的深入学习,我们掌握了 Kubernetes 中应用管理的基石——Deployment。现在,让我们回顾一下核心要点:
- Deployment 的核心价值:Deployment 是 Kubernetes 中管理无状态应用的标准方式,它建立在 ReplicaSet 之上,提供了声明式的应用生命周期管理能力,解决了 ReplicaSet 无法直接处理应用更新的痛点。
- 层级管理关系:Deployment 通过管理 ReplicaSet,再由 ReplicaSet 管理 Pod,形成了一个清晰、可靠的控制链。每一次应用更新,Deployment 都会创建一个新的 ReplicaSet 来管理新版 Pod。
- 滚动更新(Rolling Update):这是 Deployment 的标志性功能,通过逐个替换 Pod 的方式,实现了零停机时间的应用升级。其更新速度和策略可以通过
maxSurge
和maxUnavailable
参数进行精细化控制。 - 版本历史与回滚(Rollback):Deployment 会记录每次更新的修订历史,当新版本出现问题时,可以通过
kubectl rollout undo
命令快速、安全地回滚到之前的稳定版本,为生产环境的稳定性提供了强有力的保障。
掌握 Deployment 是精通 Kubernetes 的必经之路。它将运维人员从繁琐、易错的手动更新流程中解放出来,让我们能够更加从容、自信地进行应用发布和迭代。在后续的文章中,我们将学习如何通过 Service 将我们部署的应用暴露给外界访问。