当集群中的某个服务需要升级时,我们需要停止目前与该服务相关的所有 Pod ,然后下载新版本镜像井创建新的 Pod 如果集群规模比较大,则这个工作就变成了一个挑战,而且先全部停止然后逐步升级的方式会导致较长时间的服务不可用 Kubernetes 提供了滚动升级功能来解决上述问题。

如果 Pod 是通过 Deployment 建的,则用户可以在运行时修改 Deployment的Pod 定义(spec.template )或镜像名称 ,井应用到 Deployment 对象上,系统即可完成 Deployment 的自动更新操作。如果在更新过程中发生了错误, 则还可以通过回滚( Rollback )操作恢复 Pod的版本。

一、Deployment升级

Deployment nginx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#nginx-deployment.yaml 
apiVersion: apps/v1beta1
kind : Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
template :
metadata:
labels:
app: nginx
spec:
containers :
- name : nginx
image : nginx:1.7.9
ports:
- containerPort : 80

将nginx更新为1.9.1,通过kubectl set image命令为Deployment设置新的镜像

1
2
3
4
5
6
#通过命令行修改
kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
#deployment.apps/nginx-deployment image updated

#修改yaml,将 spec.template.spec.containers[O].image从Nginx:1.7.9 更改为 Nginx:1.9.1:
kubectl edit deployment/nginx-deployment

升级会触发Pod的滚动升级操作

1
2
kubectl rollout status deployment/nginx-deployment
#deployment "nginx-deployment" successfully rolled out

二、Deployment升级过程

更新过程

1
2
3
4
5
6
7
kubectl describe deployments nginx-deployment
Normal ScalingReplicaSet 5m35s deployment-controller Scaled up replica set nginx-deployment-6b47b865d4 to 1
Normal ScalingReplicaSet 4m32s deployment-controller Scaled down replica set nginx-deployment-f75bf47d to 2
Normal ScalingReplicaSet 4m32s deployment-controller Scaled up replica set nginx-deployment-6b47b865d4 to 2
Normal ScalingReplicaSet 4m29s deployment-controller Scaled down replica set nginx-deployment-f75bf47d to 1
Normal ScalingReplicaSet 4m29s deployment-controller Scaled up replica set nginx-deployment-6b47b865d4 to 3
Normal ScalingReplicaSet 4m27s deployment-controller Scaled down replica set nginx-deployment-f75bf47d to 0

初始创 Deployment 时, 系统创建了一 ReplicaSet求创建了 Pod 副本,当更新 Deployment 系统 建了一个新 ReplicaSet并将其副本数扩展 然后将旧的 ReplicaSet缩减为 2。之后,系统按照相同策略对新旧两个RepilcaSet进行调整。

image-20211101231803150

查看2个ReplicaSet状态

1
2
3
kubectl get rs
nginx-deployment-576789ffc 0 0 0 25h
nginx-deployment-6b47b865d4 3 3 3 9m26s

