Kubernetes模型設計與控制器模式精要 | 留言送書

Kubernetes創建初期,其本身在業界地位並不佔優,前有長期佔有主流市場的Mesos和基於Mesos的DCOS圍追堵截,後有Docker Swarm依託自己的容器事實標準異軍突起,反倒是Kubernetes只有谷歌的品牌。Kubernetes爲什麼能最後勝出,成爲容器雲的實施標準呢?最根本原因就是其對管理範疇的所有對象進行了抽象,通過模型標準化將容器雲平臺各個維度的問題解決得非常完美。Kubernetes模型通常由以下部分組成:

TypeMeta

TypeMeta是Kubernetes對象的最基本定義,它通過引入GKV(Group,Kind,Version)定義了一個對象的類型。

Group

Kubernetes定義了非常多對象,如何歸類這些對象是一門學問,將對象依據其功能範圍歸入不同的分組,比如把支撐最基本功能的對象歸入core組,把與應用部署有關的對象歸入apps組,會使這些對象可維護性和可理解性更高。

Kind

定義一個對象的基本類型,比如Node,Pod,Deployment等。

Version

社區每個季度會推出一個Kubernetes版本,隨着Kubernetes版本的演進,對象從創建之初到能夠完全生產化就緒的版本是不斷變化的。與軟件版本類似,通常社區提出一個模型定義以後,隨着該對象不斷成熟,其版本可能會從v1alpha1,到v1alpha2,或者到v1beta1,最終變成生產就緒版本v1。

Kubernetes通過Version屬性來控制版本。當不同版本的對象定義發生變更時,有可能需要涉及到數據遷移,Kubernetes API Server允許通過Conversion方法轉換不同版本的對象屬性。這是一種自動數據遷移的機制,當集羣版本升級以後,已經創建的老版本對象會被自動轉換爲新版本。

這裏所說的版本是對外版本(External Version),用戶通過API能看到的版本。事實上資源定義都有對內版本(Internal Version),在Kubernetes API Server處先將對外版本轉換成對內版本,然後再進行持久化。

Metadata

TypeMeta定義了“我是什麼”,Metadata定義了“我是誰”。爲方便管理,Kubernetes將不同用戶或不同業務的對象用不同的Namespace隔離。Metadata中有兩個最重要屬性——Namespace和Name,分別定義了對象的Namespace歸屬及名字,這兩個屬性唯一定義了某個對象實例。

前面說過,所有對象都會以API的形式發佈供用戶訪問,Typemeta、Namespace和Name唯一確定了該對象所在的API訪問路徑,該路徑也會被自動生成並保存在對象Metadata屬性的selfLink中,如下所示:

selfLink: /api/v1/namespaces/default/pods/nginx-6ccb6b48dd-zvfrj

Label

傳統面向對象設計系統中,對象組合的方法通常是內嵌或引用,即將對象A內嵌到對象B中,或者將對象A的ID內嵌到對象B中。這種設計的弊端是這種關係是固化的,一個對象可能對多個其他對象發生關聯,如果該對象發生變更,系統需要遍歷所有其關聯對象並做修改。

Kubernetes採用了更巧妙的方式管理對象和對象的松耦合關係,其依賴的就是Label和Selector。Label,顧名思義就是給對象打標籤,一個對象可以有任意對標籤,其存在形式是鍵值對。不像名字和UID,標籤不需要獨一無二,多個對象可以有同一個標籤,每個對象可以有多組標籤。

Label定義了這些對象的可識別屬性,Kubernetes API支持以Label作爲過濾條件查詢對象。因此Label通常用最簡形式定義:

metadata:
  labels:
    app: web
    tier: front

其他對象只需要定義Label Selector就可按條件查詢出其需要關聯的對象。Label的查詢可以基於等式如app=web,或app!=db,或基於集合如app in (web, db)或app notin (web, db),可以只查詢Label鍵,比如app。Label對多個條件查詢只支持“與”操作,如app=web, tier=front。

Annotation

Annotation與Label一樣用鍵值對來定義,但其功能與Label不一樣,所有在用法上也有不同原則,API也不支持針用Annotation做條件過濾。雖然Kubernetes把對象做了很好的抽象,在實際運用中特別是生產化落地過程中,總是需要保存一些在對象內置屬性中無法保存的信息,Annotation就是爲了滿足這類需求,事實上Annotation是對象的屬性擴展。社區在開發新功能,需要對象發生變更之前,往往會先把需要變更的屬性放在Annotation中,當功能經歷完實驗階段再將其移至正式屬性中。

