好的,各位观众,各位朋友,欢迎来到今天的“K8s那些事儿”讲座!我是你们的老朋友,江湖人称“代码诗人”的李白(当然,我只会写代码,不会写诗,但梦想还是要有的,万一实现了呢?)。
今天我们要聊聊K8s里一个非常重要,也很有趣的话题:Deployment 的滚动更新与回滚。这就像给你的在线服务做一次“换装秀”,既要保证时尚度(新功能),又要避免“车祸现场”(服务挂掉)。准备好了吗?让我们一起揭开它的神秘面纱!
一、 什么是Deployment?为什么我们需要它?
首先,我们得搞清楚Deployment是个什么东西。你可以把它想象成一个乐队的“经纪人”。这个“经纪人”负责:
- 管理乐队的成员(Pod): 告诉K8s,我需要几个Pod,他们应该运行什么镜像。
- 保持乐队的活力(副本数): 确保始终有指定数量的Pod在运行,一旦有Pod“罢工”(挂掉),立刻拉一个新的来顶替。
- 策划乐队的转型(更新策略): 当乐队需要改变风格(更新镜像)时,Deployment会负责平稳地进行过渡,尽量不影响演出效果(服务可用性)。
如果没有Deployment,你就要手动创建、管理Pod,想想都觉得头大!手动扩容、缩容、更新,简直就是噩梦。有了Deployment,我们就可以用声明式的方式来管理应用,K8s会负责搞定一切细节。这就像从“手扶拖拉机”升级到了“自动驾驶汽车”,效率提升N个数量级!
二、 滚动更新:时尚换装,平稳过渡
滚动更新,顾名思义,就是像滚雪球一样,逐步替换旧版本的Pod,用新版本的Pod来接替它们的工作。这就像给你的服务做一次“微整形”,一点一点地改变,尽量不让用户察觉。
1. 滚动更新的原理
滚动更新的核心在于两个参数:maxSurge
和 maxUnavailable
。这两个参数决定了更新过程中,最多可以超出期望副本数的Pod数量,以及最多可以有多少Pod不可用。
maxSurge
: 允许超过期望副本数的最大Pod数量。比如,如果你设置了maxSurge: 1
,并且期望副本数是3,那么在更新过程中,最多可以有4个Pod同时运行(3个旧版本 + 1个新版本,或者2个旧版本 + 2个新版本)。maxUnavailable
: 允许的最大不可用Pod数量。比如,如果你设置了maxUnavailable: 1
,并且期望副本数是3,那么在更新过程中,至少要有2个Pod是可用的。
用表格来更清晰地展示一下:
参数 | 含义 | 例子 (期望副本数=3) |
---|---|---|
maxSurge: 1 |
允许超过期望副本数的最大Pod数量 | 最多可以有4个Pod同时运行 (3+1) |
maxUnavailable: 1 |
允许的最大不可用Pod数量 | 至少要有2个Pod可用 (3-1) |
maxSurge: 25% |
允许超过期望副本数的百分比。如果期望副本数是4,那么maxSurge 最大值为 1 (4 * 25% = 1) |
最多可以有5个Pod同时运行 (4+1) |
maxUnavailable: 25% |
允许的最大不可用Pod数量的百分比。如果期望副本数是4,那么maxUnavailable 最大值为 1 (4 * 25% = 1) |
至少要有3个Pod可用 (4-1) |
2. 如何触发滚动更新?
触发滚动更新非常简单,只需要修改Deployment的Pod模板(例如,修改镜像版本),然后应用更新后的Deployment配置即可。K8s会自动检测到配置的变化,并开始滚动更新。
例如,我们有一个名为my-app
的Deployment,它的配置如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: nginx:1.21
ports:
- containerPort: 80
现在,我们要将镜像版本从nginx:1.21
升级到nginx:1.23
。只需要修改image
字段,然后执行kubectl apply -f deployment.yaml
即可。
3. 滚动更新的过程
滚动更新的大致过程如下:
- K8s创建一个新的ReplicaSet,它使用新的Pod模板。
- K8s逐步增加新ReplicaSet中的Pod数量,同时逐步减少旧ReplicaSet中的Pod数量。
- 当新ReplicaSet中的Pod数量达到期望值时,旧ReplicaSet中的所有Pod都被删除。
可以用一个简单的示意图来表示:
+-------------------+ +-------------------+ +-------------------+
| 旧ReplicaSet (v1) | --> | 旧ReplicaSet (v1) | --> | 新ReplicaSet (v2) |
| 3 Pods | | 2 Pods | | 3 Pods |
+-------------------+ +-------------------+ +-------------------+
/| /|
| |
| |
|/ |/
+-------------------+ +-------------------+ +-------------------+
| 新ReplicaSet (v2) | --> | 新ReplicaSet (v2) | --> | (完成) |
| 0 Pods | | 1 Pod | | |
+-------------------+ +-------------------+ +-------------------+
4. 滚动更新的策略
Deployment提供了两种更新策略:
- RollingUpdate (默认): 逐步替换旧版本的Pod,保证服务可用性。
- Recreate: 先删除所有旧版本的Pod,再创建新版本的Pod。这种策略会造成短暂的服务中断。
通常情况下,我们都使用RollingUpdate
策略,因为它更加平滑,可以最大限度地减少对用户的影响。
三、 回滚:时光倒流,重回正轨
人生不如意事十之八九,代码也一样。有时候,我们兴高采烈地发布了一个新版本,结果却发现它Bug百出,甚至导致服务崩溃。这时候,就需要用到回滚操作了。
回滚操作就像“时光倒流”,它可以让我们快速回到之前的稳定版本,避免更大的损失。
1. 什么是Revision History?
K8s会记录Deployment的每一次更新,并将它们保存在Revision History中。你可以把Revision History想象成一个“版本控制系统”,它可以让你随时查看、比较、回滚到之前的版本。
2. 如何查看Revision History?
可以使用kubectl rollout history deployment/<deployment-name>
命令来查看Deployment的Revision History。
例如:
kubectl rollout history deployment/my-app
输出结果可能如下:
deployment.apps/my-app
REVISION CHANGE-CAUSE
1 <none>
2 <none>
3 <none>
REVISION
列表示版本号,CHANGE-CAUSE
列表示更新的原因。默认情况下,K8s会保留最近的10个Revision。
3. 如何回滚到之前的版本?
可以使用kubectl rollout undo deployment/<deployment-name> --to-revision=<revision-number>
命令来回滚到指定的版本。
例如,要回滚到版本2,可以执行以下命令:
kubectl rollout undo deployment/my-app --to-revision=2
执行完这个命令后,K8s会自动将Deployment回滚到版本2,并开始滚动更新。
4. 如何禁用Revision History?
如果你不想保留Revision History,可以将spec.revisionHistoryLimit
设置为0。但这通常是不建议的,因为回滚功能非常有用,尤其是在生产环境中。
四、 滚动更新与回滚的实践技巧
掌握了理论知识,接下来我们来聊聊一些实践技巧,让你的滚动更新与回滚操作更加高效、安全。
1. 健康检查:确保Pod的健康
在滚动更新过程中,K8s会根据健康检查的结果来判断Pod是否可用。如果Pod的健康检查失败,K8s会将它标记为不可用,并停止流量转发。
因此,为你的Pod配置合适的健康检查非常重要。通常,我们会配置两种健康检查:
- Liveness Probe: 用于判断Pod是否存活。如果Liveness Probe失败,K8s会重启Pod。
- Readiness Probe: 用于判断Pod是否准备好接收流量。如果Readiness Probe失败,K8s会将Pod从Service中移除,停止流量转发。
例如,以下是一个带有Liveness Probe和Readiness Probe的Pod配置:
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: my-app
image: nginx:1.23
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 3
periodSeconds: 3
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 3
periodSeconds: 3
2. 灰度发布:小步快跑,降低风险
灰度发布,也称为金丝雀发布,是一种逐步将新版本推向用户的策略。你可以先将新版本部署到一小部分用户,观察它的表现,如果一切正常,再逐步扩大发布范围。
灰度发布可以帮助你及早发现问题,降低风险。K8s本身并没有提供内置的灰度发布功能,但你可以借助Service Mesh(例如Istio)来实现。
3. 监控与告警:及时发现问题
在滚动更新和回滚过程中,我们需要密切关注服务的状态,及时发现问题。可以使用Prometheus、Grafana等工具来监控服务的指标,并设置告警规则。
例如,你可以监控服务的请求延迟、错误率、CPU利用率等指标,一旦出现异常,立即收到告警通知。
4. 模拟演练:防患于未然
“纸上谈兵终觉浅,绝知此事要躬行”。在生产环境进行滚动更新和回滚之前,最好先在测试环境中进行模拟演练。这样可以帮助你熟悉操作流程,发现潜在问题,避免在生产环境中出现意外。
5. 记录更新原因:方便追踪问题
在每次更新Deployment时,最好记录更新的原因。这样可以方便你追踪问题,了解每个版本的变化。可以使用kubectl annotate deployment/<deployment-name> kubernetes.io/change-cause="<reason>"
命令来添加更新原因。
例如:
kubectl annotate deployment/my-app kubernetes.io/change-cause="Fix critical bug in authentication module"
五、 总结:掌握滚动更新与回滚,成为K8s大师
今天,我们一起学习了K8s Deployment的滚动更新与回滚操作。希望通过今天的讲解,你能够更好地理解它们的原理,掌握它们的技巧,并在实际工作中灵活运用。
记住,滚动更新就像给服务做一次“换装秀”,既要保证时尚度(新功能),又要避免“车祸现场”(服务挂掉)。回滚操作就像“时光倒流”,可以让你快速回到之前的稳定版本,避免更大的损失。
掌握了滚动更新与回滚,你就可以更加自信地管理你的K8s集群,成为真正的K8s大师!
感谢大家的观看,我们下期再见! 🚀