什么是編排 |
Kubernetes中,我們總是在說一個概念:編排.
在[Kubernetes]談談Kubernetes的本質這篇文章中,關於"編排"的概念介紹了一下:過去很多集群管理項目所擅長的都是把一個容器,按照某種規則,放置在某個最佳節點上運行起來,這種功能我們稱為"調度".但Kubernetes項目所擅長的,是按照用戶的意願和整個系統的規則,完全自動化處理好容器之間的各種關系,這種功能,叫做編排.
這篇文章就嘗試來講一下,編排.
編排是如何實現的 |
不知道你對kube-controller-manager這個組件還有沒有印象.這個組件實際上就是一系列控制器的集合.而Deployment,正是一系列控制器集合中的一種.
咱們來舉個例子,來解釋一下Deployment的作用.現在定義一個nginx的YAML文件,內容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
我們可以看到,這個Deployment定義的編排動作非常簡單,要做的就是:確保攜帶了app=nginx標簽的Pod的個數,永遠等於spec.replicas指定的個數,即2個.
這意味着,如果在這個集群中,攜帶app=nginx標簽的個數大於2的時候,就會有舊的Pod被刪除;反之,則會有新的Pod被創建.
在這里,我們需要提到一個概念:控制循環.我先上一段偽代碼,來描述一下控制循環概念:
for {
實際狀態 = 獲取集群中對象 X 的實際狀態(Actual State)
期望狀態 = 獲取集群中對象 X 的期望狀態(Desired State)
if 實際狀態 == 期望狀態{
什么都不做
} else {
執行編排動作,將實際狀態調整為期望狀態
}
}
應該能夠看出,實際狀態往往來自Kubernetes集群本身.而期望狀態,一般來自於用戶提交的YAML文件.基於上面的偽代碼,來講講,Deployment是如何實現控制循環的.
- 1,Deployment控制器從Etcd中獲取到所有攜帶了"app:nginx"標簽的Pod,然后統計它們的數量,這就是實際狀態;
- 2,Deployment對象的Replicas字段的值就是期望狀態;
- 3,Deployment控制器將兩個狀態作比較,然后根據比較結果,確定是創建Pod,還是刪除已有的Pod
控制器的完整實現 |
上面只是一個概述.這一部分詳細講講控制器的完整實現:Deployment.
Deployment看似簡單,但實際上,它實現了Kubernetes項目中一個非常重要的功能:Pod的"水平擴展/收縮".
比較難以理解?沒關系,咱們來舉個例子.假設更新了Deployment的Pod模板(比如,修改了容器的鏡像),那么Deployment就需要遵循一種叫做"滾動更新"的方式,來升級現有的容器,而這個能力的實現,依賴的是Kubernetes中一個非常重要的API對象:ReplicaSet.它的組成也很簡單:副本數目的定義和一個Pod模板.
我們可以發現,所謂的ReplicaSet對象,其實是Deployment的一個子集.而實際上,Deployment控制器實際操縱的,正是這樣的ReplicaSet對象,而不是Pod對象.
在這個基礎上,咱們一起來分析一下下面的這個Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
從上面我們可以看到,這就是一個nginx-deployment,它定義的Pod副本個數是3(spec.replicas=3).具體實現是這樣的:
這樣我們就能很清楚的看到了,Deployment,ReplicaSet,Pod之間,是一種"層層控制"的關系.ReplicaSet負責通過"控制器模式",保證系統中Pod的個數永遠等於指定的個數.這也是在Deployment中,為什么只允許容器的restartPolicy=Always的原因:只有在容器能保證自己始終是Running狀態的前提下,ReplicaSet調整Pod的個數才有意義.
在此基礎上,Deployment同樣通過"控制器模式",來操作ReplicaSet的個數和屬性,進而實現"水平擴展/收縮"和"滾動更新"這兩個編排動作."水平擴展/收縮"非常容易實現,Deployment Controller只需要修改它所控制的ReplicaSet的Pod副本個數就可以了.而在"滾動更新"這個動作中,它有一個狀態轉換的過程:
- DESIRED:用戶期望的Pod副本數(spec.replicas的值);
- CURRENT:當前處於Running狀態的Pod的個數;
- UP-TO-DATE:當前處於最新版本的Pod的個數,就是說,Pod的Spec部分與Deployment中Pod模板里定義的完全一致;
- AVAILABLE:當前已經可用的Pod的個數,即:既是Running狀態,又是最新版本,並且已經處於Ready(健康檢查正確)狀態的Pod的個數
滾動更新的詳細過程 |
在這一部分,我詳細講述一下"滾動更新"這個過程.這樣,會對"滾動更新"的好處,有一個比較好的理解.
來個小前提:假設我需要"滾動更新"3個Pod.
當我修改了Deployment里的Pod定義之后,Deployment Controller會使用這個修改后的Pod模板,創建一個新的ReplicaSet,此時這個ReplicaSet的初始Pod副本數是:0;
然后,Deployment Controller開始將這個新的ReplicaSet所控制的Pod副本數從0個變成1個,即:"水平擴展"出一個副本;
緊接着,Deployment Controller又將舊的ReplicaSet所控制的舊Pod副本數減少一個,即:“水平收縮"成兩個副本.
如此交替進行,新ReplicaSet管理的Pod副本數,從0個變成1個,再變成2個,最后變成3個.與此同時,舊的ReplicaSet管理的Pod副本數則從3個變成2個,再變成1個,最后變成0個.
像這樣,將一個集群中正在運行的多個Pod版本,交替地逐一升級過程,就是"滾動更新”
在你詳細了解"滾動更新"的過程之后,你就會對它所帶來的好處,有一個好的了解.
比如,在升級剛開始的時候,集群里只有1個新版本的Pod,如果這個時候,新版本Pod有問題啟動不起來,那么"滾動更新"就會停止,允許開發和運維人員介入解決問題,而這個應用本身還有兩個舊版本的Pod在線,所以服務不會受到太大的影響.
想和大家分享的內容,講的差不多了
以上內容來自我學習<深入剖析Kubernetes>專欄文章之后的一些見解,有偏頗之處,還望指出.
感謝您的閱讀~