Annotation作爲屬性擴展,更多是面向系統管理員和開發人員的,因此Annotation需要像其他屬性一樣做合理歸類。與Java開發中的包名設計類似,通常需要將系統以不同功能規劃爲不同的Annotation Namespace,其鍵應以如下形式存在:<namespace>/key:value, 比如一個最常用場景,爲Pod標記如下Annotation以告知Prometheus爲其抓取系統指標。

annotations:    
    prometheus.io/path: /mymetrics
    prometheus.io/port: "7355"
    prometheus.io/scrape: "true"

Finalizer

如果只看社區實現,那麼該屬性毫無存在感,因爲在社區代碼中,很少有對Finalizer的操作。但在企業化落地過程中,它是一個十分重要,值得重點強調的屬性。因爲Kubernetes不是一個獨立存在的系統,它最終會跟企業資源和系統整合,這意味着Kubernetes會操作這些集羣外部資源或系統。試想一個場景,用戶創建了一個Kubernetes對象,假設對應的控制器需要從外部系統獲取資源,當用戶刪除該對象時,控制器接收到刪除事件後,會嘗試釋放該資源。可是如果此時外部系統無法連通,並且同時控制器發生重啓了會有何後果?該對象永遠泄露了。

Finalizer本質上是一個資源鎖,Kubernetes在接收到某對象的刪除請求,會檢查Finalizer是否爲空,如果爲空則只對其做邏輯刪除,即只會更新對象中metadata.deletionTimestamp字段。具有Finalizer的對象,不會立刻刪除,需等到Finalizer列表中所有字段被刪除後,也就是該對象相關的所有外部資源已被刪除,這個對象纔會被最終被刪除。

因此,如果控制器需要操作集羣外部資源,則一定要在操作外部資源之前爲對象添加Finalizer,確保資源不會因對象刪除而泄露。同時控制器需要監聽對象的更新時間,當對象的deletionTimestamp不爲空時,則處理對象刪除邏輯,回收外部資源,並清空自己之前添加的Finalizer。

ResourceVersion

通常在多線程操作相同資源時,爲保證實物的一致性,需要在對象進行訪問時加鎖,以確保在一個線程訪問該對象時,其他線程無法修改該對象。排它鎖的存在確保某一對象在同一時刻只有一個線程在修改,但其排它的特性會讓其他線程等待鎖,使得系統整體效率顯著降低。

ResourceVersion可以被看做是一種樂觀鎖,每個對象在任意時刻都有其ResourceVersion,當Kubernetes對象被客戶端讀取以後,ResourceVersion信息也被一併讀取。客戶端更改對象並回寫APIServer時,ResourceVersion會被增加,同時APIServer需要確保回寫的版本比服務器端當前版本高,在回寫成功後服務器端的版本會更新爲新的ResourceVersion。因此當兩個線程同時訪問某對象時,假設它們獲取的對象ResourceVersion爲1。緊接着第一個線程修改了對象,資源版本會變爲2,回寫至APIServer以後,該對象服務器端ResourceVersion會被更新爲2。此時如果第二個線程對該對象在1的版本基礎上做了更改,回寫APIServer時,所帶的新的版本信息也爲2,APIServer校驗會發現第二個線程新寫入的對象ResourceVersion與服務器端ResourceVersion衝突,寫入失敗,需要第二個線程讀取最新版本重新更新。

此機制確保了分佈式系統中,任意多線程無鎖併發訪問對象,極大提升系統整體效率。

Spec和Status

Spec和Status纔是對象的核心,Spec是用戶的期望狀態,由創建對象的用戶端定義。Status是對象的實際狀態,由對應的控制器收集實際狀態並更新。與TypeMeta和Metadata等通用屬性不同,Spec和Status是每個對象獨有的,後續的章節會通過介紹一些核心對象來深入理解。

爲方便對Kubernetes對象的理解,下圖展示了按照業務目的歸類的常用Kubernetes對象和其分組。Kubernetes對象設計完全遵循互補的原則。鼓勵API對象儘量實現面向對象設計時的要求,即“高內聚,松耦合”,對業務相關的概念有一個合適的分解,提高分解出來的對象的可重用性。高層API對象設計一定是從業務出發的,低層API對象能夠被高層API對象所使用,從而實現減少冗餘、提高重用性的目的。

常用Kubernetes對象和其分組

核心對象概覽

