一篇文章為你圖解Kubernetes對象模型
Kubernetes(以下簡寫為K8s)的對象模型是K8s又一精巧的設(shè)計。我們知道,K8s所建立的容器化生態(tài)是復(fù)雜且多變的,而對象模型就是將一系列的資源實體抽象成K8s中所能識別的對象。為了方便大家更全面的了解K8s的設(shè)計思想,本文對K8s的對象模型進行了梳理,同時在文章末尾增加了常見面試題問題匯總,章節(jié)內(nèi)容分配如下:
- K8s對象模型概述-我們?yōu)槭裁匆私鈱ο竽P?/li>
- K8s常見對象模型介紹-哪些對象模型可以為我們所用
- K8s對象模型的組織形式及yaml創(chuàng)建方法-我們該如何使用對象
- 總結(jié)
K8s對象模型概述-我們?yōu)槭裁匆私鈱ο竽P?/strong>
這問題還用想?存在即合理唄。那咱們就先來看看他為什么存在。
在官方文檔中,對K8s的對象模型有這樣的定義:
“在 Kubernetes 系統(tǒng)中,Kubernetes 對象是持久化的實體。Kubernetes 使用這些實體去表示整個集群的狀態(tài)。特別地,它們描述了如下信息:
- 哪些容器化應(yīng)用在運行(以及在哪個 Node 上)
- 可以被應(yīng)用使用的資源
- 關(guān)于應(yīng)用運行時表現(xiàn)的策略,比如重啟策略、升級策略,以及容錯策略”
簡單說來,對象模型主要有兩點目標:
1.服務(wù)于K8s集群
對象模型一個功能是用以抽象化描述K8s集群狀態(tài),實體及實體間關(guān)聯(lián)。此類的代表就是Label,它建立集群對象之間的靈活、松耦合的多維關(guān)聯(lián)關(guān)系,我們可以用通過lable selector 查詢和篩選建立對象間的關(guān)系的。
2.服務(wù)于用戶。
K8s提供多種抽象對象便于用戶部署自己的應(yīng)用到集群中,這些抽象對象為用戶屏蔽了復(fù)雜的底層邏輯,讓用戶更專注于如何去使用。此類的例子就比較多,比如Pod,Node,Deployment等。舉個例子來說,比如我們要部署應(yīng)用在8s集群內(nèi),首先要我們的應(yīng)用需要轉(zhuǎn)換為K8s所能管理的實體對象如Pod;對于多副本應(yīng)用,我們需要考慮進行統(tǒng)一的管理,可以考慮如Deployment;進一步考慮副本間的負載均衡和服務(wù)發(fā)現(xiàn),我們又可以考慮采用Service來實現(xiàn),用戶無需關(guān)注其內(nèi)部實現(xiàn),從而更專注于自身的應(yīng)用。
K8s常見對象模型-哪些對象模型可以為我們所用
既然把K8s對象模型吹得這么神,那得看看他是不是真有這么神。下面來一起看看K8s常見的對象。
這里再用一幅圖來更形象地介紹各個對象在K8s中的所處位置。

Workload類對象
Pod
位置:位于圖中標有Pod標記的位置
說明:Pod是集群中可以創(chuàng)建和部署的最小且最簡單的Kubernetes對象的單元,其表示單個 容器 或少量緊密耦合并共享資源的容器集合。
抽象與封裝:Pod封裝了應(yīng)用容器,存儲資源、獨立的網(wǎng)絡(luò)IP以及容器運行的策略選項。目前Docker 是 Kubernetes Pod 中最常用的容器運行時,因此在本文中所提到的容器均值docker容器。目前Docker 是 Kubernetes Pod 中最常用的容器運行時,因此在本文中所提到的容器均指docker容器。
在K8s中,每個pod中預(yù)置了一個Pause容器,其namespace、IPC資源、網(wǎng)絡(luò)和存儲資源被pod內(nèi)其它容器共享。Pod中的所有容器緊密協(xié)作,并且作為一個整體被管理、調(diào)度和運行。
Controllers
位置:位于圖中Master中的Controller-Manager位置。
說明:Controller Manager作為集群內(nèi)部的管理控制中心,負責(zé)集群內(nèi)的Node、Pod、服務(wù)端點(Endpoint)、命名空間(Namespace)、服務(wù)賬號(ServiceAccount)、資源定額(ResourceQuota)的管理。他們的職責(zé)是保證集群中各種資源的狀態(tài)和用戶定義(yaml)的狀態(tài)一致, 每個controller通過API Server提供的接口實時監(jiān)控整個集群的每個資源對象的當前狀態(tài),當發(fā)生各種故障導(dǎo)致系統(tǒng)狀態(tài)發(fā)生變化時,會嘗試將系統(tǒng)狀態(tài)修復(fù)到“期望狀態(tài)”。例如,當某個Node意外宕機時,Node Controller會及時發(fā)現(xiàn)并執(zhí)行自動化修復(fù)流程,確保Node始終處于預(yù)期的工作狀態(tài)。下圖列出了部分controller的圖例:

