天天看点

k8s deployment controller源码分析

deployment controller是kube-controller-manager组件中众多控制器中的一个,是 deployment 资源对象的控制器,其通过对deployment、replicaset、pod三种资源的监听,当三种资源发生变化时会触发 deployment controller 对相应的deployment资源进行调谐操作,从而完成deployment的扩缩容、暂停恢复、更新、回滚、状态status更新、所属的旧replicaset清理等操作。

deployment controller的大致组成和处理流程如下图,deployment controller对pod、replicaset和deployment对象注册了event handler,当有事件时,会watch到然后将对应的deployment对象放入到queue中,然后<code>syncDeployment</code>方法为deployment controller调谐deployment对象的核心处理逻辑所在,从queue中取出deployment对象,做调谐处理。

k8s deployment controller源码分析

deployment controller分析将分为两大块进行,分别是:

(1)deployment controller初始化与启动分析;

(2)deployment controller处理逻辑分析。

https://github.com/kubernetes/kubernetes/releases/tag/v1.17.4

直接看到startDeploymentController函数,作为deployment controller初始化与启动分析的入口。

startDeploymentController主要逻辑:

(1)调用deployment.NewDeploymentController新建并初始化DeploymentController;

(2)拉起一个goroutine,跑DeploymentController的Run方法。

从<code>deployment.NewDeploymentController</code>函数代码中可以看到,deployment controller注册了deployment、replicaset与pod对象的EventHandler,也即对这几个对象的event进行监听,把event放入事件队列并做处理。并且将<code>dc.syncDeployment</code>方法赋值给<code>dc.syncHandler</code>,也即注册为核心处理方法,在<code>dc.Run</code>方法中会调用该核心处理方法来调谐deployment对象(核心处理方法后面会进行详细分析)。

主要看到for循环处,根据workers的值(来源于kcm启动参数<code>concurrent-deployment-syncs</code>配置),启动相应数量的goroutine,跑<code>dc.worker</code>方法,主要是调用前面讲到的deployment controller核心处理方法<code>dc.syncDeployment</code>。

从queue队列中取出事件key,并调用<code>dc.syncHandle</code>即<code>dc.syncDeployment</code>做调谐处理。queue队列里的事件来源前面讲过,是deployment controller注册的deployment、replicaset与pod对象的EventHandler,它们的变化event会被监听到然后放入queue中。

进行核心处理逻辑分析前,先来了解几个关键概念。

进行代码分析前,先来看几个关键的概念。

(1)最新的replicaset对象

怎样的replicaset对象是最新的呢?replicaset对象的pod template与deployment的一致,则代表该replicaset是最新的。

(2)旧的replicaset对象

怎样的replicaset对象是旧的呢?除去最新的replicaset对象,其余的都是旧的replicaset。

(3)ready状态的pod

pod对象的<code>.status.conditions</code>中,<code>type</code>为<code>Ready</code>的<code>condition</code>中,其<code>status</code>属性值为<code>True</code>,则代表该pod属于ready状态。

而<code>type</code>为<code>Ready</code>的<code>condition</code>中,其<code>status</code>属性值会pod的各个容器都ready之后,将其值设置为<code>True</code>。

pod里的容器何时ready?kubelet会根据容器配置的readiness probe就绪探测策略,在探测成功后更新pod的status将该容器设置为ready,yaml示例如下。

(4)available状态的pod

pod处于ready状态且已经超过了<code>minReadySeconds</code>时间后,该pod即处于available状态。

直接看到deployment controller核心处理方法syncDeployment。

主要逻辑:

(1)获取执行方法时的当前时间,并定义<code>defer</code>函数,用于计算该方法总执行时间,也即统计对一个 deployment 进行同步调谐操作的耗时;

(2)根据 deployment 对象的命名空间与名称,获取 deployment 对象;

(3)调用<code>dc.getReplicaSetsForDeployment</code>:对集群中与deployment对象相同命名空间下的所有replicaset对象做处理,若发现匹配但没有关联 deployment 的 replicaset 则通过设置 ownerReferences 字段与 deployment 关联,已关联但不匹配的则删除对应的 ownerReferences,最后获取返回集群中与 Deployment 关联匹配的 ReplicaSet对象列表;

