pod的升级与回滚

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

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

一、 Deployment的升级:

1、下面的资源定义文件通过deployment方式定义nginx应用pod,如图:

上图中在命名空间update中创建pod,内部容器的名字定义为nginx-app,镜像为1.16-stable, 执行创建命令为:kubectl ceate -f nginx.yaml –record ,创建后的Pod如下:

注意: –record参数的意思是在查看历史部署记录时在CHANGECAUSE列看到每个版本使用的命令

2、现在要将Nginx镜像更新为nginx:v1,可以执行如下命令kubectl set image deploy/nginx-app nginx-app=registry.cn-hangzhou.aliyuncs.com/gongguan/nginx:v1 -n update,如图:

通过命令kubectl describe po nginx-app-5c85ccc4b7-dbt7q -n update 可以查看容器镜像名字已变成v1,如图:

Deployment更新Pod原理:初始创建deployment时,创建了一个ReplicaSet,并根据需要创建了2个副本,当更新deployment时,系统创建了一个新的ReplicaSet,并将副本数扩展为1个,同时旧的ReplicaSet缩减为1个,然后继续按照相同的策略将新的副本数扩展为2个,将旧的副本数缩减为0个,从而实现滚动更新而不影响服务

Deployment 需要确保在整个更新过程中只有一定数量的Pod可能处于不可用状态 , 在默认情况下,Deployment确保可用的Pod总数至少为所需的副本数量 (DESIRED)减1,也就是最多1个不可用(maxUnavailable=1)

Deployment还需要确保在整个更新过程中Pod的总数量不会超过所需的副本数量太多。在默认情况下,Deployment确保Pod的总数最多比所需的Pod数多1个,也就是最多1个浪涌值(maxSurge=1)。Kubernetes从 1.6版本开始,maxUnavailable和maxSurge的默认值将从1、1更新为所需副本数量的25%、25%, 这样,在升级过程中,Deployment就能够保证服务不中断,并且副本数量始终维持为用户指定的数量(DESIRED)

对更新策略的说明如下 :

在Deployment的定义中,可以通过spec.strategy指定Pod更新的策 略,目前支持两种策略:Recreate(重建)和RollingUpdate(滚动更新),默认值为RollingUpdate。在前面的例子中使用的就是 RollingUpdate策略。

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

下面对滚动更新时两个主要参数的说明如下:

  • spec.strategy.rollingUpdate.maxUnavailable:用于指定 Deployment在更新过程中不可用状态的Pod数量的上限。该 maxUnavailable的数值可以是绝对值(例如5)或Pod期望的副本数的百 分比(例如10%),如果被设置为百分比,那么系统会先以向下取整的 方式计算出绝对值(整数)。而当另一个参数maxSurge被设置为0时, maxUnavailable则必须被设置为绝对数值大于0(从Kubernetes 1.6开始, maxUnavailable的默认值从1改为25%)。举例来说,当maxUnavailable 被设置为30%时,旧的ReplicaSet可以在滚动更新开始时立即将副本数缩小到所需副本总数的70%。一旦新的Pod创建并准备好,旧的ReplicaSet 会进一步缩容,新的ReplicaSet又继续扩容,整个过程中系统在任意时刻都可以确保可用状态的Pod总数至少占Pod期望副本总数的70%。
  • spec.strategy.rollingUpdate.maxSurge:用于指定在Deployment 更新Pod的过程中Pod总数超过Pod期望副本数部分的最大值。该 maxSurge的数值可以是绝对值(例如5)或Pod期望副本数的百分比(例 如10%)。如果设置为百分比,那么系统会先按照向上取整的方式计算 出绝对数值(整数)。从Kubernetes 1.6开始,maxSurge的默认值从1改 为25%。举例来说,当maxSurge的值被设置为30%时,新的ReplicaSet可 以在滚动更新开始时立即进行副本数扩容,只需要保证新旧ReplicaSet 的Pod副本数之和不超过期望副本数的130%即可。一旦旧的Pod被杀掉,新的ReplicaSet就会进一步扩容。在整个过程中系统在任意时刻都能确保新旧ReplicaSet的Pod副本总数之和不超过所需副本数的130%。

注意: 还有多重更新(Rollover)的情况。如果Deployment的上一次更新正在进行,此时用户再次发起Deployment的更新操作,那么 Deployment会为每一次更新都创建一个ReplicaSet,而每次在新的 ReplicaSet创建成功后,会逐个增加Pod副本数,同时将之前正在扩容的 ReplicaSet停止扩容(更新),并将其加入旧版本ReplicaSet列表中,然 后开始缩容至0的操作, 例如,假设我们创建一个Deployment,这个Deployment开始创建5 个Nginx:1.7.9的Pod副本,在这个创建Pod动作尚未完成时,我们又将 Deployment进行更新,在副本数不变的情况下将Pod模板中的镜像修改为Nginx:1.9.1,又假设此时Deployment已经创建了3个Nginx:1.7.9的Pod 副本,则Deployment会立即杀掉已创建的3个Nginx:1.7.9 Pod,并开始创 建Nginx:1.9.1 Pod。Deployment不会在等待Nginx:1.7.9的Pod创建到5个之后再进行更新操作。

