若是你對容器稍有涉獵,應該知道:Pod這個看似複雜的API對象,實際上就是對容器的進一步抽象和封裝而已。node
說得更形象些,「容器」鏡像雖然好用,可是容器這樣一個「沙盒」的概念,對於描述應用來講,仍是太過簡單了。這就比如,集裝箱當然好用,可是若是它四面都光禿禿的,吊車還怎麼把這個集裝箱吊起來並擺放好呢?nginx
因此,Pod對象,其實就是容器的升級版。它對容器進行了組合,添加了更多的屬性和字段。這就比如給集裝箱四面安裝了吊環,使得Kubernetes這架「吊車」,能夠更輕鬆地操做它。編程
而Kubernetes操做這些「集裝箱」的邏輯,都由控制器(Controller)完成。在專欄的第12篇文章《牛刀小試:個人第一個容器化應用》中,咱們曾經使用過Deployment這個最基本的控制器對象。api
如今,咱們一塊兒來回顧一下這個名叫nginx-deployment的例子:bash
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項目中的哪一個組件,在執行這些操做呢?app
在Kubernetes架構中,有一個叫做kube-controller-manager的組件。oop
實際上,這個組件,就是一系列控制器的集合。咱們能夠查看一下Kubernetes項目的pkg/controller目錄:ui
$ 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語言風格的僞代碼,爲你描述這個控制循環:
for {
實際狀態 := 獲取集羣中對象X的實際狀態(Actual State)
指望狀態 := 獲取集羣中對象X的指望狀態(Desired State)
if 實際狀態 == 指望狀態{
什麼都不作
} else {
執行編排動做,將實際狀態調整爲指望狀態
}
}複製代碼
在具體實現中,實際狀態每每來自於Kubernetes集羣自己。
好比,kubelet經過心跳彙報的容器狀態和節點狀態,或者監控系統中保存的應用監控數據,或者控制器主動收集的它本身感興趣的信息,這些都是常見的實際狀態的來源。
而指望狀態,通常來自於用戶提交的YAML文件。
好比,Deployment對象中Replicas字段的值。很明顯,這些信息每每都保存在Etcd中。
接下來,以Deployment爲例,我和你簡單描述一下它對控制器模型的實現:
能夠看到,一個Kubernetes對象的主要編排邏輯,其實是在第三步的「對比」階段完成的。
這個操做,一般被叫做調諧(Reconcile)。這個調諧的過程,則被稱做「Reconcile Loop」(調諧循環)或者「Sync Loop」(同步循環)。
因此,若是你之後在文檔或者社區中碰到這些詞,都不要擔憂,它們其實指的都是同一個東西:控制循環。
而調諧的最終結果,每每都是對被控制對象的某種寫操做。
好比,增長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對象麼?
這個問題的答案,我會在「深刻剖析Kubernetes」專欄第33講深刻解析容器跨主機網絡中進行詳細解釋。
文章相關:
完整文章: 極客時間「深刻剖析Kubernetes」第32講 | 淺談容器網絡