K8S系列:集群架構與組件
Kubernetes(K8s)作為當今最流行的容器編排引擎之一,其集群架構和組件扮演著關鍵角色,為現代化云原生應用的部署、擴展和管理提供了強大的支持。本文將深入探討K8s集群的架構以及核心組件,幫助讀者更好地理解Kubernetes的工作原理和設計思想。
Kubernetes 架構
Kubernetes集群由多個節點組成,其中包括Master節點和Worker節點。Master節點負責集群的控制平面,而Worker節點負責運行實際的應用程序容器。
一個Kubernetes集群由控制平面節點和工作節點組成。
1.控制平面
控制平面負責容器編排和維護集群的期望狀態。它包括以下組件:
- kube-apiserver
- etcd
- kube-scheduler
- kube-controller-manager
- cloud-controller-manager
一個集群可以有一個或多個控制平面節點。
2.工作節點
工作節點負責運行容器化的應用程序。工作節點包括以下組件:
- kubelet
- kube-proxy
- 容器運行時(Container runtime)
分層架構
Kubernetes 設計理念和功能其實就是一個類似 Linux 的分層架構,如下圖所示:
分層架構
- 核心層:Kubernetes 最核心的功能,對外提供 API 構建高層的應用,對內提供插件式應用執行環境
- 應用層:部署(無狀態應用、有狀態應用、批處理任務、集群應用等)和路由(服務發現、DNS 解析等)
- 管理層:系統度量(如基礎設施、容器和網絡的度量),自動化(如自動擴展、動態 Provision 等)以及策略管理RBAC、Quota、PSP、NetworkPolicy 等
- 接口層:kubectl 命令行工具、客戶端 SDK 以及集群聯邦
- 生態系統:在接口層之上的龐大容器集群管理調度的生態系統,可以劃分為兩個范疇。
控制面板組件
首先,讓我們看看每個控制平面組件以及每個組件背后的重要概念。
1.kube-apiserver
kube-api服務器是公開Kubernetes API的Kubernetes集群的中心樞紐。它具有高度的可擴展性,可以處理大量并發請求。最終用戶和其他集群組件通過API服務器與集群通信。監控系統和第三方服務很少會與API服務器通信,與集群進行交互。因此,當您使用kubectl來管理集群時,在后端您實際上是通過HTTP REST API與API服務器通信。然而,集群內部的組件如調度器、控制器等使用gRPC與API服務器通信。API服務器和集群中的其他組件之間通過TLS進行通信,以防止對集群的未授權訪問。
Kubernetes api-server負責以下工作:
- API管理:公開集群API端點并處理所有API請求。API是version,它同時支持多個API版本。
- 身份驗證:(使用客戶端證書、不記名令牌和HTTP基本身份驗證)和授權(ABAC和RBAC評估)
- 處理API請求并為API對象(如pods, services等)驗證數據(驗證和變異接納控制器)
- 它是唯一與etcd通信的組件。
- API-Server協調控制平面和工作節點組件之間的所有進程。
- API-Server有一個內置的apiserver代理。它是API服務器進程的一部分。它主要用于從集群外部訪問ClusterIP服務,即使這些服務通常只能在集群內部訪問。
- API服務器還包含一個聚合層,它允許您擴展Kubernetes API以創建自定義API資源和控制器。
- API服務器還支持監視資源的變化。例如,客戶端可以對特定資源建立監視,并在創建、修改或刪除這些資源時接收實時通知
2.etcd
Kubernetes是一個分布式系統,它需要一個高效的分布式數據庫,如etcd,以支持其分布式特性。它既是一個后端服務發現,也是一個數據庫。你可以稱它為Kubernetes集群的大腦。
Etcd是一個開源的強一致性分布式鍵值存儲。它具體意味著什么?
- 強一致性:如果對一個節點進行了更新,強一致性將確保該節點立即更新到集群中的所有其他節點。此外,如果你看看CAP定理,在強一致性和分區容忍下實現100%的可用性是不可能的。
- 分布式:etcd被設計成在多個節點上作為一個集群運行,而不會犧牲一致性。
- 鍵值存儲(Key Value Store) :一種非關系型數據庫,以鍵和值的形式存儲數據。它還公開了一個key-value API。該數據存儲構建在BoltDB的一個分支BboltDB之上。
Etcd采用raft共識算法實現強一致性和可用性。它以領導者-成員的方式工作,以獲得高可用性和抵御節點故障。
那么etcd如何與Kubernetes一起工作呢?
簡單地說,當你使用kubectl來獲取kubernetes對象的細節時,你是從etcd中獲取它。此外,當部署pod等對象時,會在etcd中創建一個條目。
簡而言之,以下是您需要了解的關于etcd的內容:
- etcd存儲Kubernetes對象的所有配置、狀態和元數據(pods、secrets、daemonsets、deployment、configmaps、statefulsets等)。
- etcd允許客戶端使用Watch() API訂閱事件。Kubernetes api-server使用etcd的watch功能來跟蹤對象狀態的變化。
- etcd使用gRPC提供了key-value API。此外,gRPC網關是一個RESTful代理,它將所有HTTP API調用轉換為gRPC消息。這使得它成為Kubernetes的理想數據庫。
- Etcd以鍵值格式將所有對象存儲在/registry目錄下。例如,默認命名空間中名為Nginx的pod的信息可以在/registry/pods/default/Nginx下找到
此外,etcd 是控制平面中唯一的 Statefulset 組件。
3.kube-scheduler
kube-scheduler負責在工作節點上調度Kubernetes pods。
當您部署pod時,您需要指定pod需求,例如CPU、內存、親和性、污點或容忍、優先級、持久卷(PV)等。調度器的主要任務是識別創建請求,并為滿足要求的pod選擇最佳節點。
下圖概述了調度器的工作原理:
在Kubernetes集群中,將有多個工作節點。那么,調度器如何從所有工作節點中選擇節點呢?
下面是調度器的工作原理:
- 為了選擇最佳節點,Kube-scheduler使用過濾和評分操作。
- 在篩選過程中,調度器找到可以調度pod的最適合的節點。例如,如果有5個可用資源運行pod的工作節點,它會選擇所有5個節點。如果沒有節點,那么pod是不可調度的,并移動到調度隊列。如果是一個大型集群,假設有100個工作節點,調度器不會遍歷所有節點。有一個調度器配置參數,名為percentageOfNodesToScore。默認值通常為50%。因此,它嘗試以輪詢方式迭代超過50%的節點。如果工作節點分布在多個內存域,那么調度器會遍歷不同內存域中的節點。對于非常大的集群,默認percentageOfNodesToScore是5%。
- 在評分階段,調度器通過為過濾后的工作節點分配分數來對節點進行排名。調度器通過調用多個調度插件進行評分。最后,選擇級別最高的工作節點進行pod調度。如果所有節點的相同,則隨機選擇一個節點。
- 一旦節點被選中,調度器就會在API服務器中創建一個綁定事件。意味著綁定pod和node的事件。
下面是你需要知道的關于調度器的事情:
- 它是一個在API服務器中監聽pod創建事件的控制器。
- 調度器有兩個階段。調度周期和綁定周期。它們合起來稱為調度上下文(scheduling context)。調度周期選擇一個工作節點,然后綁定周期將其應用到集群上。
- 調度器總是將高優先級的pods放在低優先級的pods之前進行調度。此外,在某些情況下,在pod開始在選定節點中運行后,pod可能會被刪除或移動到其他節點。如果你想了解更多,請閱讀Kubernetes pod優先級指南[1]
- 用戶可以創建自定義調度器,并在集群上運行多個調度器。當你部署pod時,你可以在pod清單中指定自定義調度器。因此,調度決策將基于自定義調度器邏輯進行。
- 調度器有一個可插拔的調度框架。這意味著你可以將自定義插件添加到調度工作流中。
4.kube-controller-manager
什么是控制器?控制器是運行無限控制循環的程序。這意味著它持續運行并監視對象的實際和期望狀態。如果實際狀態和期望狀態存在差異,它確保kubernetes資源/對象處于期望狀態。
根據官方文件:在Kubernetes中,控制器是監視集群狀態的控制循環,然后在需要時進行更改或請求更改。每個控制器都試圖將當前集群狀態移動到期望狀態。
假設你想要創建一個部署,你在manifest YAML文件中指定所需的狀態(聲明方式)。例如,2個副本,1個卷掛載,configmap等。內置的部署控制器確保部署始終處于所需的狀態。如果用戶用5個副本更新部署,部署控制器將識別它并確保所需狀態為5個副本。
kube-controller-manager是一個管理所有Kubernetes控制器的組件。Kubernetes資源/對象,如pods,命名空間,作業,replicaset由各自的控制器管理。此外,Kube調度器也是由Kube控制器管理器管理的控制器。
以下是重要的內置Kubernetes控制器列表:
- Deployment Controller
- ReplicaSet Controller
- DaemonSet Controller
- Job Controller
- CronJob Controller
- Endpoints Controller
- Namespace Controller
- Service Accounts Controller
- Node Controller
以下是關于Kube控制器管理器您應該了解的內容:
- 它管理所有控制器,而這些控制器則試圖保持集群處于期望的狀態。
- 你可以通過自定義資源定義(Custom Resource Definition)來擴展 Kubernetes,關聯自定義控制器。
5.cloud-controller-manager(CCM)
- 當kubernetes部署在云環境中時,云控制器管理器充當云平臺api和kubernetes集群之間的橋梁。
- 這樣,核心kubernetes的核心組件可以獨立工作,并允許云提供商使用插件與kubernetes集成。(例如,kubernetes集群和AWS cloud API之間的接口)
- 集成云控制器允許Kubernetes集群提供云資源,如實例(用于節點)、負載均衡器(用于服務)和存儲卷(用于持久卷)。
云控制器管理器包含一組特定于云平臺的控制器,確保特定于云的組件(節點、負載均衡器、存儲等)的所需狀態。以下是云控制器管理器的三個主要控制器:
- 節點控制器:該控制器通過與云提供商API通信更新節點相關信息。例如,節點標記和注釋、獲取主機名、CPU和內存可用性、節點健康狀況等。
- 路由控制器:負責在云平臺上配置網絡路由。這樣不同節點中的pods就可以相互通信。
- 服務控制器:它負責為kubernetes服務部署負載均衡器,分配IP地址等。
下面是云控制器管理器的一些經典示例:
- 部署負載均衡器類型的Kubernetes服務。在這里,Kubernetes提供了一個特定于云的負載均衡器,并與Kubernetes服務集成。
- 為云存儲解決方案支持的pods配置存儲卷(PV)。
整體云控制器管理器管理kubernetes使用的特定云資源的生命周期。
節點組件
現在讓我們看看每個工作節點組件。
1.kubelet
Kubelet是一個運行在集群中的每個節點上的代理組件。它不作為容器運行,而是作為守護進程運行,由systemd管理。
它負責向API服務器注冊工作節點,并主要從API服務器使用podSpec (Pod規范- YAML或JSON)。podSpec定義了應該在pod中運行的容器、它們的資源(例如CPU和內存限制)以及其他設置,如環境變量、卷和標簽。
然后,它通過創建容器將podSpec帶到所需狀態。
簡而言之,kubelet負責以下工作:
- 為pod創建、修改和刪除容器。
- 負責處理活性,準備和啟動探針。
- 通過讀取pod配置和在主機上為卷掛載創建相應的目錄來負責掛載卷。
- 通過調用API服務器(如cAdvisor和CRI)來收集和報告節點和pod狀態。
- Kubelet也是一個控制器,它監視pod的變化,并利用節點的容器運行時來拉取圖像,運行容器等。
除了來自API服務器的podSpec, kubelet還可以接受來自文件、HTTP端點和HTTP服務器的podSpec?!皃odSpec from a file”的一個很好的例子是Kubernetes static pods。
靜態pods由kubelet控制,而不是API服務器。
這意味著你可以通過向Kubelet組件提供pod的YAML位置來創建pods。然而,Kubelet創建的靜態pods并不由API服務器管理。
這是一個靜態pod的真實示例。
在引導控制平面時,kubelet從位于/etc/kubernetes/manifest的podSpecs中將 api-server、scheduler 和 controller manager作為靜態 pod。
以下是kubelet的一些關鍵內容:
- Kubelet使用CRI(容器運行時接口)gRPC接口與容器運行時進行通信。
- 它還向流日志公開HTTP端點,并為客戶端提供exec會話。
- 使用CSI (container storage interface) gRPC配置塊卷。
- 它使用集群中配置的CNI插件來分配pod的IP地址,并為pod設置必要的網絡路由和防火墻規則。
2.kube-proxy
要理解Kube-proxy,你需要對Kubernetes服務和端點對象有基本的了解。
Kubernetes中的服務是一種向內部或外部流量暴露一組pods的方法。當您創建服務對象時,它將獲得分配給它的虛擬IP。它被稱為clusterIP。它只能在Kubernetes集群內訪問。
Endpoint對象包含一個服務對象下pod組的所有IP地址和端口。端點控制器負責維護pod IP地址(端點)列表。服務控制器負責配置服務的端點。
你不能ping ClusterIP,因為ClusterIP只用于服務發現,不像pod ip可以ping。
現在讓我們了解一下Kube-proxy。
Kube-proxy是一個守護進程,在每個節點上作為守護進程運行。它是一個為pods實現Kubernetes服務概念的代理組件。(一組具有負載均衡的pods的單一DNS)。它主要代理UDP、TCP和SCTP,但不支持HTTP。
當你使用Service(ClusterIP)公開pods時,Kube-proxy創建網絡規則,將流量發送到服務對象下分組的后端pods(endpoints)。這意味著,所有的負載平衡和服務發現都由Kube代理處理。
那么Kube-proxy是如何工作的呢?
Kube代理與API服務器通信以獲取服務(ClusterIP)以及相應的pod ip和端口(endpoints)的詳細信息。它還監視服務和端點的變化。
然后,Kube-proxy使用以下任意一種模式來創建/更新規則,將流量路由到服務背后的pods:
(1) IPTables:默認模式。IPTables模式下,流量通過IPtable規則進行處理。這意味著對于每個服務,都創建了IPtable規則。這些規則捕獲到達ClusterIP的流量,然后將其轉發到后端pods。在這種模式下,kube-proxy隨機選擇后端pod進行負載均衡。連接建立后,請求會發送到同一個pod,直到連接終止。
(2) IPVS:對于超過1000個業務的集群,IPVS提供了性能提升。它支持以下后端負載平衡算法。
- rr:round-robin:默認模式。
- Lc:最小連接數(最小打開連接數)
- Dh:目標哈希
- Sh:源散列
- Sed:預期的最短延遲
- Nq:永不排隊
(3) 用戶空間:(遺留&不推薦)
(4) 內核空間:該模式僅適用于Windows系統。
如果您想了解kube-proxy IPtables和IPVS模式之間的性能差異,請閱讀這篇文章。此外,您可以通過將其替換為ciilium來運行Kubernetes集群,而無需kube-proxy。
1.29 Alpha特性:Kubeproxy有一個新的基于????????????????的后端。nftables是IPtables的繼承者,旨在更簡單、更高效。
3.container runtime
你可能知道Java運行時(JRE)。它是在主機上運行Java程序所需的軟件。以同樣的方式,容器運行時是運行容器所需的軟件組件。
容器運行時運行在Kubernetes集群中的所有節點上。它負責從容器注冊表中拉取映像,運行容器,為容器分配和隔離資源,以及管理主機上容器的整個生命周期。
為了更好地理解這一點,讓我們看看兩個關鍵概念:
- 容器運行時接口(CRI) :它是一組api,允許Kubernetes與不同的容器運行時交互。它允許不同的容器運行時與Kubernetes互換使用。CRI定義了用于創建、啟動、停止和刪除容器以及管理映像和容器網絡的API。
- 開放容器計劃(Open Container Initiative, OCI):它是一組容器格式和運行時的標準
Kubernetes支持與容器運行時接口(CRI)兼容的多個容器運行時(CRI-O, Docker Engine, containerd等)。這意味著,所有這些容器運行時都實現了CRI接口并公開了gRPC CRI api(運行時和映像服務端點)。
那么Kubernetes如何利用容器運行時呢?
正如我們在Kubelet部分中了解到的,Kubelet代理負責使用CRI API與容器運行時交互,以管理容器的生命周期。它還從容器運行時獲取所有容器信息,并將其提供給控制平面。
讓我們以CRI-O容器運行時接口為例。以下是容器運行時如何與kubernetes一起工作的高級概述。
- 當從API服務器有對pod的新請求時,kubelet通過Kubernetes容器運行時接口與CRI-O守護進程通信,以啟動所需的容器。
- CRI-O使用容器/映像庫從配置的容器注冊表中檢查并提取所需的容器映像。
- 然后CRI-O為容器生成OCI運行時規范(JSON)。
- 然后,CRI-O啟動一個oci兼容運行時(runc),根據運行時規范啟動容器進程。
附加組件
- kube-dns: 負責為整個集群提供 DNS 服務
- Ingress Controller: 為服務提供外網入口
- Prometheus: 提供資源監控
- Dashboard: 提供 GUI
- Federation: 提供跨可用區的集群
- Fluentd-elasticsearch: 提供集群日志采集、存儲與查詢
參考文檔:
[1]Kubernetes pod優先級指南: https://devopscube.com/pod-priorityclass-preemption/