Kubernetes的對象設計避免了簡單封裝和內部隱藏機制。簡單地封裝,A對象封裝了B對象的定義,實際沒有提供新的功能,反而增加了對所封裝API的依賴性。內部隱藏的機制也非常不利於系統維護的設計方式。例如StatefulSet、ReplicaSet和DaemonSet,如圖所示,本來就是三種Pod集合,那麼Kubernetes就用不同API對象來定義它們,而不會說將它們封裝在同一個資源對象,內部再通過特殊的隱藏算法再來區分這個資源對象是有狀態的、無狀態的還是節點服務。Pod是Kubernetes應用程序的基本執行單元,即它是Kubernetes對象模型中創建或部署的最小和最簡單的單元。多數核心對象都爲Pod對象服務的,但是它們都從Pod對象中所剝離出來的,有自己的API定義。Secret、ConfigMap和PVC是不同的資源對象定義,都可以作爲存儲卷在Pod中使用。而在Pod中使用時,只需要指定該對象的名稱即可,無需將其具體信息在Pod資源對象中擴展。

核心對象間的關係圖

Namespace

Namespace是Kubernetes進行歸類的對象,當一個集羣有多個用戶或一個用戶有多個應用需要管理時,有時需要將所有被管理的對象進行一定的隔離。Kubernetes引入了Namespace對象,類似文件目錄,不同對象被劃分到不同Namespace以後,可以通過權限控制來限制哪些用戶以何種權限訪問哪些Namespace的哪些對象,進而構建一個多租戶、彼此隔離的通用集羣。

Pod

容器雲平臺需要解決的最核心問題是應用運行,Kubernetes將容器化應用運行的實體抽象爲Pod,Pod類似豆莢,它是一個或者多個容器鏡像的組合。當應用啓動以後,每一個容器鏡像對應一組進程,而同一個Pod的所有容器中的進程默認公用同一網絡Namespace,並且共用同一網絡標識。Pod具有基本的自恢復能力,當某個副本出現問題時,它會按照預定策略被重啓。

當然,應用運行通常需要配置文件,這些配置文件又有可以明文讀寫的配置,也包含需要加密和嚴格權限控制的密碼證書等配置,Kubernetes爲這些配置分別定義了Configmap和Secret。Configmap和Secret,和PersistVolumeClaim類似,都可以作爲卷加載給運行的Pod,Pod中運行的進程可以像訪問本地文件一樣訪問它們。Configmap和Secret沒有本質區別,Secret只是將內容進行base64編碼,我們知道base64編碼是一種對稱加密,可以輕鬆解密,事實上沒有太多安全性可言。但Kubneretes支持Secret在持久化時的加密存儲,這樣保存在硬盤的Secret數據是無法解密的。其次,Kubernetes可以通過權限嚴格控制能夠訪問Secret的用戶,以保證密碼和證書信息的安全。

Pod除了包含用戶希望運行的容器鏡像和配置文件,還允許用戶定義其運行所需的資源,用戶創建Pod以後,Kubernetes會爲其選擇一個最佳節點運行。計算節點被抽象成Node對象,節點數量和每個節點的資源彙總起來就是整個集羣能提供的算力。每個計算節點負責彙報自己的心跳信息,並上報節點的資源總量和可用資源。

ServiceAccount

Pod中運行的進程有時需要與Kubernetes API通信,在啓用了安全配置的集羣后,Pod一定要以某種身份與Kubernetes通信,這個身份就是系統賬戶(ServiceAccount)。Kubernetes會默認爲每個Namespace創建一個default ServiceAccount,並且爲每個ServiceAccount生成一個JWT Token,這個Token保存在Secret中。用戶可以在其Pod定義中指定ServiceAccount(默認爲default),其對應的Token會被掛載在Pod中,Pod中的進程可以帶着該Token與Kubernetes通信以標識其身份。

ReplicaSet

Pod只是單個應用實例的抽象,要構建高可用應用,通常需要構建多個同樣的副本,提供同一個服務。Kubernetes爲此抽象出副本集ReplicaSet,其允許用戶定義Pod的副本數,每一個Pod都會被當作一個無狀態的成員管理,Kubernetes保證總是有用戶期望的數量的Pod正常運行。當某個副本宕機以後,控制器將會創建一個新的副本。當因業務負載發生變更而需要調整擴縮容時,可以方便地調整副本數量。

Deployment

