圖解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

相關文章
相關標籤/搜索