Kubernetes概念及核心對象

想學習更多相關知識請看部落客的個人部落格地址://blog.huli.com/

//blog.huli.com/

1.kubernetes快速入門

Kubernetes 集群將所有節點上的資源都整合到一個大的虛擬資源池裡,以代替一個個單獨的伺服器,而後開放諸如 CPU、記憶體和 I/O 這些基本資源用於運行其基本單元 —— Pod 資源對象。Pod 的容器中運行著隔離的任務單元,它們以 Pod 為原子單位,並根據其資源需求聰虛擬資源池中為其動態分配資源。若可以將整個集群類比為一台傳統的伺服器,那麼 Kubernetes(Master)就好比是作業系統內核,其主要職責在於抽象資源並調度任務,而 Pod 資源對象就是那些運行於用戶空間中的進程。於是,傳統意義上的向單節點或集群直接部署、配置應用的模型日漸式微,取而代之的是向 Kubernetes 的 API Server 提交運行 Pod 對象。

API Server 是負責接受並相應客戶端提交任務的介面,用戶可使用諸如 CLI 工具(如 kubectl)、UI 工具(如 Dashboard)或程式程式碼(客戶端開發庫)發起請求,其中,kubectl 是最為常用的互動式命令行工具。快速了解 kubernetes 的辦法之一就是部署一個測試集群,並嘗試測試使用他的各項基本功能。本章在簡單介紹核心資源對象後將嘗試使用 kubectl 創建 Deployment 和 Service 資源部署並暴露一個 Web 應用,以便讀者快速了解如何在 Kubernetes 系統上運行應用程式的核心任務。

2.1 Kubernetes 的核心對象

2.1.1 Pod 資源對象

Pod 資源對象是一種集合了一到多個應用容器、存儲資源、專用IP及支撐容器運行的其他選項的邏輯組件,如下圖所示。換言之,Pod 代表著 Kubernetes 的部署單元及原子運行單元,即一個應用程式的單一運行實例,它通常由共享資源且關係緊密的一個或多個應用容器組成。

file
Kubernetes 的網路模型要求其各 Pod 對象的 IP 地址位於同一網路平面內(同一 IP 網段),各 Pod 之間可使用其 IP 地址直接進行通訊,無論他們運行於集群內的哪個工作節點之上,這些 Pod 對象都像是運行於同一區域網中的多個主機。

讀者可以將每個 Pod 對象想像成一個邏輯主機,它類似於現實世界中的物理主機或VM(Virtual Machine),運行於同一個 Pod 對象中的多個進程也類似於物理機或 VM 上獨立運行的進程。不過,Pod 對象中的各進程均運行於彼此隔離的容器中,並於各容器間共享兩種關鍵資源:網路存儲卷

  • 網路(networking):每個 Pod 對象都會被分配一個集群內專用的 IP 地址,也稱為 Pod IP,同一 Pod 內部的所有容器共享 Pod 對象的 Network 和 UTS 名稱空間,其中包括主機名、IP 地址和埠等。因此,這些容器間的通訊就可以基於本地迴環介面 lo 進行,而與 Pod 外的其他組件的通訊則需要使用 Service 資源對象的 ClusterIP 及其相應的埠完成。

  • 存儲卷(volume): 用戶可以為 Pod 對象配置一組「存儲卷」資源,這些資源可以共享給其內部的所有容器使用,從而完成容器間數據的共享。存儲卷還可以確保在容器終止後被重啟,甚至是被刪除後也能確保數據不會丟失,從而保證了生命周期內的 Pod 對象數據的持久化存儲。

一個 Pod 對象代表某個應用程式的一個特定實例,如果需要擴展應用程式,則意味著為此應用程式同時創建多個 Pod 實例,每個實例均代表應用程式的一個運行的「副本」(replica)。這些副本化的 Pod 對象的創建和管理通常由一組稱之為「控制器」(Controller)的對象實現,例如,Deployment 控制器對象。