(4)调用<code>dc.getPodMapForDeployment</code>:根据deployment对象的selector,获取当前 deployment 对象关联的 pod,根据 deployment 所属的 replicaset 对象的<code>UID</code>对 pod 进行分类并返回,返回值类型为<code>map[types.UID][]*v1.Pod</code>;

(5)如果 deployment 对象的 <code>DeletionTimestamp</code> 属性值不为空,则调用<code>dc.syncStatusOnly</code>,根据deployment 所属的 replicaset 对象,重新计算出 deployment 对象的<code>status</code>字段值并更新,调用完成后,直接return,不继续往下执行;

(6)调用<code>dc.checkPausedConditions</code>:检查 deployment 是否为<code>pause</code>状态,是则更新deployment对象的<code>status</code>字段值,为其添加<code>pause</code>相关的<code>condition</code>;

(7)判断deployment对象的<code>.Spec.Paused</code>属性值,为<code>true</code>时,则调用<code>dc.sync</code>做处理,调用完成后直接return;

(8)调用<code>getRollbackTo</code>检查deployment对象的<code>annotations</code>中是否有以下key:<code>deprecated.deployment.rollback.to</code>,如果有且值不为空,调用 <code>dc.rollback</code> 方法执行 回滚操作;

(9)调用<code>dc.isScalingEvent</code>:检查deployment对象是否处于 <code>scaling</code> 状态,是则调用<code>dc.sync</code>做扩缩容处理,调用完成后直接return;

(10)判断deployment对象的更新策略,当更新策略为<code>Recreate</code>时调用<code>dc.rolloutRecreate</code>做进一步处理,也即对deployment进行recreate更新处理;当更新策略为<code>RollingUpdate</code>时调用<code>dc.rolloutRolling</code>做进一步处理,也即对deployment进行滚动更新处理。

dc.getReplicaSetsForDeployment主要作用:获取集群中与 Deployment 相关的 ReplicaSet,若发现匹配但没有关联 deployment 的 replicaset 则通过设置 ownerReferences 字段与 deployment 关联,已关联但不匹配的则删除对应的 ownerReferences。

主要逻辑如下:

(1)获取deployment对象命名空间下的所有replicaset对象;

(2)调用<code>cm.ClaimReplicaSets</code>对replicaset做进一步处理,并最终返回与deployment匹配关联的replicaset对象列表。

遍历与deployment对象相同命名空间下的所有replicaset对象,调用<code>m.ClaimObject</code>做处理,<code>m.ClaimObject</code>的作用主要是将匹配但没有关联 deployment 的 replicaset 则通过设置 ownerReferences 字段与 deployment 关联,已关联但不匹配的则删除对应的 ownerReferences。

dc.getPodMapForDeployment:根据deployment对象的Selector,获取当前 deployment 对象关联的 pod,根据 deployment 所属的 replicaset 对象的<code>UID</code>对 pod 进行分类并返回,返回值类型为<code>map[types.UID][]*v1.Pod</code>。

如果 deployment 对象的 <code>DeletionTimestamp</code> 属性值不为空,则调用<code>dc.syncStatusOnly</code>,根据deployment 所属的 replicaset 对象,重新计算出 deployment 对象的<code>status</code>字段值并更新,调用完成后,直接return,不继续往下执行;

关于具体如何计算出deployment对象的status,可以查看<code>calculateStatus</code>函数,计算逻辑都在里面,这里不展开分析。

先调用<code>getRollbackTo</code>检查deployment对象的<code>annotations</code>中是否有以下key:<code>deprecated.deployment.rollback.to</code>,如果有且值不为空,调用 <code>dc.rollback</code> 方法执行 <code>rollback</code> 操作;

dc.rollback主要逻辑:

(1)获取deployment的所有关联匹配的replicaset对象列表;

(2)获取需要回滚的Revision;

(3)遍历上述获得的replicaset对象列表,比较Revision是否与需要回滚的Revision一致,一致则调用<code>dc.rollbackToTemplate</code>做回滚操作(主要是根据特定的Revision的replicaset对象,更改deployment对象的<code>.Spec.Template</code>);

(4)最后,不管有没有回滚成功,都将deployment对象的<code>.spec.rollbackTo</code>属性置为nil,然后更新deployment对象。

下面来分析一下dc.sync方法,以下两种情况下,都会调用dc.sync,然后直接return:

(1)判断deployment的<code>.Spec.Paused</code>属性值是否为true,是则调用<code>dc.sync</code>做处理,调用完成后直接return;

