K8s 中的 Deployment 滚动更新与回滚操作

好的,各位观众,各位朋友,欢迎来到今天的“K8s那些事儿”讲座!我是你们的老朋友,江湖人称“代码诗人”的李白(当然,我只会写代码,不会写诗,但梦想还是要有的,万一实现了呢?)。

今天我们要聊聊K8s里一个非常重要,也很有趣的话题:Deployment 的滚动更新与回滚。这就像给你的在线服务做一次“换装秀”,既要保证时尚度(新功能),又要避免“车祸现场”(服务挂掉)。准备好了吗?让我们一起揭开它的神秘面纱!

一、 什么是Deployment?为什么我们需要它?

首先,我们得搞清楚Deployment是个什么东西。你可以把它想象成一个乐队的“经纪人”。这个“经纪人”负责:

  • 管理乐队的成员(Pod): 告诉K8s,我需要几个Pod,他们应该运行什么镜像。
  • 保持乐队的活力(副本数): 确保始终有指定数量的Pod在运行,一旦有Pod“罢工”(挂掉),立刻拉一个新的来顶替。
  • 策划乐队的转型(更新策略): 当乐队需要改变风格(更新镜像)时,Deployment会负责平稳地进行过渡,尽量不影响演出效果(服务可用性)。

如果没有Deployment,你就要手动创建、管理Pod,想想都觉得头大!手动扩容、缩容、更新,简直就是噩梦。有了Deployment,我们就可以用声明式的方式来管理应用,K8s会负责搞定一切细节。这就像从“手扶拖拉机”升级到了“自动驾驶汽车”,效率提升N个数量级!

二、 滚动更新:时尚换装,平稳过渡

滚动更新,顾名思义,就是像滚雪球一样,逐步替换旧版本的Pod,用新版本的Pod来接替它们的工作。这就像给你的服务做一次“微整形”,一点一点地改变,尽量不让用户察觉。

1. 滚动更新的原理

滚动更新的核心在于两个参数:maxSurgemaxUnavailable。这两个参数决定了更新过程中,最多可以超出期望副本数的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. 滚动更新的过程

滚动更新的大致过程如下:

  1. K8s创建一个新的ReplicaSet,它使用新的Pod模板。
  2. K8s逐步增加新ReplicaSet中的Pod数量,同时逐步减少旧ReplicaSet中的Pod数量。
  3. 当新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大师!

感谢大家的观看,我们下期再见! 🚀

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注