二、 Deployment的回滚:

有时(例如新的Deployment不稳定时)我们可能需要将Deployment 回滚到旧版本。在默认情况下,所有Deployment的发布历史记录都被保留在系统中,以便于我们随时进行回滚(可以配置历史记录数量)。

1、首先通过命令kubectl rollout history查看部署的历史记录,如图:

加上–revision=N 参数可以查看特定版本的详细信息,如图:

从上图可以看出,查看版本2的详细信息可以看到是当前的更新镜像后的版本,如果要回滚到更新之前的版本,此时可以执行命令如下:

此时再通过kubectl describe命令可以查看已经回滚到更新前的版本,如图:

还可以通过用–to-revision参数指定回滚到的部署版本号,如图:

上图中首先查看历史版本记录,然后通过–to-revision回滚到指定版本即可

三、 暂停和恢复Deployment的部署操作,以完成复杂的修改

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

例如:还是以上面创建的Nginx应用的pod滚动更新为例,首先暂停deployment,执行命令如下:

然后可以执行命令更新镜像或者其他资源信息,最后在执行命令恢复Deployment,如图:

注意:在暂停期间,对资源的任何修改都不会触发滚动更新,当恢复后,会再次触发滚动更新,同时, 在恢复暂停的Deployment之前,无法回滚该Deployment。

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

1、DaemonSet的更新策略:

目前DaemonSet的升级策略(updateStrategy)包括两种:OnDelete和RollingUpdate。

OnDelete:DaemonSet的默认升级策略,与1.5及之前版本的Kubernetes保持一致。当使用OnDelete作为升级策略时,在创建好新的DaemonSet配置之后,新的Pod并不会被自动创建,直到用户手动删除旧版本的Pod,才触发新建操作,即只有手工删除了DaemonSet创建的Pod副本,新的Pod副本才会被创建出来。如果不设置updateStrategy的值,则在Kubernetes 1.6之后的版本中会被作为updateStrategy的默认设置

RollingUpdate:从Kubernetes 1.6版本开始引入。当使用RollingUpdate作为升级策略对DaemonSet进行更新时,旧版本的Pod将被自动“杀掉”,然后自动创建新版本的DaemonSet Pod。整个过程与普通Deployment的滚动升级一样是可控的。不过有两点不同于普通Pod的滚动升级:一是目前Kubernetes还不支持查看和管理DaemonSet的更新历史记录;二是DaemonSet的回滚(Rollback)并不能如同Deployment一样直接通过kubectl rollback命令来实现,必须通过再次提交旧版本配置的方式实现。

2、StatefulSet的更新策略:

1.7版本之后,StatefulSet又增加了updateStrategy字段给予用户更强的StatefulSet升级控制能力,并实现了RollingUpdate、OnDelete和Partitioned这几种策略,以保证StatefulSet中各Pod有序地、逐个地更新,并且能够保留更新历史,也能回滚到某个历史版本。如果用户未设置updateStrategy字段,则系统默认使用RollingUpdate策略。

当 updateStrategy 的 值 被 设 置 为 RollingUpdate 时 , StatefulSetController会删除并创建StatefulSet相关的每个Pod对象,其处理顺序StatefulSet终止Pod的顺序一致,即从序号最大的Pod开始重建,每次更新一个Pod。注意,如果StatefulSet的Pod Management Policy被设置为OrderedReady , 则 可 能 在 更 新 过 程 中 发 生 一 些 意 外 , 从 而 导 致StatefulSet陷入奔溃状态,此时需要用户手动修复。

当updateStrategy的值被设置为OnDelete时,StatefulSet Controller并不会自动更新StatefulSet中的Pod实例,而是需要用户手动删除这些Pod并触发StatefulSet Controller创建新的Pod实例来弥补,因此这其实是一种手动升级模式。

updateStrategy也支持特殊的分区升级策略(Partitioned),在这种模式下,用户指定一个序号,StatefulSet中序号大于等于此序号的Pod实例会全部被升级,小于此序号的Pod实例则保留旧版本不变,即使这些Pod被删除、重建,也仍然保持原来的旧版本。这种分区升级策略通常用于按计划分步骤的系统升级过程中。

标签