(2)先调用<code>dc.isScalingEvent</code>,检查deployment对象是否处于 <code>scaling</code> 状态,是则调用<code>dc.sync</code>做处理,调用完成后直接return。

关于Paused字段

deployment的<code>.Spec.Paused</code>为true时代表该deployment处于暂停状态,false则代表处于正常状态。当deployment处于暂停状态时,deployment对象的PodTemplateSpec的任何修改都不会触发deployment的更新,当<code>.Spec.Paused</code>再次赋值为false时才会触发deployment更新。

dc.sync主要逻辑:

(1)调用<code>dc.getAllReplicaSetsAndSyncRevision</code>获取最新的replicaset对象以及旧的replicaset对象列表;

(2)调用<code>dc.scale</code>,判断是否需要进行扩缩容操作,需要则进行扩缩容操作;

(3)当deployment的<code>.Spec.Paused</code>为true且不需要做回滚操作时,调用<code>dc.cleanupDeployment</code>,根据deployment配置的保留历史版本数(<code>.Spec.RevisionHistoryLimit</code>)以及replicaset的创建时间,把最老的旧的replicaset给删除清理掉;

(4)调用<code>dc.syncDeploymentStatus</code>,计算并更新deployment对象的status字段。

dc.scale主要作用是处理deployment的扩缩容操作,其主要逻辑如下:

(1)调用<code>deploymentutil.FindActiveOrLatest</code>,判断是否只有最新的replicaset对象的副本数不为0,是则找到最新的replicaset对象,并判断其副本数是否与deployment期望副本数一致,是则直接return,否则调用<code>dc.scaleReplicaSetAndRecordEvent</code>更新其副本数为deployment的期望副本数;

(2)当最新的replicaset对象的副本数与deployment期望副本数一致,且旧的replicaset对象中有副本数不为0的,则从旧的replicset对象列表中找出副本数不为0的replicaset,调用<code>dc.scaleReplicaSetAndRecordEvent</code>将其副本数缩容为0,然后return;

(3)当最新的replicaset对象的副本数与deployment期望副本数不一致,旧的replicaset对象中有副本数不为0的,且deployment的更新策略为滚动更新,说明deployment可能正在滚动更新,则按一定的比例对新旧replicaset进行扩缩容操作,保证滚动更新的稳定性,具体逻辑可以自己分析下,这里不展开分析。

当deployment的所有pod都是updated的和available的,而且没有旧的pod在running,则调用<code>dc.cleanupDeployment</code>,根据deployment配置的保留历史版本数(<code>.Spec.RevisionHistoryLimit</code>)以及replicaset的创建时间,把最老的旧的replicaset给删除清理掉。

判断deployment对象的更新策略<code>.Spec.Strategy.Type</code>,当更新策略为<code>Recreate</code>时调用<code>dc.rolloutRecreate</code>做进一步处理。

dc.rolloutRecreate主要逻辑:

(1)调用<code>dc.getAllReplicaSetsAndSyncRevision</code>,获取最新的replicaset对象以及旧的replicaset对象列表;

(2)调用<code>dc.scaleDownOldReplicaSetsForRecreate</code>,缩容旧的replicaSets,将它们的副本数更新为0,当有旧的replicasets需要缩容时,调用<code>dc.syncRolloutStatus</code>更新deployment状态后直接return;

(3)调用<code>oldPodsRunning</code>函数,判断是否有属于deployment的pod还在running(pod的<code>pod.Status.Phase</code>属性值为<code>Failed</code>或<code>Succeeded</code>时代表该pod不在running),还在running则调用<code>dc.syncRolloutStatus</code>更新deployment状态并直接return;

(4)当新的replicaset对象没有被创建时,调用<code>dc.getAllReplicaSetsAndSyncRevision</code>来创建新的replicaset对象(注意:新创建的replicaset的副本数为0);

(5)调用<code>dc.scaleUpNewReplicaSetForRecreate</code>,扩容刚新创建的replicaset,更新其副本数与deployment期望副本数一致(即deployment的<code>.Spec.Replicas</code>属性值);

(6)调用<code>util.DeploymentComplete</code>,检查deployment的所有pod是否都是updated的和available的,而且没有旧的pod在running,是则继续调用<code>dc.cleanupDeployment</code>,根据deployment配置的保留历史版本数(<code>.Spec.RevisionHistoryLimit</code>)以及replicaset的创建时间,把最老的旧的replicaset给删除清理掉。

