Kube-controller-manager(Deployment)
Kube-controller-manager(Deployment)
基于1.25
Deployment控制器主要控制Deployment资源。
- Deploymen控制器依旧更新策略调整RS资源
控制器初始化
Deployment控制器初始化的时候,会创建工作队列存储Deployment资源对象的Key
- Deployment资源对象:监听Add、Update、Delete事件,把监听到的RS资源对象的Key加入到工作队列中,等待Worker协程消费处理
- RS资源对象
- Pod资源对象
主要执行逻辑
dc.Listener.Deployments
获取Deployment资源对象。通过Deployment Informer的Lister接口Get获取完整的Deployment资源对象
dc.getReconcileSetsForDeployment
获取管理的RS对象
d.DeletionTimestamp !=nil
判断是否执行Reconcile
d.Spec.Paused
判断是否暂停版本更新。当处于Paused状态时,Deployment Controller仅仅通过RS将Pod数量调谐到Deployment对象的规定数量,但不处理Pod模版的更新
pod数量的调谐sync func完成
-
if d.Spec.Paused {
return dc.sync(ctx, d, rsList)
}
getRollbackTo(d)!=nil
判断是否会滚版本
如果Deployment资源对象存在“deprecated.deployment.rollback.to” Annotation,则认为是Pod模版需要会滚到Annotation指定版本去,调用rollback func寻找目标的RS并将Deployment资源对象的Pod模版修改为该RS的配置
-
// rollback is not re-entrant in case the underlying replica sets are updated with a new
// revision so we should ensure that we won't proceed to update replica sets until we
// make sure that the deployment has cleaned up its rollback spec in subsequent enqueues.
if getRollbackTo(d) != nil {
return dc.rollback(ctx, d, rsList)
}
dc.isScalingEvent
根据期望副本数量的变化执行Pod的拓展/缩容的操作。
如果Deployment被认为发生了扩容/缩容操作,就需要调用sync执行Pod数量的调谐
负责检查Deployment是否扩容/缩容的是isScalingEvent func:检查Deployment关联的各个活跃的RS的”deployment.kubernetes.io/desired-replicas” Annotation记录的Deployment的期望副本数量,如果不一致,则说明Deployment发生了扩容/缩容
-
// isScalingEvent checks whether the provided deployment has been updated with a scaling event
// by looking at the desired-replicas annotation in the active replica sets of the deployment.
//
// rsList should come from getReplicaSetsForDeployment(d).
func (dc *DeploymentController) isScalingEvent(ctx context.Context, d *apps.Deployment, rsList []*apps.ReplicaSet) (bool, error) {
newRS, oldRSs, err := dc.getAllReplicaSetsAndSyncRevision(ctx, d, rsList, false)
if err != nil {
return false, err
}
allRSs := append(oldRSs, newRS)
for _, rs := range controller.FilterActiveReplicaSets(allRSs) {
desired, ok := deploymentutil.GetDesiredReplicasAnnotation(rs)
if !ok {
continue
}
if desired != *(d.Spec.Replicas) {
return true, nil
}
}
return false, nil
}
PodTempldate的更新操作不会影响Spec.Replicas字段。所以只更新PodTempldate不会,进入到此处的Pod扩缩容操作
-
switch d.Spec.Strategy.Type
按更新策略更新Pod。
当更新策略为Recreate时,调用dc.rolloutRecreate func执行Pod更新
当更新策略为RollingUpdate,调用dc.rolloutRolling func 执行Pod更新
更新Pod的过程中,旧Pod的销毁是通过调低旧RS期望副本数实现,而新版Pod的创建通过调高RS的期望数实现
-
switch d.Spec.Strategy.Type {
case apps.RecreateDeploymentStrategyType:
return dc.rolloutRecreate(ctx, d, rsList, podMap)
case apps.RollingUpdateDeploymentStrategyType:
return dc.rolloutRolling(ctx, d, rsList)
}
return fmt.Errorf("unexpected deployment strategy type: %s", d.Spec.Strategy.Type)
调谐Pod的数量
当Deployment处于Suspend状态,或期望副本数量发生变化时,Deployment控制器调用sync func,借助RS调谐Pod数量
Deployment控制首先获取Deployment关联的所有RS,根据实际情况执行以下逻辑:
- 如果仅有一个或者完全没有活跃的RS:找出创建时间最近的RS,将其副本数量调整到Deployment对象一致
- 如果最新的RS存在,并且副本数和Deployment一致,就把其他的RSPod期望数降为0,删除这些旧的Pod
- 如果有多个活跃的RS,更新策略为RollingUpdate,通过多次迭代,逐渐把旧RS的Pod删除,并且调整最新的RS的Pod数
- 第三种情况,说明Pod版本更新和Pod副本数量同时执行,K8s不推荐,应该把更新副本数和版本更新分开
更新策略
Deployment 支持更新策略为 Recrate和 RollingUpdate 俩种
Recrate
如果Deployment资源对象的更新策略为Recreate,Deployment关联的所有RS
- 所有非最新的RS的Pod副本数量将为0,来删除旧的Pod
- 在删除所有旧Pod之前,Deployment Controller只会更新Deployment的状态,不会创建新的Pod
- 删除所有旧的Pod之后,Deployment Controller创建使用新Pod模版的RS,实现创建新的Pod
RollingUpdate
Deployment会多次执行同步操作,每次同步操作通过调节新、旧RS的Spec.Replicas字段的方式,创建和删除一些Pod,分次逐步完成Pod的更新
- Spec.MaxSurge:指定超出期望Pod的数量
- Spec.MaxUnavailable:更新过程中不可用的Pod数量
- Deployment Controller获取Deployment关联的所有RS
- 如果所有RS都和DeploymentPod模版不同,就会创建一个新的RS(Recreate不一样,它选择只有删除所有的Pod,才会创建新的RS)
- Deployment Controller会尝试扩容最新的RS,使得总可用的Pod数量不超过MaxSurge的上限
- Deployment Controller会修改新的RS的Spec.Replicas,扩容一部分Pod,并且结束同步
- 如果新的RS已经成功扩容了新的Pod,DeploymentController就会删除一些旧的Pod
- Deployment Controller会执行旧Pod的缩容,使得总不可用数量不超过Max Unavailable的下限
- Deployment Controller会修改新的RS的Spec.Replicas,缩容一部分Pod,并且结束同步
- Deployment Controller 会检查Deployment状态,如果可用Pod已经达到Spec.Replicas一致,更新完成,清理冗余的RS
版本回滚
Deployment Controller创建的RS都有一条注解记录(deployment.kubernetes.io/version
)其版本号
版本回滚主要是3步骤:
获取回滚的版本号
Deployment Controller 调用getRollbackTo func获取回滚版本号,回滚版本号记录在Deployment中的Annotation(
deprecated.deployment.rollback.io
)中-
// TODO: Remove this when extensions/v1beta1 and apps/v1beta1 Deployment are dropped.
func getRollbackTo(d *apps.Deployment) *extensions.RollbackConfig {
// Extract the annotation used for round-tripping the deprecated RollbackTo field.
revision := d.Annotations[apps.DeprecatedRollbackTo]
if revision == "" {
return nil
}
revision64, err := strconv.ParseInt(revision, 10, 64)
if err != nil {
// If it's invalid, ignore it.
return nil
}
return &extensions.RollbackConfig{
Revision: revision64,
}
}
-
根据回滚版本号,找到对应的RS
如果回滚版本号是0,则Deployment Controller 回滚到次新版本。Deployment Controller根据回滚版本号,找到对应的RS对象
更新Deployment的Pod模版
Deployment Controlller更新Deployment资源对象的Pod模版,将其更换为回滚的目标RS中的Pod模版,并且清空回滚Annottaion
需要注意回滚过程只更新Pod模版回滚,Pod模版之外的配置无法回滚