Kubernetes與容器設計模式

振宇要低調發表於2017-03-07

  在程式設計領域,物件導向設計和麵向物件語言是大家最為熟悉和強大的工具,而物件導向除了其強大的核心特性之外,還有人們通過實踐總結出來的一系列設計模式,可以用來解決實際應用設計中的一些複雜問題。

  雲原生應用執行的環境都是複雜的分散式環境,在這種情況下,一些有用的設計模式可以起到四兩撥千斤的作用,而K8s社群推出的容器設計模式,則是結合了K8s叢集的微服務模型提出的一系列可重用的解決典型分散式系統問題的模式。目前K8s社群推出的容器設計模式主要分為三大類:

    1)        單容器管理模式;

    2)        單節點多容器模式;

    3)        多節點多容器模式;

一、單容器管理模式

  K8s的最大特色是支援多容器的微服務例項。當然,單容器的模式也是支援的,只不過這種模式並不能突出K8s的特色和強大。很多人對K8s一直以來的印象是:功能強大,但入門較難。其實,單單就啟動一個單容器微服務例項,K8s的命令列操作跟Docker原生命令一樣簡單。

[root@demo-k8s ~]# kubectl run nginx --image=nginx
deployment "nginx" created
[root@demo-k8s ~]# kubectl get deployment
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx     1         1         1            1           24s
[root@demo-k8s ~]# kubectl get rs
NAME               DESIRED   CURRENT   AGE
nginx-3137573019   1         1         1m

  由上面的例子可以看到,K8s只要一個命令既可以啟動以nginx為映象的一個微服務例項。與此同時,K8s的強大之處在於,方便使用者用一個命令的同時,仍然保證了K8s應用體系的完整性和規範性。也就是說,雖然使用者只執行了一個命令,但K8s為使用者自動建立了四種API物件,包括:Deployment,ReplicaSet(RS),Pod和Container。要想擴充套件伸縮同一服務的例項個數也非常簡單。

[root@demo-k8s ~]# kubectl scale deployment nginx --replicas=3
deployment "nginx" scaled
[root@demo-k8s ~]# kubectl get rs
NAME               DESIRED   CURRENT   AGE
nginx-3137573019   3         3         22m

  依靠這種兼顧易用性和模型一致性的設計理念,K8s使自己既適合簡單場景也適合複雜場景。

二、單節點多容器模式

  從單節點多容器模式開始的容器設計模式,是真正體現K8s設計特點的地方,也就是基於多容器微服務模型的分散式應用模型。在K8s體系中,Pod是一個輕量級的節點,同一個Pod中的容器可以共享同一塊儲存空間和同一個網路地址空間,這使得我們可以實現一些組合多個容器在同一節點工作的模式。既然Pod的特點是共享儲存空間和網路地址,那麼單節點多容器模式一定是利用這兩種特性的。

2.1 挎鬥模式(Sidecar pattern)

  第一種單節點多容器模式是挎鬥模式。這種模式主要是利用在同一Pod中的容器可以共享儲存空間的能力。

  一個典型的挎鬥應用場景如圖所示:一個工具容器寫檔案到共享的檔案目錄,應用主容器從共享的檔案目錄讀檔案。例如,我們可以用Nginx構建一個程式碼釋出倉庫,簡單的將程式碼放到某個本地目錄即可。為了保持同步,我們同時用一個裝有Git客戶端的容器定時到原始程式碼倉庫同步下拉最新的程式碼。這種模式的好處是,工具容器的映象,也就是打包有Git客戶端的映象可以重用,而不需要跟應用的容器打包在一起。同樣的應用,應用主容器不用Nginx也可以用Apache Httpd,都可以跟工具容器組合起來形成微服務。

  另一個典型的挎鬥模式如圖所示:一個工具容器讀檔案,應用容器寫檔案。例如:一個基於Nginx的Web應用向系統檔案系統寫入日誌,而一個收集日誌的容器從共享目錄讀出日誌,並輸出到叢集的日誌系統。這一模式的好處在於,工具容器的映象是可以重用的,不需要在每次更新應用容器打包的時候,把工具容器的執行檔案打包進去。

2.2 外交官模式(Ambassador pattern)

  第二種單節點多容器模式是外交官模式。這種模式主要利用同一Pod中的容器可以共享網路地址空間的特性。如圖所示,在一個Pod中給應用容器搭配一個工具容器作為代理伺服器。工具容器幫助應用容器訪問外部服務,使得應用容器訪問服務時不需要使用外網的IP地址,而只需要用localhost訪問本地服務。在這種模式下,作為代理伺服器的工具容器好像外部服務派駐在Pod中的“外交官”,使得應用容器辦理業務時只需要跟本Pod的外交官打交道,而不需要出國了,因此而得名。

2.2.1基於外交官模式的Redis訪問案例