(7)调用<code>dc.syncRolloutStatus</code>更新deployment状态。

dc.getAllReplicaSetsAndSyncRevision会获取所有的旧的replicaset对象,以及最新的replicaset对象,然后返回。

关于最新的replicaset对象,怎样的replicaset对象是最新的呢?replicaset对象的pod template与deployment的一致,则代表该replicaset是最新的。

关于旧的replicaset对象,怎样的replicaset对象是旧的呢?除去最新的replicaset对象,其余的都是旧的replicaset。

syncRolloutStatus方法主要作用是计算出deployment的新的status属性值并更新,具体的计算逻辑可以自己查看代码,这里不展开分析。

遍历deployment下所有的pod,找到属于旧的replicaset对象的pod,判断pod的状态(即<code>pod.Status.Phase</code>的值)是否都是<code>Failed</code>或<code>Succeeded</code>,是则代表所有旧的pod都没在running了,返回false。

dc.getAllReplicaSetsAndSyncRevision方法主要作用是获取最新的replicaset对象以及旧的replicaset对象列表,当传入的<code>createIfNotExisted</code>变量值为true且新的replicaset对象不存在时,调用dc.getNewReplicaSet时会新建replicaset对象(新建的replicaset对象副本数为0)。

遍历全部旧的replicaset,调用<code>dc.scaleReplicaSetAndRecordEvent</code>将其副本数缩容为0。

调用<code>dc.scaleReplicaSetAndRecordEvent</code>,将最新的replicset对象的副本数更新为deployment期望的副本数。

判断deployment对象的更新策略<code>.Spec.Strategy.Type</code>,当更新策略为<code>RollingUpdate</code>时调用<code>dc.rolloutRolling</code>做进一步处理。

dc.rolloutRolling主要逻辑:

(1)调用<code>dc.getAllReplicaSetsAndSyncRevision</code>,获取最新的replicaset对象以及旧的replicaset对象列表,当新的replicaset对象不存在时,将创建一个新的replicaset对象(副本数为0);

(2)调用<code>dc.reconcileNewReplicaSet</code>,调谐新的replicaset对象,根据deployment的滚动更新策略配置<code>.Spec.Strategy.RollingUpdate.MaxSurge</code>和现存pod数量进行计算,决定是否对新的replicaset对象进行扩容以及扩容的副本数;

(3)当新的replicaset对象副本数在调谐时被更新,则调用<code>dc.syncRolloutStatus</code>更新deployment状态后直接return;

(4)调用<code>dc.reconcileOldReplicaSets</code>,根据deployment的滚动更新策略配置<code>.Spec.Strategy.RollingUpdate.MaxUnavailable</code>、现存的Available状态的pod数量、新replicaset对象下所属的available的pod数量,决定是否对旧的replicaset对象进行缩容以及缩容的副本数;

(5)当旧的replicaset对象副本数在调谐时被更新,则调用<code>dc.syncRolloutStatus</code>更新deployment状态后直接return;

dc.reconcileNewReplicaSet主要作用是调谐新的replicaset对象,根据deployment的滚动更新策略配置和现存pod数量进行计算,决定是否对新的replicaset对象进行扩容。

(1)当新的replicaset对象的副本数与deployment声明的副本数一致,则说明该replicaset对象无需再调谐,直接return;

(2)当新的replicaset对象的副本数比deployment声明的副本数要大,则调用<code>dc.scaleReplicaSetAndRecordEvent</code>,将replicaset对象的副本数缩容至与deployment声明的副本数一致,然后return;

(3)当新的replicaset对象的副本数比deployment声明的副本数要小,则调用<code>deploymentutil.NewRSNewReplicas</code>,根据deployment的滚动更新策略配置<code>.Spec.Strategy.RollingUpdate.MaxSurge</code>的值计算出新replicaset对象该拥有的副本数量,并调用<code>dc.scaleReplicaSetAndRecordEvent</code>更新replicaset的副本数。

NewRSNewReplicas

当deployment配置了滚动更新策略时,<code>NewRSNewReplicas</code>函数将根据<code>.Spec.Strategy.RollingUpdate.MaxSurge</code>的配置,调用<code>intstrutil.GetValueFromIntOrPercent</code>计算出<code>maxSurge</code>(代表滚动更新时可超出deployment声明的副本数的最大值),最终根据<code>maxSurge</code>与现存pod数量计算出新的replicaset对象该拥有的副本数。