升级过程中,系统会保证至少有两个 Pod 可用,并且最多同时运行4个 Pod,这是 Deployment 通过复杂的算法完成的。 Deployment 需要确保在整个更新过程中只有一定数量的 Pod 可能处于不可用状态,在默认情况下, Deployment 确保可用的 Pod 总数至少为所需的副本的数量( DESIRED )减1 ,也就是最多1个不可用maxUnavailable=1), Deployment还需要确保在整个更新过程中 Pod 的总数量不会超过所需的副本数太多,在默认情况下,Deployment 确保 Pod 的总数最 比所 Pod 数多1个,也就是最多1个浪涌值(maxSurge=1Kubenretes v1.6 版本开始, maxUnavailablemaxSurge 默认值将从1,1更新为所需副本数的 25%、25%

更新策略

Deployment 的定义中,可以通过 spec.strategy指定 Pod 更新的策略,目前支持两种策略RollingUpdate (被动更新)和 Recreate (重建) ,默认值为 RollingUpdate

  • Recreate (重建):设置 spec. strategy. type= Recreate 表示 Deployment 在更新 Pod 时,会先杀掉所有正在运行的 Pod ,然后创建新的 Pod
  • RollingUpdate (滚动更新):设置 spec.strategy.type=RollingUpdate ,表示 Deployment以滚动更新的方式来逐个更新 Pod 。同时,可以通过设置 spec. strategy rollingUpdate下的两个参数( maxUnavailablemaxSurge )来控制被动更新的过程。

滚动升级的参数:

  • spec.strategy.rollingUpdate.maxUnavailable :指定 Deployment 在更新过程中不可用状态 Pod 的上限。可以是绝对值也可以是百分比
  • spec.strategy.rollingUpdate.maxSurge:Pod 总数超过Pod 期望副本数部分的最大值

多重更新:如果Deployment 上一次更新正在进行 ,此时用户再次发起 Deployment 更新操作,那 Deployment 每一次更新都创建一个ReplicaSet 而每次新的 ReplicaSet成功后,会逐 Pod 副本数 ,同时将之前正在扩容的 ReplicaSet 停止扩容(更新) 并将其加入旧版本 ReplicaSet 列表中,然后开始缩容至操作。

注意更新 Deployment 的标签选择器( Label selector )的情况。不鼓励更新Deployment 的标签选择器,因为这样会导致 Deployment选择的Pod列表发生变化,也能与其他控制器产生冲突。注意事项:

  • 添加选择器标签时,必须同步修改 Deployment配置的Pod 的标签 ,为 Pod 添加新的标签,否则Deployment的更新会报验证错误而失败。添加标签选择器是无法向后兼容的,新的标签选择器不会匹配和使用旧选择器创建的 ReplicaSet和Pod ,因此添加选择器将会导致旧版 ReplicaSetPod处于孤立状态
  • 更新标签选择器,即更改选择器中标签的键或者值,也会产生与添加选择器标签类似的效果。
  • 删除标签选择器, 即从 Deployment 标签选择器中删除一个或者多个标签,该DeploymentReplicaSetPod 不会受到任何影响,不是被删除的标签 仍会存在于现有 PodReplicaSet 上。

二、Deployment的回滚

当我们更新一个镜像出现错误,这时需要用kubectl rollout history查看Deployment部署的历史记录

1
2
3
kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE

创建Deployment时使用--record参数,就可以在CHANGE-CAUSE中看到每个版本的命令

Deployment 的更新操作是在 Deployment 进行部署( Rollout )时被触发的, 这意味着当且仅当 Deployment的Pod (即 spec.template )被更改时才会创建新的修订版本,例如更新模板标签或容器镜像。其他更新操作(如扩展副本数〉将不会触发 Deployment的更新操作,这也意味着我 Deployment 回滚之前版本时, 只有 Deployment的Pod板部分会被修改。

1
2
#查看特定版本的详细信息 ,可以加--revision=<N>参数
kubectl rollout history deployment/nginx-deployment --revision=3

回滚到上一个版本:

1
2
kubectl rollout undo deployment/nginx-deployment
kubectl rollout undo deployment/nginx-deployment --to-revision=2

三、暂停和恢复Deployment的部署

对于一次复杂的 Deployment 配置修改,为了避免频繁触发 Deployment 更新操作,可以先暂停 Deployment 的更新操作,然后进行配置修改再恢复 Deployment ,一次性触发完整的更新操作,就可以避免不必要的Deployment 更新操作了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#通过 kubectl rollout pause 命令暂停 Deployment 的更新操作:
kubectl rollout pause deployment/nginx-deployment

#修改镜像信息
kubectl set image deploy/nginx-deployment nginx=nginx:1.9.1

#查看历史记录,发现没有触发更新
kubectl rollout history deployment/nginx-deployment

#在暂停deployment部署之后 ,可以根据需要进行任意次数的配置更新,更新容器资源限制
kubectl set resources deployment nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi

#恢复部署
kubectl rollout resume deploy nginx-deployment

四、其他管理对象的更新策略

DaemonSet 的更新策略

包含2种升级策略

  • OnDelete : 当使用OnDelete 作为升级策略时, 建好新 DaemonSet 配置之后 Pod 并不会被自动创建,直到用户手动删除旧版本 Pod 发新建操。
  • RollingUpdate:旧版本的 Pod 将被自动杀掉, 然后自动创建新版本的 DaemonSet Pod整个过程与普通 deployment的滚动升级一样是可控 。不同于普通 Pod 滚动升级:
    • 不支持查看和管理 DaemonSet 更新历史记录
    • DaemonSet 回滚并不能如同 Deployment 样直接通过 kubectl rollback 命令来实现, 而是必须通过再次提交旧版本配置的方式实现。

StatefulSet更新

针对 StatefulSet 的更新策略正逐渐向 Deploymont DaemonSet的更新策略看齐 ,也将实 RollingUpdate Paritioned OnDelete 种策略 目标是保证StatefulSet 中各 Pod 有序 、逐个被更新,并且能够保留更新历史,也能回滚到某个历史版本。