Pod 這個看似複雜的 API 對象,實際上就是對容器的進一步抽象和封裝而已。 說得更形象些,「容器」鏡像雖然好用,可是容器這樣一個「沙盒」的概念,對於描述應用來講, 仍是太過簡單了。node
這就比如,集裝箱當然好用,可是若是它四面都光禿禿的,吊車還怎麼把這個集 裝箱吊起來並擺放好呢? 因此,Pod 對象,其實就是容器的升級版。它對容器進行了組合,添加了更多的屬性和字段。這就 比如給集裝箱四面安裝了吊環,使得 Kubernetes 這架「吊車」,能夠更輕鬆地操做它。 而 Kubernetes 操做這些「集裝箱」的邏輯,都由控制器(Controller)完成。咱們曾經使用過 Deployment 這個最基本的控制器對 象。 如今,咱們一塊兒來回顧一下這個名叫 nginx-deployment 的例子:nginx
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 標籤的 Pod 的個數大於 2 的時候,就會有舊的 Pod 被刪除;反之,就會有新的 Pod 被建立。 這時,你也許就會好奇:到底是 Kubernetes 項目中的哪一個組件,在執行這些操做呢?api
我在前面介紹 Kubernetes 架構的時候,曾經提到過一個叫做 kube-controller-manager 的組件。 實際上,這個組件,就是一系列控制器的集合。咱們能夠查看一下 Kubernetes 項目的 pkg/controller 目錄:架構
$ cd kubernetes/pkg/controller/ $ ls -d */ deployment/ job/ podautoscaler/ cloud/ disruption/ namespace/ replicaset/ serviceaccount/ volume/ cronjob/ garbagecollector/ nodelifecycle/ replication/ statefulset/ daemon/ ...
這個目錄下面的每個控制器,都以獨有的方式負責某種編排功能。而咱們的 Deployment,正是 這些控制器中的一種。 實際上,這些控制器之因此被統一放在 pkg/controller 目錄下,就是由於它們都遵循 Kubernetes 項目中的一個通用編排模式,即:控制循環(control loop)。 好比,如今有一種待編排的對象 X,它有一個對應的控制器。那麼,我就能夠用一段 Go 語言風格 的僞代碼,爲你描述這個控制循環:app
for { 實際狀態 := 獲取集羣中對象 X 的實際狀態(Actual State) 指望狀態 := 獲取集羣中對象 X 的指望狀態(Desired State) if 實際狀態 == 指望狀態{ 什麼都不作 } else { 執行編排動做,將實際狀態調整爲指望狀態 } }
在具體實現中,實際狀態每每來自於 Kubernetes 集羣自己。 好比,kubelet 經過心跳彙報的容器狀態和節點狀態,或者監控系統中保存的應用監控數據,或者控 制器主動收集的它本身感興趣的信息,這些都是常見的實際狀態的來源。 而指望狀態,通常來自於用戶提交的 YAML 文件。框架
好比,Deployment 對象中 Replicas 字段的值。很明顯,這些信息每每都保存在 Etcd 中。 接下來,以 Deployment 爲例,我和你簡單描述一下它對控制器模型的實現:oop
- 1. Deployment 控制器從 Etcd 中獲取到全部攜帶了「app: nginx」標籤的 Pod,而後統計它們的 數量,這就是實際狀態;
- 2. Deployment 對象的 Replicas 字段的值就是指望狀態;
- 3. Deployment 控制器將兩個狀態作比較,而後根據比較結果,肯定是建立 Pod,仍是刪除已有的 Pod(具體如何操做 Pod 對象,我會在下一篇文章詳細介紹)。
能夠看到,一個 Kubernetes 對象的主要編排邏輯,其實是在第三步的「對比」階段完成的。 這個操做,一般被叫做調諧(Reconcile)。這個調諧的過程,則被稱做「Reconcile Loop」(調諧 循環)或者「Sync Loop」(同步循環)。 因此,若是你之後在文檔或者社區中碰到這些詞,都不要擔憂,它們其實指的都是同一個東西:控 制循環。 而調諧的最終結果,每每都是對被控制對象的某種寫操做。spa
好比,增長 Pod,刪除已有的 Pod,或者更新 Pod 的某個字段。這也是 Kubernetes 項目「面向 API 對象編程」的一個直觀體現。 其實,像 Deployment 這種控制器的設計原理,就是咱們前面提到過的,「用一種對象管理另外一種 對象」的「藝術」。 其中,這個控制器對象自己,負責定義被管理對象的指望狀態。好比,Deployment 裏的 replicas=2 這個字段。設計
而被控制對象的定義,則來自於一個「模板」。好比,Deployment 裏的 template 字段。 能夠看到,Deployment 這個 template 字段裏的內容,跟一個標準的 Pod 對象的 API 定義,絲毫 不差。而全部被這個 Deployment 管理的 Pod 實例,其實都是根據這個 template 字段的內容建立 出來的。
像 Deployment 定義的 template 字段,在 Kubernetes 項目中有一個專有的名字,叫做 PodTemplate(Pod 模板)。 這個概念很是重要,由於後面我要講解到的大多數控制器,都會使用 PodTemplate 來統必定義它 所要管理的 Pod。更有意思的是,咱們還會看到其餘類型的對象模板,好比 Volume 的模板。 至此,咱們就能夠對 Deployment 以及其餘相似的控制器,作一個簡單總結了:
如上圖所示,相似 Deployment 這樣的一個控制器,實際上都是由上半部分的控制器定義(包括期 望狀態),加上下半部分的被控制對象的模板組成的。
這就是爲何,在全部 API 對象的 Metadata 裏,都有一個字段叫做 ownerReference,用於保存 當前這個 API 對象的擁有者(Owner)的信息。 那麼,對於咱們這個 nginx-deployment 來講,它建立出來的 Pod 的 ownerReference 就是 nginx-deployment 嗎?或者說,nginx-deployment 所直接控制的,就是 Pod 對象麼? 這個問題的答案,我就留到下一篇文章時再作詳細解釋吧。
總結
不少不一樣類型的容器編排功能,好比 StatefulSet、DaemonSet 等 等,它們無一例外地都有這樣一個甚至多個控制器的存在,並遵循控制循環(control loop)的流 程,完成各自的編排邏輯。 實際上,跟 Deployment 類似,這些控制循環最後的執行結果,要麼就是建立、更新一些 Pod(或 者其餘的 API 對象、資源),要麼就是刪除一些已經存在的 Pod(或者其餘的 API 對象、資源)。 但也正是在這個統一的編排框架下,不一樣的控制器能夠在具體執行過程當中,設計不一樣的業務邏輯, 從而達到不一樣的編排效果。 這個實現思路,正是 Kubernetes 項目進行容器編排的核心原理。在此後講解 Kubernetes 編排功 能的文章中,我都會遵循這個邏輯展開,而且帶你逐步領悟控制器模式在不一樣的容器化做業中的實 現方式。