intstrutil.GetValueFromIntOrPercent

maxSurge的计算也不复杂,当<code>maxSurge</code>为百分比时,因为函数入参<code>roundUp</code>为<code>true</code>,所以计算公式为:<code>maxSurge = ⌈deployment.Spec.Strategy.RollingUpdate.MaxSurge * deployment.Spec.Replicas / 100⌉</code>(结果向上取整) ;

当<code>maxSurge</code>不为百分比时,直接返回其值。

dc.reconcileNewReplicaSet主要作用是调谐旧的replicaset对象,根据deployment的滚动更新策略配置<code>.Spec.Strategy.RollingUpdate.MaxUnavailable</code>和现存的Available状态的pod数量进行计算,决定是否对旧的replicaset对象进行缩容。

(1)获取旧的replicaset对象的副本数总数,如果是0,则代表旧的replicaset对象已经无法缩容,调谐完毕,直接return;

(2)调用<code>deploymentutil.MaxUnavailable</code>,计算获取<code>maxUnavailable</code>的值,即最大不可用pod数量(这里注意一点,当deployment滚动更新策略中<code>MaxUnavailable</code>与<code>MaxSurge</code>的配置值都为0时,此处计算<code>MaxUnavailable</code>的值时会返回1,因为这两者均为0时,无法进行滚动更新);

(3)根据<code>MaxUnavailable</code>的值、deployment的期望副本数、新replicaset对象的期望副本数、新replicaset对象的处于<code>Available</code>状态的副本数,计算出<code>maxScaledDown</code>即最大可缩容副本数,当<code>maxScaledDown</code>小于等于0,则代表目前暂不能对旧的replicaset对象进行缩容,直接return;

(4)调用<code>dc.cleanupUnhealthyReplicas</code>,按照replicaset的创建时间排序,先清理缩容<code>Unhealthy</code>的副本(如<code>not-ready</code>的、<code>unscheduled</code>的、<code>pending</code>的pod),具体逻辑暂不展开分析;

(5)调用<code>dc.scaleDownOldReplicaSetsForRollingUpdate</code>,根据deployment的滚动更新策略配置<code>.Spec.Strategy.RollingUpdate.MaxUnavailable</code>计算出旧的replicaset对象该拥有的副本数量,调用<code>dc.scaleReplicaSetAndRecordEvent</code>缩容旧的replicaset对象(所以这里也可以看到,<code>dc.cleanupUnhealthyReplicas</code>与<code>dc.scaleDownOldReplicaSetsForRollingUpdate</code>均有可能会对旧的replicaset进行缩容操作);

(6)如果缩容的副本数大于0,则返回true,否则返回false。

dc.scaleDownOldReplicaSetsForRollingUpdate

dc.scaleDownOldReplicaSetsForRollingUpdate主要逻辑是缩容旧的replicaset对象,主要逻辑如下:

(1)根据deployment的滚动更新策略配置<code>.Spec.Strategy.RollingUpdate.MaxUnavailable</code>和现存的Available状态的pod数量,计算出<code>totalScaleDownCount</code>,即目前需要缩容的副本数;

(2)对旧的replicaset对象按照创建时间先后排序;

(3)遍历旧的replicaset对象,根据需要缩容的副本总数,缩容replicaset。

其中deployment的扩缩容、暂停恢复、更新、回滚、状态status更新、所属的旧replicaset清理等操作都在deployment controller的核心处理方法<code>syncDeployment</code>里进行处理调用。

关于deployment更新这一块,deployment controller会根据deployment对象配置的更新策略Recreate或RollingUpdate,会调用<code>rolloutRecreate</code>或<code>rolloutRolling</code>方法来对deployment对象进行更新操作。

且经过以上的代码分析,可以看出,deployment controller并不负责deployment对象的删除,除按历史版本限制数需要清理删除多余的replicaset对象以外,deployment controller也不负责replicset对象的删除(实际上,除按历史版本限制数deployment controller需要清理删除多余的replicaset对象以外,其他的replicaset对象的删除由garbagecollector controller完成)。

k8s deployment controller源码分析

deployment controller的核心处理逻辑在<code>syncDeployment</code>方法中,下图即<code>syncDeployment</code>方法的处理流程。