創建 Pod 時,還可以使用 Pod Preset 對象為 Pod 注入特定的資訊,如 ConfigMap、Secret、存儲卷、卷掛載和環境變數等。有了 Pod Preset 對象,Pod 模版的創建者就無須為每個模版顯示提供所有資訊,因此,也就無須事先了解需要配置的每個應用的細節即可完成模版定義。這些內容將在後面的章節中予以介紹。

基於期望的目標狀態和各節點的資源可用性,Master 會將 Pod 對象調度至某選定的工作節點運行,工作節點於指向的鏡像倉庫(image registry)下載鏡像,並於本地的容器運行時環境中啟動容器。Master 會將整個集群的狀態保存與 etcd 中,並通過 API Server 共享給集群的各個組件及客戶端。

2.1.2 Controller

Kubernetes 集群的設計中,Pod 是有生命周期的對象。用戶通過手工創建或由 Controller(控制器)直接創建的 Pod 對象會被「調度器」(Scheduler)調度至集群中的某工作節點運行,待到容器應用進程運行結束之後正常終止,隨後就會被刪除。另外,節點資源耗盡或故障也會導致 Pod 對象被回收。

但 Pod 對象本身並不具有「自愈」功能,若是因為工作節點甚至是調度器自身導致了運行失敗,那麼它將會被刪除;同樣,資源耗盡或節點故障導致的回收操作也會刪除相關的 Pod 對象。在設計上,Kubernetes 使用「控制器」實現對一次性的(用後即棄)Pod 對象的管理操作, 例如,要確保部署的應用程式的 Pod 副本數量嚴格反應用戶期望的數目,以及基於 Pod 模版來重建 Pod 對象等,從而實現 Pod 對象的擴縮容、滾動更新和自愈能力等。例如,某節點發生故障時,相關的控制器會將此節點上運行的 Pod 對象重新調度到其他節點上進行重建。

控制器本身也是一種資源類型,它有著多種實現,其中與工作負載相關的實現 Reqlication Controller、Deployment、StatefulSet、DeamonSet 和 Jobs 等,也可統稱它們為 Pod 控制器。如下圖中的 Doployment 就是這類控制器的代表實現,是目前最常用的管理無狀態應用的 Pod 控制器。

Pod 控制器的定義通常由期望的副本數量、Pod 模版和標籤選擇器(Label Selector)組成。Pod 控制器會根據標籤選擇器對 Pod 對象的標籤進行匹配檢查,所有滿足選擇條件的 Pod 對象都將受控於當前控制器並計入其副本總數,並確保此數目能夠精確反映期望的副本數。

需要注意的是,在實際的應用場景中,在接受到請求流量負載顯著低於或接近於已有 Pod 副本的整體承載能力時,用戶需要手動修改 Pod 控制器中的期望副本數量以實現應用規模的擴容或縮容。不過,若集群中部署了 HeapSter 或 Prometheus 一類的資源指標監控附件時,用戶還可以使用「HorizontalPodAutoscaler」(HPA) 計算出合適的 Pod 副本數量,並自動修改 Pod 控制器中期望的副本數以實現應用規模的動態伸縮,提高集群資源利用率,如下圖所示。

Kubernetes 集群中的每個節點都運行著 cAdvisor 以收集容器及節點 CPU、記憶體及磁碟資源的利用率指標數據,這些統計數據由 Heapster 聚合後可通過 API Server 訪問。HorizontalPodAutoscaler 基於這些統計數據監控容器健康狀態並做出擴展決策。

file
file

2.1.3 Service

儘管 Pod 對象可以擁有 IP 地址,但此地址無法確保在 Pod 對象重啟或被重建後保持不變,這會為集群中的 Pod 應用間依賴關係的維護帶來麻煩:前端 Pod 應用(依賴方)無法基於固定地址持續跟蹤後端 Pod 應用(被依賴方)。於是,Service 資源被用於在被訪問的 Pod 對象中添加一個有著固定 IP 地址的中間層,客戶端向此地址發起訪問請求後由相關的 Service 資源調度並代理至後端的 Pod 對象。

