图解kubernetes控制器Deployment核心机制

Deployment是k8s中部署更新的关键实现,今天咱们一块儿初探下其关键机制包括: 暂停、回滚、扩缩容、更新策略的实现算法

1. 基础概念

Deployment本质上其实只是一种部署策略,在了解其实现以前,先简单介绍一下部署系统里面常见的概念,Deployment里面的各类参数和设计其实也都是围绕着这些展开的数据库

1.1 ReplicaSet

image.png

Deployment自己并不直接操做Pod,每当其更新的时候经过构建ReplicaSet来进行版本更新,在更新的过程当中经过scale up(新的RS)和scale down(旧的RS)来完成bash

1.2 部署状态

在k8s的官方文档中主要是介绍了Deployment的三种状态, 对应的Condition分别为Available、Progressing、ReplicaFailure三种状态, 而且每一个状态下面又会颇有致使对应状态切换的不一样的Reson,Reson多是运维过程当中最须要关注的点微信

1.3 部署策略

部署策略是Deployment控制ReplicaSet更新的策略,经过对新旧ReplicaSet的扩缩容,再知足部署策略的状况下,将系统更新至最新的目标状态,Deployment自己并无太多可选的策略,默认只有两种Recreate和RollingUpdate image.pngapp

在一些大版本产品更新的时候,新旧版本的数据库模型都不一致的状况下,一般会选择停服操做,此时能够选择Recreate即将全部老的副本都干掉,而后从新建立一批。固然默认状况下大部分业务仍是RollingUpdate即滚动更新便可运维

1.4 可用性与高低水位

部署过程当中最常被提到的可能就是可用性问题了,即在更新的过程当中(RollingUpdate策略下)须要保证系统中可用的Pod在一个指定的水位,保证对应服务的可用性 image.pngide

高低水位(deployment并无这个词)其实就是对应的上面的可用性来讲的,Deployment经过一些参数让咱们能够自由控制在滚动更新的过程当中,咱们能够建立的Pod的最多数量(高水位)和能够删除的最多的Pod(低水位), 从而达到可用性保护的目标源码分析

部署的概念就介绍到这里, 接下来就一块儿看看Deployment中这些关键机制的具体实现学习

2. 核心实现

Deployment的实现上相对复杂一点,可是从场景上又能够简单的分为:删除、暂停、回滚、扩缩容、更新几个大的场景ui

2.1 暂停部署

暂停部署是用于中断Deployment更新流程的一种方式,但因为k8s中是基于事件驱动的最终一致性的系统,这里的中断仅仅意味着Deployment层不会进行的进行后续的副本变动,而底层的replicaSet此时若是尚未达到目标的副本,则就须要继续更新, 同时在暂停的过程当中若是发现并无尝试进行回滚到指定版本的操做,这时候还会进行一些副本的清理工做,即只保留最近的指定数量的历史副本

2.2 回滚控制

回滚控制里面的信息跟其余参数有些不一样,其主要是经过在Annotations中存储的DeprecatedRollbackTo来进行指定版本的回滚 image.png

回滚的实现本质上就是从指定的Revisions中获取对应的replicaset的Pod模板,去覆盖当前的Deployment的Pod模板,而且更新Deployment便可, 那若是对应的版本不存在怎么办,若是是这种状况,其实就须要你本身去寻找历史版本了,而且k8s会给新添加一个RollbackRevisionNotFound类型的事件提示你版本不存在 

2.3 扩缩容机制

扩缩容机制主要是指的Deployment的scale操做,在进行Deployment更新以前,会首先检查对应Deployment的副本的指望是否获得知足,只有指望的副本数获得知足,才会进行更新操做,因此在k8s中若是以前进行了扩缩容操做,则在该操做完成以前,是不会进行模板更新的

2.4 Recreate策略

image.png

Recreate部署策略在实现上经过两种机制保证以前的Pod必定被删除:全部活跃副本都为0和全部Pod都处于(PodFailed和PodSucceeded)两种状态下,而后才会建立新的副本,若是对应的副本彻底就绪,还会进行清理历史副本

2.5 RollingUpdate策略

RollingUpdate策略多是最复杂的部分之一了,里面颇有多的参数控制,都做用于该策略,来一块儿看下

2.5.1 缩容过多的新版本

首先在更新的时候要作一致性检测,若是发现新版本的ReplicaSet比当前的deployment设定的副本数目多,则首先干掉这部分Pod, 同时会根据当前的Deployment的副本数来设定当前的指望副本数DesiredReplicasAnnotation, 而且根据maxSurge来计算当前最大的副本数量MaxReplicasAnnotation, 同时在这个同步ReplicaSet的minReadySeconds