k8s deployment controller源码分析

无论deployment配置了ReCreate还是RollingUpdate的更新策略,在<code>dc.rolloutRecreate</code>或<code>dc.rolloutRolling</code>的处理逻辑里,都会判断最新的replicaset对象是否存在,不存在则会创建。

在创建了deployment对象后,deployment controller会收到deployment的新增event,然后会做调谐处理,在第一次进入<code>dc.rolloutRecreate</code>或<code>dc.rolloutRolling</code>的处理逻辑时,deployment所属的replicaset对象为空,所以会触发创建一个新的replicaset对象出来。

(1)先缩容旧的replicaset,将其副本数缩容为0;

(2)等待旧的replicaset的pod全部都处于not running状态(pod的<code>pod.Status.Phase</code>属性值为<code>Failed</code>或<code>Succeeded</code>时代表该pod处于not running状态);

(3)接着创建新的replicaset对象(注意:新创建的replicaset的实例副本数为0);

(4)随后扩容刚新创建的replicaset,更新其副本数与deployment期望副本数一致;

(5)最后等待,直至deployment的所有pod都属于最新的replicaset对象、pod数量与deployment期望副本数一致、且所有pod都处于Available状态,则deployment更新完成。

(1)根据deployment的滚动更新策略配置<code>.Spec.Strategy.RollingUpdate.MaxSurge</code>和现存pod数量进行计算,决定是否对新的replicaset对象进行扩容以及扩容的副本数;

(2)根据deployment的滚动更新策略配置<code>.Spec.Strategy.RollingUpdate.MaxUnavailable</code>、现存的Available状态的pod数量、新replicaset对象下所属的available的pod数量,决定是否对旧的replicaset对象进行缩容以及缩容的副本数;

(3)循环以上步骤,直至deployment的所有pod都属于最新的replicaset对象、pod数量与deployment期望副本数一致、且所有pod都处于Available状态,则deployment滚动更新完成。

先来看到deployment滚动更新配置的两个关键参数:

(1)<code>.Spec.Strategy.RollingUpdate.MaxUnavailable</code>:指定更新过程中不可用的 Pod 的个数上限。该值可以是绝对数字(例如5),也可以是deployment期望副本数的百分比(例如10%),运算公式:期望副本数乘以百分比值并向下取整。 如果maxSurge为0,则此值不能为0。MaxUnavailable默认值为 25%。该值越小,越能保证服务稳定,deployment更新越平滑。

(2)<code>.Spec.Strategy.RollingUpdate.MaxSurge</code>:指定可以创建的超出期望 Pod 个数的 Pod 数量。此值可以是绝对数(例如5),也可以是deployment期望副本数的百分比(例如10%),运算公式:期望副本数乘以百分比值并向上取整。 如果 MaxUnavailable 为0,则此值不能为0。 MaxSurge默认值为 25%。该值越大,deployment更新速度越快。

注意:MaxUnavailable与MaxSurge不能均配置为0,但可能在运算之后这两个值均为0,这种情况下,为了保证滚动更新能正常进行,deployment controller会在滚动更新时将MaxUnavailable的值置为1去进行滚动更新。

例如,当deployment期望副本数为2、MaxSurge值为0、MaxUnavailable为1%时(MaxUnavailable为百分比,根据运算公式运算并向下取整后,取值为0,这时MaxSurge与MaxUnavailable均为0,所以在deployment滚动更新时,会将MaxUnavailable置为1去做滚动更新操作),触发滚动更新后,会立即将旧 replicaSet 副本数缩容到1,并扩容新的replicaset副本数为1。待新 Pod Available后,可以继续缩容旧有的 replicaSet副本数为0,然后扩容新的replicaset副本数为2。滚动更新期间确保Available可用的 Pods 总数在任何时候都至少为1个。

例如,当deployment期望副本数为2、MaxSurge值为1%、MaxUnavailable为0时(MaxSurge根据运算公式运算并向上取整,取值为1),触发滚动更新后,会立即扩容新的replicaset副本数为1,待新pod Available后,再缩容旧replicaset副本数为1,然后再扩容扩容新的replicaset副本数为2,待新pod Available后,再缩容旧replicaset副本数为0。滚动更新期间确保Available可用的 Pods 总数在任何时候都至少为2个。

更多示例如下:

继续阅读