抽象與封裝:從邏輯上講,每個控制器都是一個單獨的進程,他們?yōu)橛脩舴庋b了針對于資源對象的管理邏輯。用戶在創(chuàng)建資源對象后,controller會幫助用戶實時監(jiān)控整個集群的每個資源對象的當前狀態(tài),自動化地確保資源對象始終處于預(yù)期的工作狀態(tài)。此外。K8s支持用戶自定義擴展controller。
Deployment/Statefulset/Daemonset/Job
位置:Deployment位于圖中④位置,Statefulset位于圖中⑤位置,Daemonset/Job位于圖中綠色Pod位置。
說明:這一類資源對象為Pod提供了一個聲明式定義(declarative)方法,但同時他們又各自負責(zé)處理不同的使用場景。Deployment 為 Pod 和 ReplicaSet 提供了一個聲明式定義(declarative)方法,用來替代以前的ReplicationController 來方便的管理應(yīng)用,主要是針對是 Kubernetes 中用于處理無狀態(tài)服務(wù)的資源。典型的應(yīng)用場景包括:
- 定義Deployment來創(chuàng)建Pod和ReplicaSet
- 滾動升級和回滾應(yīng)用
- 擴容和縮容
- 暫停和繼續(xù)Deployment
StatefulSet 是用于支持有狀態(tài)服務(wù)的資源,典型的應(yīng)用場景是Zookeeper、Kafka。它可以保證部署和 scale 的順序。其應(yīng)用場景包括:
- 穩(wěn)定的持久化存儲。
- 穩(wěn)定的網(wǎng)絡(luò)標志。
- 有序部署和擴展。
- 有序收縮和刪除。
DaemonSet不同于上兩個方式,它解決的場景是在集群中所有節(jié)點上同時提供基礎(chǔ)服務(wù)和守護進程。DaemonSet 可以保證集群中所有的或者部分的節(jié)點都能夠運行同一份 Pod 副本,如kube-router、flannel等都是以DaemonSet部署。
Job負責(zé)批處理任務(wù),即僅執(zhí)行一次的任務(wù),它保證批處理任務(wù)的一個或多個Pod成功結(jié)束,可應(yīng)用的場景如采集數(shù)據(jù)等??赡軙萌讼M茏詣踊亩〞r執(zhí)行任務(wù),就像crontab一樣,別急,K8s同樣針對定時任務(wù)提供了cronjob資源對象,能夠支持類似crontab一樣的定時功能。
Discovery&Loadbalance類對象
Service/Endpoints/Ingress
位置:Service在圖中①,②位置處。Ingress在圖中③處。
說明:Kubernetes Service 是對一個個Pod 的邏輯分組的抽象,它提供了一種可以訪問它們的策略,通常稱為微服務(wù)。
K8s通過抽象出Service概念,為后端綁定的pod服務(wù)提供服務(wù)發(fā)現(xiàn)和負載均衡功能,為一組具有相同功能的容器應(yīng)用提供一個統(tǒng)一的入口地址,并將請求進行負載分發(fā)到后端的各個容器應(yīng)用上的控制器。這一組 Pod 能夠被 Service 訪問到,通常是通過 Label Selector實現(xiàn)的。
Endpoint是K8s集群中的一個資源對象,存儲在etcd中,用來記錄一個Service對應(yīng)的所有pod的訪問地址。Service配置selector,endpoint controller才會自動創(chuàng)建對應(yīng)的endpoint對象;否則,不會生成Endpoint對象。
Ingress同樣是與Service相關(guān)的資源對象,它授權(quán)入站連接到達集群服務(wù)的規(guī)則集合。我們可以給Ingress配置提供外部可訪問的URL、負載均衡、SSL、基于名稱的虛擬主機等。用戶通過POST Ingress資源到API server的方式來請求ingress。 偷個懶,借用一張網(wǎng)絡(luò)上的圖來解釋一下三者關(guān)系(圖中的Pod可以理解為是EndPoints):

