在程序設計領域,面向對象設計和麪向對象語言是你們最爲熟悉和強大的工具,而面向對象除了其強大的核心特性以外,還有人們經過實踐總結出來的一系列設計模式,能夠用來解決實際應用設計中的一些複雜問題。html
雲原生應用運行的環境都是複雜的分佈式環境,在這種狀況下,一些有用的設計模式能夠起到四兩撥千斤的做用,而K8s社區推出的容器設計模式,則是結合了K8s集羣的微服務模型提出的一系列可重用的解決典型分佈式系統問題的模式。目前K8s社區推出的容器設計模式主要分爲三大類:nginx
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的特色是共享存儲空間和網絡地址,那麼單節點多容器模式必定是利用這兩種特性的。app
第一種單節點多容器模式是挎鬥模式。這種模式主要是利用在同一Pod中的容器能夠共享存儲空間的能力。編程語言
一個典型的挎鬥應用場景如圖所示:一個工具容器寫文件到共享的文件目錄,應用主容器從共享的文件目錄讀文件。例如,咱們能夠用Nginx構建一個代碼發佈倉庫,簡單的將代碼放到某個本地目錄便可。爲了保持同步,咱們同時用一個裝有Git客戶端的容器定時到原始代碼倉庫同步下拉最新的代碼。這種模式的好處是,工具容器的鏡像,也就是打包有Git客戶端的鏡像能夠重用,而不須要跟應用的容器打包在一塊兒。一樣的應用,應用主容器不用Nginx也能夠用Apache Httpd,均可以跟工具容器組合起來造成微服務。
另外一個典型的挎鬥模式如圖所示:一個工具容器讀文件,應用容器寫文件。例如:一個基於Nginx的Web應用向系統文件系統寫入日誌,而一個收集日誌的容器從共享目錄讀出日誌,並輸出到集羣的日誌系統。這一模式的好處在於,工具容器的鏡像是能夠重用的,不須要在每次更新應用容器打包的時候,把工具容器的執行文件打包進去。
第二種單節點多容器模式是外交官模式。這種模式主要利用同一Pod中的容器能夠共享網絡地址空間的特性。如圖所示,在一個Pod中給應用容器搭配一個工具容器做爲代理服務器。工具容器幫助應用容器訪問外部服務,使得應用容器訪問服務時不須要使用外網的IP地址,而只須要用localhost訪問本地服務。在這種模式下,做爲代理服務器的工具容器好像外部服務派駐在Pod中的「外交官」,使得應用容器辦理業務時只須要跟本Pod的外交官打交道,而不須要出國了,所以而得名。
第三種單節點多容器模式是適配器模式。這種模式對於監控和管理分佈式系統尤其重要。對分佈式系統的一種理想設計目標,就是可以實現「分佈地執行和存儲,統一的監控和管理」。要想實現「統一的監控和管理」,應用和監控管理交互的接口須要是統一的,並且其接口是依照「統一的監控服務」的接口模式來實現。這和麪向對象設計模式中的「適配器模式」也很是類似。
一個典型的能夠採用適配器模式的系統,是利用Prometheus做爲監控服務的分佈式系統。在Prometheus周邊項目中,有諸多適用於不一樣應用系統的監控數據輸出器(Exporter),負責收集跟特定應用相關的監控數據,使得Prometheus服務能夠以統一的數據模式收集不一樣應用系統的監控數據,每一個Exporter同時也都是一個適配器模式的實現。
多節點選舉在分佈式系統中是一種重要的模式,特別是對有狀態服務來講。在分佈式系統中,通常來講,無狀態服務,能夠隨意的水平伸縮,只要把運行業務邏輯的實例複製出去運行就能夠,這也就是K8s裏ReplicationController和ReplicaSet所作的事情。
對於有狀態服務,人們也但願可以水平的擴展,但由於每一個實例有本身的持久化狀態,而這個持久化狀態必需要延續它的生命,所以,有狀態服務的水平伸縮模式就是狀態的分片,其中機制跟數據庫的分片是一致的。那麼對於一個原生爲分佈式系統設計的有狀態服務,每一個實例與分片數據的對應關係,就成爲這個有狀態服務的全局信息。對於任何服務,多個實例的全局信息都須要一個保存的地方。
一個簡單的辦法是保存在外部的一個代理服務器上,這也就是MariaDB的Galera解決方案的作法,也是因此代理服務器爲後端服務器所作的事情。但這種方式的問題在於,系統要依賴外部代理服務器,而代理服務器自己的高可用和水平伸縮仍是沒有解決的問題。
因此對於要原生本身解決高可用和水平伸縮問題的系統,例如Etcd和ElasticSearch,必定要有原生的主控節點選舉機制。這樣這個分佈式系統就不須要依賴外部的系統來維護本身的狀態了。對於一個分佈式系統,最主要的系統全局信息,就是集羣中有哪些節點,Master節點是哪一個,每一個節點對應哪一個分片。主控節點的任務,就是保存和分發這些信息。
在K8s集羣中,一個微服務實例Pod能夠有多個容器。這一特性很好地提升了多節點選舉機制的可重用性。它使得咱們能夠專門開發一個用於選舉的容器鏡像,在實際部署中,將選舉容器和普通應用容器組合起來,應用容器只須要從本地的選舉容器讀取狀態,就能夠獲得選舉結果。這樣,使得應用容器能夠只關注自身業務邏輯相關的代碼。
分佈式系統的一個重要做用是可以充分利用多個物理計算資源的能力,特別是在動態按需調動計算資源完成計算任務。設想若是有大量的須要處理的任務隨機的到來,對計算資源須要的容量是不肯定地;顯然,按照最大可能計算量和最小可能計算量設置計算節點都是不合理的。
這種狀況下,能夠把須要處理的任務放到一個待處理的隊列裏,根據須要啓動計算節點從隊列讀取任務進行處理。在容器技術普遍應用以前,也有諸多的分佈式處理系統依靠隊列來處理大量計算任務,例如大數據處理系統Hadoop和Spark等。這些系統的一個限制是實現隊列處理模式大多要遵循特定的編程模式和特定的編程語言,同時搭建基礎設施也大多複雜而耗時。而基於容器和Kubernetes編排技術的工做隊列模式的好處在於,利用很是簡單的編排腳本就能夠實現工做隊列模式,而用Pod做爲輕量級處理節點的模式,使得動態的調度計算資源變得很是容易。在Kubernetes中應用工做隊列模式的邏輯示意圖以下:
分散收集模式利用分佈式系統彈性計算能力的容器設計模式。在這一模式中,計算服務的使用者,即服務的客戶端,將初始計算請求發送給一個「根計算節點」。根計算節點對計算任務作出分割,將任務分割成大量的小計算任務,而後將小計算任務分配給大量計算服務器進行分佈式平行計算 。每一個計算服務器都計算初始計算任務的一小塊,將計算結果返回給根計算節點。根計算節點將全部計算結果合併起來,組成一個針對初始計算任務的一個統一的結果,返回給申請計算任務的客戶端。
這一系統中的分佈式服務器很是適合用容器技術來實現,具體到K8s系統中,就是一個K8s的Pod;具體到Docker系統中,就是一個Docker容器。利用容器快速部署啓動和運行時開銷特別小的特色,任務能夠被分到不少小服務器上並行處理,這些容器造成的小服務器跟其餘任務共同使用基礎設施計算節點的能力。
一個典型的分散收集模式的分佈式系統以下圖所示。根節點接受到來自客戶端的服務請求,將服務請求分配給不一樣的業務模塊分散處理,處理結果收集到根節點,通過必定的匯聚合併運算,產生一個合併的結果交付給客戶端。
聲明:本文並不是原創,只是本人在學習容器設計模式過程當中,對一些網絡資料的整理。主要參考於:《Kubernetes與雲原生應用》系列之容器設計模式