2.5.2 扩容新副本

若是说新副本的数量不足,则就须要根据当前的maxSurege来设定,同时会再次计算当前的RS的全部Pod,若是发现Pod数量过多即超过Deployment的Replicas+maxSurge,则也不会进行操做

// Find the total number of pods
		currentPodCount := GetReplicaCountForReplicaSets(allRSs)
		// 最大pod数量
		maxTotalPods := *(deployment.Spec.Replicas) + int32(maxSurge)
		// 当前pod数量》总的运行的pod数量
		if currentPodCount >= maxTotalPods {
			// Cannot scale up.
			return *(newRS.Spec.Replicas), nil
		}

不然则就会进行计算容许scale up的数量

scaleUpCount := maxTotalPods - currentPodCount
		scaleUpCount = int32(integer.IntMin(int(scaleUpCount), int(*(deployment.Spec.Replicas)-*(newRS.Spec.Replicas))))

2.5.3 缩容旧的副本

缩容计数器的算法计算主要是根据Deployment的Replcas和maxUnavailable(经过surge和maxUnavailable)共同计算而来,最终的公式其实以下,有了缩容的数量,就能够更新旧ReplicaSet的数量了

minAvailable := *(deployment.Spec.Replicas) - maxUnavailable
	// 新副本不可用数量
	newRSUnavailablePodCount := *(newRS.Spec.Replicas) - newRS.Status.AvailableReplicas
	// 最大缩容大小=全部pod统计-最小不可用-新副本不可用副本
	maxScaledDown := allPodsCount - minAvailable - newRSUnavailablePodCount

整理以下

最小可用副本	 = Deployment的副本-最大不可用副本
		新副本不可用统计= 新副本数量-可用副本数量
		最大缩容数量   = 所有副本Pod计数-最小可用副本-新副本不可用统计

至此咱们知道了Deployment扩缩容的核心的副本计算实现,也知道了扩缩容的流程,那还缺什么呢?答案是状态

2.5.4 Available状态

Deployment的状态主要是由新旧副本以及当前集群中的Pod决定的,其计算公式以下, 则认为当前可用不然即为不可用

前可用的副本数量计数>=Deployment的副本数量-最大不可用副本计数
if availableReplicas >= *(deployment.Spec.Replicas)-deploymentutil.MaxUnavailable(*deployment) {
		minAvailability := deploymentutil.NewDeploymentCondition(apps.DeploymentAvailable, v1.ConditionTrue, deploymentutil.MinimumReplicasAvailable, "Deployment has minimum availability.")
		deploymentutil.SetDeploymentCondition(&status, *minAvailability)
	} else {
 		noMinAvailability := deploymentutil.NewDeploymentCondition(apps.DeploymentAvailable, v1.ConditionFalse, deploymentutil.MinimumReplicasUnavailable, "Deployment does not have minimum availability.")
		deploymentutil.SetDeploymentCondition(&status, *noMinAvailability)
	}

2.5.5 Processing状态

首先并非全部的Deployment都有该状态,只有设置了progressDeadlineSeconds参数的才会有该状态,其主要实在Deployment未完成的时候,进行一些状态决策,从而避免一个Deployment无期限的运行,其关键状态有两个即运行中与超时决策, 其流程实现上分为两步 1)首先若是判断是正在运行中,就更新LastTransitionTime

condition := util.NewDeploymentCondition(apps.DeploymentProgressing, v1.ConditionTrue, util.ReplicaSetUpdatedReason, msg)

condition.LastTransitionTime = currentCond.LastTransitionTime

2)超时检测则及时经过记录以前的转换时间,而后决策是否超时

from := condition.LastUpdateTime
	now := nowFn()
	delta := time.Duration(*deployment.Spec.ProgressDeadlineSeconds) * time.Second
	timedOut := from.Add(delta).Before(now)

2.5.6 ReplicaFailure状态

 该状态相对简单,检测当前的全部的副本,若是发现有副本失败,就取最新的一条失败的信息来填充Condition

3. 小结

image.png

更新机制的核心实现可能就这些,代码实现上仍是相对复杂的,主要是集中在为了保证伸缩和更新时为了保证可用性而作了大量的计算,还有不少的边界条件的处理,先就关注到这里,里面的具体的更细的细节,等出问题的时候,再详细琢磨,今天就到这里了

kubernetes学习笔记地址: https://www.yuque.com/baxiaoshi/tyado3

微信号:baxiaoshi2020 关注公告号阅读更多源码分析文章 图解源码 更多文章关注 www.sreguide.com

相关文章
相关标签/搜索