Config&Storage類對象
Configmap/ Secret/ Volume/ PersistentVolume
位置:Configmap、Secret位于圖中標有Configmap、Secret的位置。PersistentVolume則位于圖中PV1,PV2,PV3。
說明:在K8s中,定義了volume來解決容器的存儲問題,稱之為Volume。不僅能夠解決 Container 中文件的臨時性問題,也能夠讓同一個 Pod 中的多個 Container 共享文件。這里提到的卷(Volume)其實是一個比較特定的概念,它并不是一個持久化存儲,可能會隨著 Pod 的刪除而刪除,常見的卷就包括 EmptyDir、HostPath、ConfigMap 和 Secret,這些卷與所屬的 Pod 具有相同的生命周期。與Volume相對應(yīng)的,是持久卷概念,即PersistentVolume,他提供了持久化存儲的方案,將Pod與卷的聲明周期分離。
抽象與封裝:Volume和PersistentVolume為用戶屏蔽了集群中容器存儲的底層邏輯,集群中的每一個卷在被 Pod 使用時都會經(jīng)歷兩個操作,也就是掛載(Mount)、卸載(Unmount),有些如Configmap、Secret還會經(jīng)歷附著(Attach)、分離(Detach)操作,但這些操作用戶都不需要關(guān)心,只需要在yaml中設(shè)置數(shù)據(jù)源和掛載路徑就可以。同時,存儲對象的管理也是有對象自動進行的,創(chuàng)建和刪除存儲資源,對于用戶來說只需要簡單的create和delete,但實際上對于存儲資源的分配,回收也都有K8s自動完成。
Cluster類對象
Node/Namespace/Role/ClusterRole
位置:Node位于圖中黃色塊并標有Node的位置。Namespace是位于圖中標有Namespace的框,。Role是圖中位于盾牌位置, ClusterRole是圖中盾牌的全集。
說明:Cluster對象在K8s中代表著某些全局性的資源對象。Node不必多說,是K8s存在的物理基礎(chǔ)。Namespace類似編程語言中的作用域,K8s支持通過Namespace在一個物理集群中劃分出多個虛擬集群,這些虛擬集群使用單獨的命名空間。各個Namespace之間容器是不透明的,也便于用戶進行更細粒度的權(quán)限控制。
Role和ClusterRole負責(zé)為用戶提供集群內(nèi)的權(quán)限管理。Role對象用于授予對某一單一命名空間中資源的訪問權(quán)限,而整個Kubernetes集群范圍內(nèi)有效的角色則通過ClusterRole對象實現(xiàn)。在使用中,我們可以對以下幾種資源賦予權(quán)限:
- 集群范圍資源(如node)
- 非資源類型endpoint
- 跨命名空間的資源(例如跨namespace的pod)
抽象與封裝:Cluster類型的對象為用戶屏蔽了對于集群的管理邏輯。整個集群被抽象成一種扁平化的結(jié)構(gòu)。我們可以把集群比作一個象棋棋盤,Pod(棋子)優(yōu)先會部署在各自的區(qū)域(namespace),有些Pod(棋子)只能在各自區(qū)域操作,有些Pod(棋子)則可以跨區(qū)域操作。用戶只需要學(xué)會使用這些Pod(棋子),而具體的規(guī)則和執(zhí)行邏輯由K8s制定。
K8s對象模型的組織形式及yaml創(chuàng)建方法-我們該如何使用對象
在K8s中,提供給用戶的組織和創(chuàng)建對象的方式是通過yaml文件進行的,對于一個編寫好的yaml文件,可以采用以下指令來創(chuàng)建對象資源
- kubectl create/apply -f ***.yaml
通過下列指令就可以看到一個Pod對象的組織方式。
- kubectl describe pod *** -n <namespace>
下面,本節(jié)針對對象yaml的各個字段及各資源創(chuàng)建方式進行詳細解析。首先,我們需要建立一個概念,yaml文件是對對象描述的一種形象化,即描述對象的概念映射到y(tǒng)aml上就是一個個kv字段。在描述K8s對象時,有兩個嵌套字段是必須的,它們負責(zé)管理對象的配置:spec 和 status。spec必須提供,它描述了對象的期望狀態(tài)——希望對象所具有的特征。status 描述了對象的實際狀態(tài),它是由 K8s系統(tǒng)提供和更新。在任何時刻,K8s管理模塊一直處于活躍狀態(tài),管理著對象的實際狀態(tài)以與我們所期望的狀態(tài)相匹配。
例如:

可以看到Deployment對象的Spec和Status描述結(jié)構(gòu)。
再說yaml,對于不同的對象而言,yaml配置的內(nèi)容有所不同,但以下幾項是必選:
- apiVersion # 創(chuàng)建該對象所使用的 Kubernetes API 的版本
- kind # 想要創(chuàng)建的對象的類型
- metadata # 識別對象唯一性的數(shù)據(jù),包括一個 name 字符串、UID 和可選的 namespace
https://kubernetes.io/docs/api/)。下面我們對各資源的創(chuàng)建方式進行舉例:
Workload類對象
Pod類資源我們使用經(jīng)典案例——busybox的創(chuàng)建模板進行簡述:

這則模板中首先指定了yaml的三要素,apiVersion、kind、metadata。在Pod特有的spec中指定了所需的鏡像busybox,并簡單設(shè)置了鏡像拉取和容器重啟的策略。在使用過程中我們會發(fā)現(xiàn),簡單的配置后,因鏡像拉取或容器重啟帶來的異常管理問題,K8s都會幫你自動完成,也就是之前提到的對象的實際狀態(tài)以與我們所期望的狀態(tài)相匹配。
再舉一個例子,經(jīng)典的nginx模板用例:

Deployment用以描述一類Pod集合,因此這里指定了副本數(shù),并設(shè)置了selector來簡歷Pod與Deployment的關(guān)系。
Discovery&Loadbalance類對象
這一類資源代表具備網(wǎng)絡(luò)特性的對象,其中的代表對象就是Service,這里我們也列舉一個Service的經(jīng)典用例加以說明。

Service對象的yaml模板里,我們可以指定一個或一組Pod的通信端口及通信協(xié)議,并制定服務(wù)的暴露方式。
Config&Storage類對象
Configmap作為非持久化存儲的代表,我們先舉一個例子來說明:

Configmap的部署用例沒有spec域,直接指定了數(shù)據(jù)的內(nèi)容。除了以上使用yaml方式創(chuàng)建外,當我們將 ConfigMap 或者 Secret 包裝成卷并掛載到某個目錄時,我們其實是在創(chuàng)建 Volume,這些 Volume 并不是 Kubernetes 中的對象,它們只存在于當前 Pod 中,隨著 Pod 的刪除而刪除,但是需要注意的是這些臨時的Volume的刪除并不會導(dǎo)致相關(guān) ConfigMap 或者 Secret 對象的刪除。
我們再舉持久化存儲的例子。

持久化存儲的創(chuàng)建用例和Pod對象有些類似,需要制定存儲的預(yù)期狀態(tài),這里設(shè)置了一個容量為1G,以可讀可寫方式掛載到多個節(jié)點,并使用nfs掛載的PV存儲。這樣在創(chuàng)建完成后,就可以使用PVC在Pod進行存儲綁定了。
Cluster類對象
Cluster類對象多數(shù)屬于集群集群資源對象,默認可不需要用戶自己使用yaml創(chuàng)建,比如namespace就可以直接使用命令 kubectl create ns **** 來創(chuàng)建。這里我們舉一個ClusterRole的yaml例子。

在這個例子中,我們定義了一個ClusterRole的對象,它可以授予對secrets資源對象的get,watch,list權(quán)限。接來下我們就是用ClusterRoleBinding來使用它。ClusterRoleBinding可以將角色中定義的權(quán)限授予用戶或用戶組,ClusterRoleBinding包含一組權(quán)限列表(subjects),權(quán)限列表中包含有不同形式的待授予權(quán)限資源類型(如USER,GROUP,SERVICEACCOUNT),ClusterRoleBinding適用于集群范圍內(nèi)的授權(quán),與之相對應(yīng)的RoleBinding適用于某個命名空間內(nèi)授權(quán)。舉例說明:

在這個用例中,我們將secret這個ClusterRole綁定到了dazhuang這個用戶上,授權(quán)用戶dazhuang只能訪問myspace中的secret。
總結(jié)
K8s的對象模型是 K8s中非常重要的一部分,也是K8s構(gòu)建的基礎(chǔ)。K8s中各個對象為使用者屏蔽了復(fù)雜的底層細節(jié),并通過不斷獲取集群的運行狀態(tài)與期望狀態(tài)進行對比,來幫助使用者確保對象能在預(yù)期的狀態(tài)下運行,希望這篇文章能幫助各位讀者更全面的理解K8s的對象模型。