2.3 介面卡模式(Adapter pattern)

  第三種單節點多容器模式是介面卡模式。這種模式對於監控和管理分散式系統尤為重要。對分散式系統的一種理想設計目標,就是能夠實現“分佈地執行和儲存,統一的監控和管理”。要想實現“統一的監控和管理”,應用和監控管理互動的介面需要是統一的,而且其介面是依照“統一的監控服務”的介面模式來實現。這和麵向物件設計模式中的“介面卡模式”也非常相似。

  一個典型的可以採用介面卡模式的系統,是利用Prometheus作為監控服務的分散式系統。在Prometheus周邊專案中,有諸多適用於不同應用系統的監控資料輸出器(Exporter),負責收集跟特定應用相關的監控資料,使得Prometheus服務可以以統一的資料模式收集不同應用系統的監控資料,每個Exporter同時也都是一個介面卡模式的實現。

三、多節點組合模式

3.1 多節點選舉模式

  多節點選舉在分散式系統中是一種重要的模式,特別是對有狀態服務來說。在分散式系統中,一般來說,無狀態服務,可以隨意的水平伸縮,只要把執行業務邏輯的例項複製出去執行就可以,這也就是K8s裡ReplicationController和ReplicaSet所做的事情。

  對於有狀態服務,人們也希望能夠水平的擴充套件,但因為每個例項有自己的持久化狀態,而這個持久化狀態必須要延續它的生命,因此,有狀態服務的水平伸縮模式就是狀態的分片,其中機制跟資料庫的分片是一致的。那麼對於一個原生為分散式系統設計的有狀態服務,每個例項與分片資料的對應關係,就成為這個有狀態服務的全域性資訊。對於任何服務,多個例項的全域性資訊都需要一個儲存的地方。

  一個簡單的辦法是儲存在外部的一個代理伺服器上,這也就是MariaDB的Galera解決方案的做法,也是所以代理伺服器為後端伺服器所做的事情。但這種方式的問題在於,系統要依賴外部代理伺服器,而代理伺服器本身的高可用和水平伸縮還是沒有解決的問題。

  所以對於要原生自己解決高可用和水平伸縮問題的系統,例如Etcd和ElasticSearch,一定要有原生的主控節點選舉機制。這樣這個分散式系統就不需要依賴外部的系統來維護自己的狀態了。對於一個分散式系統,最主要的系統全域性資訊,就是叢集中有哪些節點,Master節點是哪個,每個節點對應哪個分片。主控節點的任務,就是儲存和分發這些資訊。

   在K8s叢集中,一個微服務例項Pod可以有多個容器。這一特性很好地提高了多節點選舉機制的可重用性。它使得我們可以專門開發一個用於選舉的容器映象,在實際部署中,將選舉容器和普通應用容器組合起來,應用容器只需要從本地的選舉容器讀取狀態,就可以得到選舉結果。這樣,使得應用容器可以只關注自身業務邏輯相關的程式碼。

3.2工作佇列模式

  分散式系統的一個重要作用是能夠充分利用多個物理計算資源的能力,特別是在動態按需調動計算資源完成計算任務。設想如果有大量的需要處理的任務隨機的到來,對計算資源需要的容量是不確定地;顯然,按照最大可能計算量和最小可能計算量設定計算節點都是不合理的。

  這種情況下,可以把需要處理的任務放到一個待處理的佇列裡,根據需要啟動計算節點從佇列讀取任務進行處理。在容器技術廣泛應用之前,也有諸多的分散式處理系統依靠佇列來處理大量計算任務,例如大資料處理系統Hadoop和Spark等。這些系統的一個限制是實現佇列處理模式大多要遵循特定的程式設計模式和特定的程式語言,同時搭建基礎設施也大多複雜而耗時。而基於容器和Kubernetes編排技術的工作佇列模式的好處在於,利用非常簡單的編排指令碼就可以實現工作佇列模式,而用Pod作為輕量級處理節點的模式,使得動態的排程計算資源變得非常容易。在Kubernetes中應用工作佇列模式的邏輯示意圖如下:

3.3 分散收集模式

  分散收集模式利用分散式系統彈性計算能力的容器設計模式。在這一模式中,計算服務的使用者,即服務的客戶端,將初始計算請求傳送給一個“根計算節點”。根計算節點對計算任務做出分割,將任務分割成大量的小計算任務,然後將小計算任務分配給大量計算伺服器進行分散式平行計算 。每個計算伺服器都計算初始計算任務的一小塊,將計算結果返回給根計算節點。根計算節點將所有計算結果合併起來,組成一個針對初始計算任務的一個統一的結果,返回給申請計算任務的客戶端。

  這一系統中的分散式伺服器非常適合用容器技術來實現,具體到K8s系統中,就是一個K8s的Pod;具體到Docker系統中,就是一個Docker容器。利用容器快速部署啟動和執行時開銷特別小的特點,任務可以被分到很多小伺服器上並行處理,這些容器形成的小伺服器跟其他任務共同使用基礎設施計算節點的能力。

  一個典型的分散收集模式的分散式系統如下圖所示。根節點接受到來自客戶端的服務請求,將服務請求分配給不同的業務模組分散處理,處理結果收集到根節點,經過一定的匯聚合併運算,產生一個合併的結果交付給客戶端。

 

  宣告:本文並非原創,只是本人在學習容器設計模式過程中,對一些網路資料的整理。主要參考於:《Kubernetes與雲原生應用》系列之容器設計模式

相關文章