1. 程式人生 > >Kubernetes設計和開發四大基本原則

Kubernetes設計和開發四大基本原則

作者介紹:Saad Ali 是來自Google的高階軟體工程師,致力於開源Kubernetes專案。他於201412加入該專案並負責Kubernetes儲存和volume子系統的開發。他還擔任Kubernetes儲存興趣小組的負責人,同時也是CSI(容器儲存介面)的協同開發者和maintainer。在加入Google之前,Saad Ali於微軟負責IMAP原型開發專案。

 

 

 

Kubernetes正在迅速成為在分散式系統上部署工作負載的事實標準。在這篇文章中,筆者將通過揭示其設計的一些原則,幫助你更深入地瞭解Kubernetes。

 

 

1、要宣告式而不要命令式

 

一旦你學會在Kubernetes開源編排引擎上部署第一個工作負載(pod),就會遇到Kubernetes的第一個原則:Kubernetes API是宣告性的而不是命令式的。

在命令式API中,你可以直接發出伺服器要執行的命令,例如: “執行容器”、“停止容器”等。在宣告性API中,你宣告系統要執行的操作,系統將不斷向該狀態驅動。

可以想象成手動駕駛和自動駕駛系統。

因此,在Kubernetes中,你建立一個API物件(使用CLI或REST API)來表示你希望系統執行的操作。系統中的所有元件都會向該狀態發展,直到刪除該物件。

例如,如果要排程容器化工作負載,不是發出“執行容器”命令,而是建立描述所需狀態的API物件、pod:

建立後,此物件在API伺服器上保留:

 

如果容器由於某種原因崩潰,系統將重新啟動容器。

要終止容器,請刪除pod物件:

為什麼要宣告式而不要命令式?

宣告式API使系統更加健壯。

在分散式系統中,任何元件都可能隨時出現故障。當元件恢復時,需要弄清楚要做什麼。

使用命令式API時,崩潰的元件可能在它關閉時錯過了一個呼叫,並且需要一些外部元件在它恢復時“趕上”。但是使用宣告式API,元件只需檢視API伺服器的當前狀態,即可確定它需要執行的操作(“啊,我需要確保此容器正在執行”)。

這也被描述為“水平觸發”而不是“邊緣觸發”。在邊緣觸發系統中,如果系統錯過“事件”(“邊緣”),則必須重放事件以便系統恢復。在水平觸發系統中,即使系統錯過了“事件”(可能是因為它已經關閉),當它恢復時,它可以檢視訊號的當前狀態並相應地做出響應。

因此,宣告式API使Kubernetes系統對元件故障更加健壯。

 

2、沒有隱藏的內部API


如果你瞭解各種Kubernetes元件的工作原理,你會遇到Kubernetes的下一個原則:控制平面是透明的,因為沒有隱藏的內部API。

這意味著Kubernetes元件用來互動的API和你用來與Kubernetes互動的API相同。結合第一個原則(Kubernetes API是宣告式的),這意味著Kubernetes元件只能通過監控和修改Kubernetes API來互動。

讓我們通過一個簡單的例子來說明這一點。為了啟動容器化工作負載,你可以在Kubernetes API伺服器上建立一個pod物件,如上所示。

Kubernetes排程程式根據可用資源確定執行pod的最佳節點。排程程式通過為新pod物件監控Kubernetes API伺服器來完成此操作。當新的未排程的pod被建立時,排程程式將執行其演算法為這個pod查詢最佳節點。在排程pod之後(已為pod選擇了最佳節點),排程程式不會去告訴所選節點要啟動pod。請記住,Kubernetes API是宣告式的,內部元件使用相同的API。因此,排程程式更新pod物件中的NodeName欄位以指示已經排程該pod。

kubelet(在節點上執行的Kubernetes代理)監控Kubernetes API(就像其他Kubernetes元件一樣)。當kubelet看到具有與自身對應的NodeName欄位的pod時,它知道改pod已經被排程且必須啟動它。一旦kubelet啟動了pod,它就會繼續為pod監控容器狀態,並且只要相應的pod物件繼續存在於API伺服器中,就會一直讓容器保持執行。

刪除pod物件後,Kubelet會明白不再需要容器,並終止它。

 

為什麼沒有隱藏的內部API?