對於無狀態在線應用,Kubernetes提供了更高級的版本變更控制。版本變更是一個日常頻繁發生的關鍵操作,如何在不中斷業務的前提下更新版本,一直是業界努力解決的問題。Deployment就是一個用來描述發佈過程的對象,其實現機制是,當某個應用有新版本發佈時,Deployment會同時操作兩個版本的ReplicaSet。其內置多種滾動升級策略,會按照既定策略降低老版本的Pod數量,同時創建新版本的Pod,並且總是保證正在運行的Pod總數與用戶期望副本數一致,並依次將該Deployment中的所有副本都更新至新版本。下圖展示了基於Deployment進行版本發佈的一箇中間狀態。

Deployment的滾動升級

因爲Deployment會維護ReplicaSet,ReplicaSet會創建Pod,因此通過Deployment維護針對無狀態的應用是第一選擇,它可以滿足諸多需求,縮短應用上線的時間,在不造成停機的情況下創建彈性部署,能夠使用戶更快或更頻繁地發佈應用和功能。

  • 創建並保證目標數量的Pod在運行狀態。

  • 按既定策略滾動升級,同時支持升級暫停、恢復和回滾。選擇滾動升級策略非常靈活,正確的策略對於交付彈性應用程序和基礎架構都是至關重要的。

  • 便利的擴容和縮容。

Service和Ingress

即使在傳統平臺中,爲支持應用的高可用,都需要在應用實例之上構建負載均衡。Service和Ingress就是描述負載均衡配置的對象,它允許用戶定義發佈服務的協議和端口,並定義Selector選擇後端服務的Pod。Selector本身是一個Label過濾器,它會選擇所有Label與該Selector匹配的Pod作爲目標。Kubernetes會爲Service和其選擇出來的Pod創建一個關聯對象,Endpoint裏面記錄了所有Pod的IP,以及就緒狀態,這些信息會被相應組件作爲期望狀態進行負載均衡配置。Ingress是在服務的基礎上,定義API網關的對象。通過Ingress,用戶可以定義七層轉發規則、網關證書等高級路由功能。

PersistentVolume和PersistentVolumeClaim

PersistentVolume(PV)是集羣中的一塊存儲卷,可由管理員手動設置,或當用戶創建PersistentVolumeClaim(PVC)時根據StorageClass動態設置。PV和PVC與Pod生命週期無關。也就是說當Pod中的容器重新啓動、Pod重新調度或者刪除時,PV和PVC不會受到影響,Pod存儲於PV裏的數據得以保留。對於不同的使用場景,用戶通常需要不同屬性(例如性能、訪問模式等)的PV。所以集羣一般需要提供各種類型的PV,由StorageClass來區分。一般集羣環境都設置了默認的StorageClass。如果在PersistentVolumeClaim中未指定StorageClass,則使用羣集的默認StorageClass。

CustomResourceDefinition

自定義資源定義(CRD)是Kubernetes 1.7中引入的一項強大功能,它允許用戶將自己的自定義對象添加到Kubernetes集羣中,當創建新CRD的定義時,APIServer將爲指定的每個版本創建一個新的RESTful資源路徑。當集羣中成功地創建了CRD,就可以像Kubernetes原生的資源一樣使用它,利用Kubernetes的所有功能,例如其CLI、安全性、API服務、RBAC等。CRD的定義是集羣範圍內的,CRD的資源對象的作用域可以是命名空間(Namespaced)或者集羣範圍(Cluster-wide)的。與現有的內置對象一樣,刪除Namespace也會刪除該Namespace中所有自定義的對象,但不會刪除CRD的定義。Kubernetes還提供一系列Codegen工具(deepcopy-gen、client-gen、lister-gen、informer-gen等),能夠自動生成該CRD資源的Golang版本的Clientset、Lister及Informer,這爲該資源編寫控制器提供了很大便利。

CRD就像數據庫的開放式表結構,允許用戶自定義Schema。有了這種開放式設計,使得用戶可以基於CRD定義一切需要的模型,滿足不同業務的需求。社區鼓勵基於CRD的業務抽象,衆多主流的擴展應用都是基於CRD構建的,比如Istio,比如Knative。甚至基於CRD推出了Operator Mode和Operator SDK,可以以極低的開發成本定義新對象,並構建新對象的控制器。

控制器模式

聲明式系統的工作原理是什麼?當用戶定義了對象的期望狀態,Kubernetes通過何種機制確保實際狀態與期望狀態最終保持一致?定義瞭如此多的對象,那麼這些對象是如何聯動起來,完成一個個業務流的呢?祕密就是控制器模式,Kubernetes定義了一系列的控制器,事實上幾乎所有的Kubernetes對象都被一個或數個控制器監聽,當對象發生變化時,控制器會捕獲對象變化並完成配置操作。