換言之,Service 是「微服務」的一種實現,事實上它是一種抽象:通過規則定義出由多個 Pod 對象組合而成的邏輯集合,並附帶訪問這組 Pod 對象的策略。Service 對象挑選,關聯 Pod 對象的方式和 Pod 控制器一樣,都是要基於 Label Selector 進行定義,其示意圖如下圖所示。

![Service 對象功能示意圖][1]

Service IP 是一種虛擬 IP,也稱為 Cluster IP,它專用於集群內通訊,通常使用專用的地址段,如 「10.96.0.0/12」 網路,各 Service 對象的 IP 地址在此範圍內由系統動態分配。

集群內的 Pod 對象可直接請求此類的 Cluster IP,例如,上圖中來自 pod client 的訪問請求即可以 Service 的 Cluster IP 作為目標地址,但集群網路屬於私有網路地址,它們僅在集群內部可達。將集群外部的訪問流量引入集群內部的常用方法是通過節點網路進行,實現方法是通過工作節點的 IP 地址和某埠(NodePort)接入請求並將其代理至相應的 Service 對象的 Cluster IP 上的服務埠,而後由 Service 對象的 Cluster IP 上的服務埠,而後由 Service 對象將請求代理至後端的 Pod 對象的 Pod IP 及應用程式監聽的埠。因此,諸如上圖中 External Clients 這種來自集群外部的客戶端無法直接請求此 Service 提供的服務,而是需要事先經由某一個工作節點(如 Node Y)的 IP 地址進行,這類請求需要兩次轉發才能到達目標 Pod 對象,因此在通訊效率上必然存在負面影響。

事實上,NodePort 會部署於集群中的每一個節點,這就意味著,集群外部的客戶端通過任何一個工作節點的 IP 地址來訪問定義好的 NodePort 都可以到達相應的 Service 對象。此種場景中,如果存在集群外部的一個負載均衡器,即可將用戶請求負載均衡至集群中的部分或者所有節點。這是一種稱為 「LoadBalancer」 類型的 Service,它通常是由 Cloud Provider 自動創建並提供的軟體負載均衡器,不過,也可以是由管理員手工配置的諸如 F5 Big-IP 一類的硬體設備。

簡單來說,Service 主要由三種常用類型:第一種是僅用與集群內部通訊的 ClusterIP 類型:第二種是接入集群外部請求的 NodePort 類型,它工作於每個節點的主機 IP 之上;第三種是 LoadBalacer 類型,它可以把外部請求負載均衡至多個 Node 的主機IP的 NodePort 之上。此三種類型中,每一種都以前一種為基礎才能實現,而且第三種類型中的 LoadBalacer 需要協同集群外部的組建才能實現,並且此外部組建並不接受 Kubernetes 的管理。
file

2.1.4 部署應用程式的主體過程

Docker 容器技術使得部署應用程式從傳統的安裝、配置、啟動應用程式的方式轉為於容器引擎上基於鏡像創建和運行容器,而 Kubernetes 又使得創建和運行容器的操作不必再關注其位置,並在一定程度上賦予了它動態擴縮容及自愈的能力,從而讓用戶從主機、系統及應用程式的維護工作中解脫出來。

用到某應用程式時,用戶只需要向 API Server 請求創建一個 Pod 控制器,由控制器根據鏡像等資訊向 API Server 請求創建出一定數量的 Pod 對象,並由 Master 之上的調度器指派至選定的工作節點以運行容器化應用。此外,用戶一般還需要創建一個具體的 Service 對象以便為這些 Pod 對象建立起一個固定的訪問入口,從而使得其客戶端能夠通過其服務名稱或 ClusterIP 進行訪問,如下圖所示:

file
API Server 的常用客戶端程式是 Kubernetes 系統自帶的命令行工具 kubectl,它通過一眾子命令用於實現集群及相關資源對象的管理操作,並支援直接命令式、命令式配置清單及聲明式配置清單等三種操作方式,特性豐富且功能強大。而需作為集群附件額外部署的 Dashboard 則提供了基於 Web 介面的圖形客戶端,它是一個通用目的的管理工具,與 Kubernetes 緊密集成,支援多級別用戶授權,能在一定程度上替代 kubectl 的大多數操作。

本章後面的篇幅將介紹在部署完成的 Kubernetes 集群環境眾如何快速部署如圖所示的示例應用程式,並簡單說明如何完成對容器化應用的訪問,以及如何進行應用規模的動態伸縮,並藉此讓讀者了解 kubectl 命令的基本功能和用法。

3.Kubernetes應用管理模型

下圖展示了Kubernetes的應用管理模型:
file

Pod是Kubernetes中的最小調度資源。Pod中會包含一組容器,它們一起工作,並且對外提供一個(或者一組)功能。對於這組容器而言它們共享相同的網路和存儲資源,因此它們之間可以直接通過本地網路(127.0.0.1)進行訪問。當Pod被創建時,調度器(kube-schedule)會從集群中找到滿足條件的節點運行它。

如果部署應用程式時,需要啟動多個實例(副本),則需要使用到控制器(Controller)。用戶可以在Controller定義Pod的調度規則、運行的副本數量以及升級策略等等資訊,當某些Pod發生故障之後,Controller會嘗試自動修復,直到Pod的運行狀態滿足Controller中定義的預期狀態為止。Kubernetes中提供了多種Controller的實現,包括:Deployment(無狀態應用)、StatefulSet(有狀態應用)、Daemonset(守護模式)等,以支援不同類型應用的部署和調度模式。

通過Controller和Pod我們定義了應用程式是如何運行的,接下來需要解決如何使用這些部署在Kubernetes集群中的應用。Kubernetes將這一問題劃分為兩個問題域,第一,集群內的應用如何通訊。第二,外部的用戶如何訪問部署在集群內的應用?

對於第一個問題,在Kubernetes中通過定義Service(服務)來解決。Service在Kubernetes集群內扮演了服務發現和負載均衡的作用。在Kubernetes下部署的Pod實例都會包含一組描述自身資訊的label,而創建Service,可以聲明一個Selector(標籤選擇器)。Service通過Selector,找到匹配標籤規則的Pod實例,並將對Service的請求轉發到代理的Pod中。Service創建完成後,集群內的應用就可以通過使用Service的名稱作為DNS域名進行相互訪問。

而對於第二個問題,Kubernetes中定義了單獨的資源Ingress(入口)。Ingress是一個工作在7層的負載均衡器,其負責代理外部進入集群內的請求,並將流量轉發到對應的服務中。

最後,對於同一個Kubernetes集群其可能被多個組織使用,為了隔離這些不同組織創建的應用程式,Kubernetes定義了Namespace(命名空間)對資源進行隔離。

4. Kubernetes架構模型

為了能夠更好的理解Kubernetes下的監控體系,我們需要了解Kubernetes的基本架構,如下所示,是Kubernetes的架構示意圖:

file
Kubernetes的核心組件主要由兩部分組成:Master組件和Node組件,其中Matser組件提供了集群層面的管理功能,它們負責響應用戶請求並且對集群資源進行統一的調度和管理。Node組件會運行在集群的所有節點上,它們負責管理和維護節點中運行的Pod,為Kubernetes集群提供運行時環境。

Master組件主要包括:

  • kube-apiserver:負責對外暴露Kubernetes API;
  • etcd:用於存儲Kubernetes集群的所有數據;
  • kube-scheduler: 負責為新創建的Pod選擇可供其運行的節點;
  • kube-controller-manager: 包含Node Controller,Deployment Controller,Endpoint Controller等等,通過與apiserver交互使相應的資源達到預期狀態。

Node組件主要包括:

  • kubelet:負責維護和管理節點上Pod的運行狀態;
  • kube-proxy:負責維護主機上的網路規則以及轉發。
  • Container Runtime:如Docker,rkt,runc等提供容器運行時環境。