讓Kubernetes元件使用相同的外部API使得Kubernetes可組合和可擴充套件。

如果由於某種原因,Kubernetes的預設元件(例如,排程程式)不足以滿足你的需求,你可以將其關閉並將其替換為自己的使用相同API的元件。

此外,如果你需要的功能尚不可用,則可以使用公共API輕鬆編寫元件以擴充套件Kubernetes功能。

 

3、在使用者所在的位置滿足他們

 

Kubernetes API允許儲存工作負載可能感興趣的資訊。例如,Kubernetes API可用於儲存祕密或配置對映。祕密可以是你在容器映象中不想要的任何敏感資料,包括密碼、證書等。配置對映可以包含應獨立於容器映象的配置資訊,例如應用程式啟動和其他類似引數。

由於上面定義的沒有隱藏的內部API的第二個原則,可以修改在Kubernetes上執行的應用程式以直接從Kubernetes API伺服器獲取祕密或配置對映資訊。但這意味著你需要修改應用程式以意識到它是在Kubernetes中執行。

這就是Kubernetes的第三個原則:在使用者所在的位置滿足他們。也就是說,Kubernetes不應要求重寫要在Kubernetes上執行的應用程式。

 

例如,許多應用程式接受祕密和配置資訊作為檔案或環境變數。因此,Kubernetes支援將祕密和配置對映作為檔案或環境變數注入pod。

 

為什麼要這麼做?

通過進行設計選擇,最大限度地減少在Kubernetes上部署工作負載的障礙,Kubernetes可以輕鬆地執行現有工作負載,而無需重寫或大幅改變它們。

 

4、工作負載可移植性

 

一旦在Kubernetes上執行無狀態工作負載,下一步自然就是嘗試在Kubernetes上執行有狀態工作負載。Kubernetes提供了一個功能強大的卷外掛系統,可以將許多不同型別的持久儲存系統與Kubernetes工作負載一起使用。

例如,使用者可以輕鬆地請求將Google Cloud Persistent Disk安裝到特定路徑的pod中:

建立此pod時,Kubernetes將自動負責將指定的GCE PD掛載到pod被排程到的節點,並將其掛載到指定的容器中。然後,容器可以在容器或pod的生命週期之外寫入GCE PD被掛載到持久資料的路徑。

此方法的問題在於pod定義(pod YAML)直接引用Google Cloud Persistent Disk。如果此pod已部署在非Google Cloud Kubernetes叢集上,則無法啟動(因為GCE PD無法使用)。

這是另一個Kubernetes原則的用武之地:工作負載定義應該可以跨叢集移植。使用者應該能夠使用相同的工作負載定義檔案(例如相同的pod yaml)來跨不同的叢集可以部署工作負載。

理想情況下,上面指定的pod甚至應該可以在沒有GCE PD的叢集上執行。為了實現這一目標,Kubernetes引入了PersistentVolumeClaim(PVC)和PersistentVolume(PV)API物件。這些物件將儲存實現與儲存使用分離。

PersistentVolumeClaim物件用作使用者以與實現無關的方式請求儲存的方法。例如,使用者可以建立PVC物件來請求100 GB的ReadWrite儲存,而不是請求特定的GCE PD:

Kubernetes系統將此請求與來自包含PersistentVolume物件的可用磁碟池中的卷匹配,或自動配置新卷以滿足請求。無論哪種方式,用於Kubernetes叢集部署工作負載的物件都可以跨叢集實現移植。

 

為什麼要有工作負載可移植性?

這種工作負載可移植性原則突出了Kubernetes的核心優勢:與作業系統使應用程式開發人員不必擔心底層硬體的細節一樣,Kubernetes將分散式系統應用程式開發人員從底層叢集的細節中解放出來。使用Kubernetes,分散式系統應用程式開發人員不必被鎖定到特定的叢集環境。針對Kubernetes部署的應用程式可以輕鬆地部署到本地和雲環境中的各種叢集,而無需對應用程式或部署指令碼進行特定於環境的更改(Kubernetes端點除外)。

 

5、結論

 

由於這些原則,Kubernetes更強大,可擴充套件,可移植且易於遷移。這就是Kubernetes迅速成為在分散式系統上部署工作負載的行業標準的原因。