Kubernetes的功能組件會在後面章節中展開,但本節深入理解控制器模式有助於理解Kubernetes的運作機制。APIServer是Kubernetes的大腦,保存了所有對象和其狀態。開源項目client-go對控制器的編寫提供了完備的自動化支持,任何Kubernetes對象都可以由client-go創建供控制器使用的Informer()和Lister()接口。如圖所示,控制器的工作流程就是圍繞着Informer()和Lister()的。

  • Informer()是用來接收資源對象的變化的Event,針對Add、Update和Delete的事件,可註冊相應的EventHandler。在EventHandler內,根據傳入的object調用controller.KeyFunc計算出字符串key,並把它加入控制器的隊列中。

  • Lister()是給控制器提供主動查詢資源對象的接口,根據labels.Selector去指定篩選條件。

控制器模式是一個標準的生產者消費者模式,一方面控制器在啓動後,Informer會監聽其所關注的對象變化。一旦對象發生了創建,更新和刪除等事件,這些事件會由核心組件APIServer推送給控制器。控制器會將對象保存在本地緩存,並將對象的主鍵推送至消息隊列,此爲生產者。

另一方面,控制器會啓動多個工作子線程(Worker),從隊列中依次獲取對象主鍵,並從緩存中讀取完整狀態,按照期望狀態完成配置更改並將最終狀態回寫至APIServer,此爲消費者。

Kubernetes就是基於此模式保證了整個系統的最終一致性。

控制器的工作流程

Kubernetes運行一組控制器,以使資源的當前狀態與所需狀態保持匹配。基於事件的體系結構,控制器利用事件去觸發相應的自定義代碼,這部分都是由SharedInformer完成。例如創建Deployment的控制器,其核心代碼如下:

kubeInformerFactory := kubeinformers.NewSharedInformerFactory(kubeClient, resyncPeriod)
deploymentInformer := kubeInformerFactory.Apps().V1().Deployments()
deploymentInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
  AddFunc: controller.handleObject,
  UpdateFunc: func(old, new interface{}) {
     newDepl := new.(*appsv1.Deployment)
     oldDepl := old.(*appsv1.Deployment)
     if newDepl.ResourceVersion == oldDepl.ResourceVersion {
        return
     }
     controller.handleObject(new)
  },
  DeleteFunc: controller.handleObject,
})
kubeInformerFactory.Start(stopCh)

具體地,如圖所示,SharedInformer有Reflector、Informer、Indexer和Store四個組件。

Informer的內部機制

Reflector是用來監聽特定的Kubernetes API資源對象,可以是Kubernetes內建的或者是自定義的資源。具體的實現是通過ListAndWatch的方法。Reflector首先會將資源版本號設置爲0,使用List操作獲得指定資源對象,可能會導致本地的緩存相對於etcd裏面的內容存在延遲。Reflector再通過Watch操作監聽到APIServer處資源對象的版本號變化,並將最新的數據放入到Delta FIFO隊列中,使得本地的緩存數據與etcd的數據保持一致。如果resyncPeriod不爲零,那麼Reflector會以resyncPeriod爲週期定期執行Delta FIFO的Resync函數,這樣就可以使Informer定期處理所有的對象。

Informer是從Delta FIFO隊列中彈出對象,一方面將對象存入本地存儲以供檢索,另一方面觸發事件以調用資源事件回調函數。控制器後續的典型模式是獲取資源對象的key,並將該key排入工作隊列以進行進一步處理。Indexer提供對象的索引功能。

Indexer可以根據多個索引函數維護索引。Indexer使用線程安全的數據存儲來存儲對象及其鍵。在Store中定義了一個名爲MetaNamespaceKeyFunc的默認函數,該函數生成對象的鍵的格式是<namespace>/<name>的組合。

控制器的協同工作原理

單個Kubernetes資源對象的變更,觸發多個控制器對該資源對象的變更進行響應,繼而還能引發其相關的其他對象發生變更,從而觸發其他對象控制器的配置邏輯,這一模式使得整個系統成爲聲明式。下圖簡要描述了用戶創建一個Deployment對象時各個控制器是如何協同工作的。

協同工作流程示例

除APIServer和etcd外,所有Kubernetes組件,不論其名稱是Scheduler,Controller Manager、或是Kubelet,其本質都是一致的,都可以被稱爲控制器,因爲這些組件中都有一個控制循環。他們監聽APIServer中的對象變更,並在自己關注的對象發生變更後完成既定的邏輯控制,並將控制邏輯執行完成後的結果更新回APIServer,並持久化到etcd中。

APIServer作爲集羣的API網關,接收所有來自用戶的請求。用戶發創建Deployment之後,該請求被髮送至APIServer,經過認證鑑權和准入三個環節,該Deployment對象被保存至etcd。

Controller Manager中的Deployment Controller監聽APIServer中所有Deployment的變更事件,此時其捕獲了Deployment的創建事件,並開始執行控制邏輯。Deployment Controller讀取Deployment對象的Selector定義,並通過該屬性過濾當前Namespace中所有ReplicaSet對象,並判斷是否有任何ReplicaSet對象的OwnerReference屬性爲此Deployment。因爲此Deployment剛剛創建,因此沒有滿足此查詢條件的ReplicaSet,於是Deployment Controller會讀取Deployment中定義的podTemplate,並將其做哈希計算,並依照如下約定創建新的ReplicaSet:

  • 並創建新的ReplicaSet,將其命名爲[deployment-name]-[pod-template-hash]。

  • 更新ReplicaSet,爲ReplicaSet添加label,記pod-template-hash值爲[計算出的哈希值]。

  • 將Deployment設置爲ReplicaSet的OwnerReference。

Deployment Controller將新的ReplicaSet創建請求發送至APIServer,APIServer同樣的經過認證授權和准入步驟,將該對象保存至etcd。

ReplicaSet Controller監聽APIServer中所有ReplicaSet對象的變更,新對象的創建令其喚醒並開始執行控制邏輯。ReplicaSet Controller讀取ReplicaSet對象的Selector定義,並通過該屬性過濾當前Namespace中所有Pod對象,並判斷是否有任何Pod對象的OwnerReference爲該ReplicaSet。因爲此ReplicaSet剛剛創建,因此沒有滿足此查詢條件的Pod,於是ReplicaSet會按照如下約定創建Pod:

  • 讀取Replicas定義,Replicas的數量代表需要創建Pod的數量。

  • 以ReplicaSet名作爲Pod的GenerateName,該屬性會作爲Pod名的前綴,Kubernetes在此基礎上加一個隨機字符串作爲Pod名。

  • 該ReplicaSet作爲Pod的OwnerReference。

ReplicaSet Controller將新建Pod的請求發送至APIServer,APIServer將Pod悉數保存。

此時調度器被喚醒,其監聽APIServer中所有nodeName爲空的Pod,即未經過調度的Pod。經過一系列的調度算法,不滿足Pod需求的節點被過濾,符合的節點按照空閒資源,端口占用情況,實際資源利用率等信息被排序,評分最高的節點名被更新至nodeName屬性,該同樣經APIServer保存至etcd。

最後,運行在Pod被調度節點的Kubelet監聽到有歸屬於自己節點的新Pod,則開始加載Pod清單,下載Pod所需的配置信息,調用容器運行時接口啓動容器,調用容器網絡接口加載網絡,調用容器存儲接口掛載存儲,並完成Pod的啓動。

Kubernetes就是依靠這樣的聯動機制,通過分散的業務控制邏輯滿足用戶需求。從用戶的角度看,只是發送了一個Deployment創建請求,但事實上,爲滿足該需求,可能會牽扯到數個甚至更多Kubernetes組件。此架構模式的優勢是每個組件各司其職,巧妙而靈活,代碼易維護,但帶來的運維複雜度相對較高,此業務流中有任何組件出現故障,對用戶感受來講,都是Kubernetes不可用。

留言福利

本文節選自《Kubernetes生產化實踐之路》,經出版社授權發佈,本書來自eBay五年來Kubernetes生產實踐的經驗總結。爲了感謝粉絲的支持特意送出6本此書作爲福利。歡迎大家在留言區談談學習Kubernetes的心得,截止2020年12月15日12時,精選留言點贊前6名,各送出此書一本!沒中獎的同學可以點擊下方鏈接購買。

Kubernetes實戰培訓

Kubernetes實戰培訓將於2020年12月25日在深圳開課,3天時間帶你係統掌握Kubernetes,學習效果不好可以繼續學習。本次培訓包括:雲原生介紹、微服務;Docker基礎、Docker工作原理、鏡像、網絡、存儲、數據卷、安全;Kubernetes架構、核心組件、常用對象、網絡、存儲、認證、服務發現、調度和服務質量保證、日誌、監控、告警、Helm、實踐案例等,點擊下方圖片或者閱讀原文鏈接查看詳情。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章