溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

從零開始入門 K8s| K8s 的應(yīng)用編排與管理

發(fā)布時間:2020-06-25 22:47:08 來源:網(wǎng)絡(luò) 閱讀:395 作者:阿里系統(tǒng)軟件技術(shù) 欄目:云計(jì)算

從零開始入門 K8s| K8s 的應(yīng)用編排與管理作者 | 張振 阿里巴巴高級技術(shù)專家

一、資源元信息

1. Kubernetes 資源對象

我們知道,Kubernetes 的資源對象組成:主要包括了 Spec、Status 兩部分。其中 Spec 部分用來描述期望的狀態(tài),Status 部分用來描述觀測到的狀態(tài)。

今天我們將為大家介紹 K8s 的另外一個部分,即元數(shù)據(jù)部分。該部分主要包括了用來識別資源的標(biāo)簽:Labels, 用來描述資源的注解;Annotations, 用來描述多個資源之間相互關(guān)系的 OwnerReference。這些元數(shù)據(jù)在 K8s 運(yùn)行中有非常重要的作用。

2. labels

第一個元數(shù)據(jù),也是最重要的一個元數(shù)據(jù)——資源標(biāo)簽。資源標(biāo)簽是一種具有標(biāo)識型的 Key:Value 元數(shù)據(jù),如下圖所示,展示了幾個常見的標(biāo)簽。

前三個標(biāo)簽都打在了 Pod 對象上,分別標(biāo)識了對應(yīng)的應(yīng)用環(huán)境、發(fā)布的成熟度和應(yīng)用的版本。從應(yīng)用標(biāo)簽的例子可以看到,標(biāo)簽的名字包括了一個域名的前綴,用來描述打標(biāo)簽的系統(tǒng)和工具, 最后一個標(biāo)簽打在 Node 對象上,還在域名前增加了版本的標(biāo)識 beta 字符串。

標(biāo)簽主要用來篩選資源和組合資源,可以使用類似于 SQL 查詢 select,來根據(jù) Label 查詢相關(guān)的資源。
從零開始入門 K8s| K8s 的應(yīng)用編排與管理


3. Selector

最常見的 Selector 就是相等型 Selector?,F(xiàn)在舉一個簡單的例子:

假設(shè)系統(tǒng)中有四個 Pod,每個 Pod 都有標(biāo)識系統(tǒng)層級和環(huán)境的標(biāo)簽,我們通過 Tie:front 這個標(biāo)簽,可以匹配左邊欄的 Pod,相等型 Selector 還可以包括多個相等條件,多個相等條件之間是邏輯”與“的關(guān)系。

在剛才的例子中,通過 Tie=front,Env=dev 的 Selector,我們可以篩選出所有 Tie=front,而且 Env=dev 的 Pod,也就是下圖中左上角的 Pod。另外一種 Selector 是集合型 Selector,在例子中,Selector 篩選所有環(huán)境是 test 或者 gray 的 Pod。

除了 in 的集合操作外,還有 notin 集合操作,比如 tie notin(front,back),將會篩選所有 tie 不是 front 且不是 back 的 Pod。另外,也可以根據(jù)是否存在某 lable 的篩選,如:Selector release,篩選所有帶 release 標(biāo)簽的 Pod。集合型和相等型的 Selector,也可以用“,”來連接,同樣的標(biāo)識邏輯”與“的關(guān)系。

從零開始入門 K8s| K8s 的應(yīng)用編排與管理

4. Annotations

另外一種重要的元數(shù)據(jù)是:annotations。一般是系統(tǒng)或者工具用來存儲資源的非標(biāo)示的信息,可以用來擴(kuò)展資源的 spec/status 的描述,這里給了幾個 annotations 的例子:

第一個例子,存儲了阿里云負(fù)載器的證書 ID,我們可以看到 annotations 一樣可以擁有域名的前綴,標(biāo)注中也可以包含版本信息。第二個 annotation存儲了 nginx 接入層的配置信息,我們可以看到 annotations 中包括“,”這樣無法出現(xiàn)在 label 中的特殊字符。第三個 annotations 一般可以在 kubectl apply 命令行操作后的資源中看到, annotation 值是一個結(jié)構(gòu)化的數(shù)據(jù),實(shí)際上是一個 json 串,標(biāo)記了上一次 kubectl 操作的資源的 json 的描述。

從零開始入門 K8s| K8s 的應(yīng)用編排與管理

5. Ownereference

最后一個元數(shù)據(jù)叫做 Ownereference。所謂所有者,一般就是指集合類的資源,比如說 Pod 集合,就有 replicaset、statefulset,這個將在后序的課程中講到。

集合類資源的控制器會創(chuàng)建對應(yīng)的歸屬資源。比如:replicaset 控制器在操作中會創(chuàng)建 Pod,被創(chuàng)建 Pod 的 Ownereference 就指向了創(chuàng)建 Pod 的 replicaset,Ownereference 使得用戶可以方便地查找一個創(chuàng)建資源的對象,另外,還可以用來實(shí)現(xiàn)級聯(lián)刪除的效果。

二、操作演示

這里通過 kubectl 命令去連接我們 ACK 中已經(jīng)創(chuàng)建好的一個 K8s 集群,然后來展示一下怎么查看和修改 K8s 對象中的元數(shù)據(jù),主要就是 Pod 的一個標(biāo)簽、注解,還有對應(yīng)的 Ownerference。

首先我們看一下集群里現(xiàn)在的配置情況:

1.查看 Pod,現(xiàn)在沒有任何的一個 Pod;

  • kubectl get pods

2.然后用事先準(zhǔn)備好的一個 Pod 的 yaml,創(chuàng)建一個 Pod 出來;

  • kubectl apply -f pod1.yaml
  • kubectl apply -f pod2.yaml

3.現(xiàn)在查看一下 Pod 打的標(biāo)簽,我們用 --show-labels 這個選項(xiàng),可以看到這兩個 Pod 都打上了一個部署環(huán)境和層級的標(biāo)簽;

  • kubectl get pods —show-labels

4.我們也可以通過另外一種方式來查看具體的資源信息。首先查看 nginx1 第一個 Pod 的一個信息,用 -o? yaml 的方式輸出,可以看到這個 Pod 元數(shù)據(jù)里面包括了一個 lables 的字段,里面有兩個 lable;

  • kubectl get pods nginx1 -o yaml | less

5.現(xiàn)在再想一下,怎么樣對 Pod 已有的 lable?進(jìn)行修改?我們先把它的部署環(huán)境,從開發(fā)環(huán)境改成測試環(huán)境,然后指定 Pod 名字,在環(huán)境再加上它的一個值 test ,看一下能不能成功。 這里報了一個錯誤,可以看到,它其實(shí)是說現(xiàn)在這個 label 已經(jīng)有值了;

  • kubectl label pods nginx1 env=test

6.如果想覆蓋掉它的話,得額外再加上一個覆蓋的選項(xiàng)。加上之后呢,我們應(yīng)該可以看到這個打標(biāo)已經(jīng)成功了;

  • kubectl label pods nginx1 env=test —overwrite

7.我們再看一下現(xiàn)在集群的 lable 設(shè)置情況,首先可以看到 nginx1 的確已經(jīng)加上了一個部署環(huán)境 test 標(biāo)簽;

  • kubectl get pods —show-labels

8.如果想要對 Pod 去掉一個標(biāo)簽,也是跟打標(biāo)簽一樣的操作,但是 env 后就不是等號了。只加上 label 名字,后面不加等號,改成用減號表示去除 label 的 k:v;

  • kubectl label pods nginx tie-

9.可以看到這個 label,去標(biāo)已經(jīng)完全成功;

  • kubectl get pods —show-labels

從零開始入門 K8s| K8s 的應(yīng)用編排與管理

10.下面來看一下配置的 label 值,的確能看到 nginx1 的這個 Pod 少了一個 tie=front 的標(biāo)簽。有了這個 Pod 標(biāo)簽之后,可以看一下怎樣用 label Selector 進(jìn)行匹配?首先 label Selector 是通過 -l 這個選項(xiàng)來進(jìn)行指定的 ,指定的時候,先試一下用相等型的一個 label 來篩選,所以我們指定的是部署環(huán)境等于測試的一個 Pod,我們可以看到能夠篩選出一臺;

  • kubectl get pods —show-labels -l env=test

11.假如說有多個相等的條件需要指定的,實(shí)際上這是一個與的關(guān)系,假如說 env 再等于 dev,我們實(shí)際上是一個 Pod 都拿不到的;

  • kubectl get pods —show-labels -l env=test,env=dev

12.然后假如說 env=dev,但是 tie=front,我們能夠匹配到第二個 Pod,也就是 nginx2;

  • kubectl get pods —show-labels -l env=dev,tie=front

13.我們還可以再試一下怎么樣用集合型的 label Selector 來進(jìn)行篩選。這一次我們還是想要匹配出所有部署環(huán)境是 test 或者是 dev 的一個 Pod,所以在這里加上一個引號,然后在括號里面指定所有部署環(huán)境的一個集合。這次能把兩個創(chuàng)建的 Pod 都篩選出來;

  • kubectl get pods —show-labels -l ’env in (dev,test)’

14.我們再試一下怎樣對 Pod 增加一個注解,注解的話,跟打標(biāo)是一樣的操作,但是把 label 命令改成 annotate 命令;然后,一樣指定類型和對應(yīng)的名字。后面就不是加上 label 的 k:v 了,而是加上 annotation 的 k:v。這里我們可以指定一個任意的字符串,比如說加上空格、加上逗號都可以;

  • kubectl annotate pods nginx1 my-annotate=‘my annotate,ok’

15.然后,我們再看一下這個 Pod 的一些元數(shù)據(jù),我們這邊能夠看到這個 Pod 的元數(shù)據(jù)里面 annotations,這是有一個 my-annotate 這個 Annotations;

  • kubectl get pods nging1 -o yaml | less

然后我們這里其實(shí)也能夠看到有一個 kubectl apply 的時候,kubectl 工具增加了一個 annotation,這也是一個 json 串。

從零開始入門 K8s| K8s 的應(yīng)用編排與管理

16.然后我們再演示一下看 Pod 的 Ownereference 是怎么出來的。原來的 Pod 都是直接通過創(chuàng)建 Pod 這個資源方式來創(chuàng)建的,這次換一種方式來創(chuàng)建:通過創(chuàng)建一個 ReplicaSet 對象來創(chuàng)建 Pod 。首先創(chuàng)建一個 ReplicaSet 對象,這個 ReplicaSet 對象可以具體查看一下;

  • kubectl apply -f rs.yaml
  • kubectl get replicasets ?nginx-replicasets -o yaml |less

從零開始入門 K8s| K8s 的應(yīng)用編排與管理

17.我們可以關(guān)注一下這個 ReplicaSet 里面 spec 里面,提到會創(chuàng)建兩個 Pod,然后 selector 通過匹配部署環(huán)境是 product 生產(chǎn)環(huán)境的這個標(biāo)簽來進(jìn)行匹配。所以我們可以看一下,現(xiàn)在集群中的 Pod 情況;

  • kubectl get pods

從零開始入門 K8s| K8s 的應(yīng)用編排與管理

18.將會發(fā)現(xiàn)多了兩個 Pod,仔細(xì)查看這兩個 Pod,可以看到 ReplicaSet 創(chuàng)建出來的 Pod 有一個特點(diǎn),即它會帶有 Ownereference,然后 Ownereference 里面指向了是一個 replicasets 類型,名字就叫做 nginx-replicasets;

  • kubectl get pods nginx-replicasets-rhd68 -o yaml | less

從零開始入門 K8s| K8s 的應(yīng)用編排與管理

三、控制器模式

1、控制循環(huán)

控制型模式最核心的就是控制循環(huán)的概念。在控制循環(huán)中包括了控制器、被控制的系統(tǒng),以及能夠觀測系統(tǒng)的傳感器,三個邏輯組件。

當(dāng)然這些組件都是邏輯的,外界通過修改資源 spec 來控制資源,控制器比較資源 spec 和 status,從而計(jì)算一個 diff,diff 最后會用來決定執(zhí)行對系統(tǒng)進(jìn)行什么樣的控制操作,控制操作會使得系統(tǒng)產(chǎn)生新的輸出,并被傳感器以資源 status 形式上報,控制器的各個組件將都會是獨(dú)立自主地運(yùn)行,不斷使系統(tǒng)向 spec 表示終態(tài)趨近。

從零開始入門 K8s| K8s 的應(yīng)用編排與管理

2、Sensor

控制循環(huán)中邏輯的傳感器主要由 Reflector、Informer、Indexer 三個組件構(gòu)成。

Reflector 通過 List 和 Watch K8s server 來獲取資源的數(shù)據(jù)。List 用來在 Controller 重啟以及 Watch 中斷的情況下,進(jìn)行系統(tǒng)資源的全量更新;而 Watch 則在多次 List 之間進(jìn)行增量的資源更新;Reflector 在獲取新的資源數(shù)據(jù)后,會在 Delta 隊(duì)列中塞入一個包括資源對象信息本身以及資源對象事件類型的 Delta 記錄,Delta 隊(duì)列中可以保證同一個對象在隊(duì)列中僅有一條記錄,從而避免 Reflector 重新 List 和 Watch 的時候產(chǎn)生重復(fù)的記錄。

Informer 組件不斷地從 Delta 隊(duì)列中彈出 delta 記錄,然后把資源對象交給 indexer,讓 indexer 把資源記錄在一個緩存中,緩存在默認(rèn)設(shè)置下是用資源的命名空間來做索引的,并且可以被 Controller Manager 或多個 Controller 所共享。之后,再把這個事件交給事件的回調(diào)函數(shù)

從零開始入門 K8s| K8s 的應(yīng)用編排與管理

控制循環(huán)中的控制器組件主要由事件處理函數(shù)以及 worker 組成,事件處理函數(shù)之間會相互關(guān)注資源的新增、更新、刪除的事件,并根據(jù)控制器的邏輯去決定是否需要處理。對需要處理的事件,會把事件關(guān)聯(lián)資源的命名空間以及名字塞入一個工作隊(duì)列中,并且由后續(xù)的 worker 池中的一個 Worker 來處理,工作隊(duì)列會對存儲的對象進(jìn)行去重,從而避免多個 Woker 處理同一個資源的情況。

Worker 在處理資源對象時,一般需要用資源的名字來重新獲得最新的資源數(shù)據(jù),用來創(chuàng)建或者更新資源對象,或者調(diào)用其他的外部服務(wù),Worker 如果處理失敗的時候,一般情況下會把資源的名字重新加入到工作隊(duì)列中,從而方便之后進(jìn)行重試。

3、控制循環(huán)例子-擴(kuò)容

這里舉一個簡單的例子來說明一下控制循環(huán)的工作原理。

ReplicaSet 是一個用來描述無狀態(tài)應(yīng)用的擴(kuò)縮容行為的資源, ReplicaSet controler 通過監(jiān)聽 ReplicaSet 資源來維持應(yīng)用希望的狀態(tài)數(shù)量,ReplicaSet 中通過 selector 來匹配所關(guān)聯(lián)的 Pod,在這里考慮 ReplicaSet rsA 的,replicas 從 2 被改到 3 的場景。

從零開始入門 K8s| K8s 的應(yīng)用編排與管理

首先,Reflector 會 watch 到 ReplicaSet 和 Pod 兩種資源的變化,為什么我們還會 watch pod 資源的變化稍后會講到。發(fā)現(xiàn) ReplicaSet 發(fā)生變化后,在 delta 隊(duì)列中塞入了對象是 rsA,而且類型是更新的記錄。

Informer 一方面把新的 ReplicaSet 更新到緩存中,并與 Namespace nsA 作為索引。另外一方面,調(diào)用 Update 的回調(diào)函數(shù),ReplicaSet 控制器發(fā)現(xiàn) ReplicaSet 發(fā)生變化后會把字符串的 nsA/rsA 字符串塞入到工作隊(duì)列中,工作隊(duì)列后的一個 Worker 從工作隊(duì)列中取到了 nsA/rsA 這個字符串的 key,并且從緩存中取到了最新的 ReplicaSet 數(shù)據(jù)。

Worker 通過比較 ReplicaSet 中 spec 和 status 里的數(shù)值,發(fā)現(xiàn)需要對這個 ReplicaSet 進(jìn)行擴(kuò)容,因此 ReplicaSet 的 Worker 創(chuàng)建了一個 Pod,這個 pod 中的 Ownereference 取向了 ReplicaSet rsA。

從零開始入門 K8s| K8s 的應(yīng)用編排與管理

然后 Reflector Watch 到的 Pod 新增事件,在 delta 隊(duì)列中額外加入了 Add 類型的 deta 記錄,一方面把新的 Pod 記錄通過 Indexer 存儲到了緩存中,另一方面調(diào)用了 ReplicaSet 控制器的 Add 回調(diào)函數(shù),Add 回調(diào)函數(shù)通過檢查 pod ownerReferences 找到了對應(yīng)的 ReplicaSet,并把包括 ReplicaSet 命名空間和字符串塞入到了工作隊(duì)列中。

ReplicaSet 的 Woker 在得到新的工作項(xiàng)之后,從緩存中取到了新的 ReplicaSet 記錄,并得到了其所有創(chuàng)建的 Pod,因?yàn)?ReplicaSet 的狀態(tài)不是最新的,也就是所有創(chuàng)建 Pod 的數(shù)量不是最新的。因此在此時 ReplicaSet 更新 status 使得 spec 和 status 達(dá)成一致。

從零開始入門 K8s| K8s 的應(yīng)用編排與管理

四、控制器模式總結(jié)

1、兩種 API 設(shè)計(jì)方法

Kubernetes 控制器模式依賴聲明式的 API。另外一種常見的 API 類型是命令式 API。為什么 Kubernetes 采用聲明式 API,而不是命令式 API 來設(shè)計(jì)整個控制器呢?

首先,比較兩種 API 在交互行為上的差別。在生活中,常見的命令式的交互方式是家長和孩子交流方式,因?yàn)楹⒆忧啡蹦繕?biāo)意識,無法理解家長期望,家長往往通過一些命令,教孩子一些明確的動作,比如說:吃飯、睡覺類似的命令。我們在容器編排體系中,命令式 API 就是通過向系統(tǒng)發(fā)出明確的操作來執(zhí)行的。

而常見的聲明式交互方式,就是老板對自己員工的交流方式。老板一般不會給自己的員工下很明確的決定,實(shí)際上可能老板對于要操作的事情本身,還不如員工清楚。因此,老板通過給員工設(shè)置可量化的業(yè)務(wù)目標(biāo)的方式,來發(fā)揮員工自身的主觀能動性。比如說,老板會要求某個產(chǎn)品的市場占有率達(dá)到 80%,而不會指出要達(dá)到這個市場占有率,要做的具體操作細(xì)節(jié)。

類似的,在容器編排體系中,我們可以執(zhí)行一個應(yīng)用實(shí)例副本數(shù)保持在 3 個,而不用明確的去擴(kuò)容 Pod 或是刪除已有的 Pod,來保證副本數(shù)在三個。

從零開始入門 K8s| K8s 的應(yīng)用編排與管理

2、命令式 API 的問題

在理解兩個交互 API 的差別后,可以分析一下命令式 API 的問題。

  • 命令 API 最大的一個問題在于錯誤處理;

在大規(guī)模的分布式系統(tǒng)中,錯誤是無處不在的。一旦發(fā)出的命令沒有響應(yīng),調(diào)用方只能通過反復(fù)重試的方式來試圖恢復(fù)錯誤,然而盲目的重試可能會帶來更大的問題。

假設(shè)原來的命令,后臺實(shí)際上已經(jīng)執(zhí)行完成了,重試后又多執(zhí)行了一個重試的命令操作。為了避免重試的問題,系統(tǒng)往往還需要在執(zhí)行命令前,先記錄一下需要執(zhí)行的命令,并且在重啟等場景下,重做待執(zhí)行的命令,而且在執(zhí)行的過程中,還需要考慮多個命令的先后順序、覆蓋關(guān)系等等一些復(fù)雜的邏輯情況。

  • 實(shí)際上許多命令式的交互系統(tǒng)后臺往往還會做一個巡檢的系統(tǒng),用來修正命令處理超時、重試等一些場景造成數(shù)據(jù)不一致的問題;

然而,因?yàn)檠矙z邏輯和日常操作邏輯是不一樣的,往往在測試上覆蓋不夠,在錯誤處理上不夠嚴(yán)謹(jǐn),具有很大的操作風(fēng)險,因此往往很多巡檢系統(tǒng)都是人工來觸發(fā)的。

  • 最后,命令式 API 在處理多并發(fā)訪問時,也很容易出現(xiàn)問題;

假如有多方并發(fā)的對一個資源請求進(jìn)行操作,并且一旦其中有操作出現(xiàn)了錯誤,就需要重試。那么最后哪一個操作生效了,就很難確認(rèn),也無法保證。很多命令式系統(tǒng)往往在操作前會對系統(tǒng)進(jìn)行加鎖,從而保證整個系統(tǒng)最后生效行為的可預(yù)見性,但是加鎖行為會降低整個系統(tǒng)的操作執(zhí)行效率。

  • 相對的,聲明式 API 系統(tǒng)里天然地記錄了系統(tǒng)現(xiàn)在和最終的狀態(tài)。

不需要額外的操作數(shù)據(jù)。另外因?yàn)闋顟B(tài)的冪等性,可以在任意時刻反復(fù)操作。在聲明式系統(tǒng)運(yùn)行的方式里,正常的操作實(shí)際上就是對資源狀態(tài)的巡檢,不需要額外開發(fā)巡檢系統(tǒng),系統(tǒng)的運(yùn)行邏輯也能夠在日常的運(yùn)行中得到測試和錘煉,因此整個操作的穩(wěn)定性能夠得到保證。

最后,因?yàn)橘Y源的最終狀態(tài)是明確的,我們可以合并多次對狀態(tài)的修改??梢圆恍枰渔i,就支持多方的并發(fā)訪問。

從零開始入門 K8s| K8s 的應(yīng)用編排與管理

3、控制器模式總結(jié)

最后我們總結(jié)一下:

  1. Kubernetes 所采用的控制器模式,是由聲明式 API 驅(qū)動的。確切來說,是基于對 Kubernetes 資源對象的修改來驅(qū)動的;
  2. Kubernetes 資源之后,是關(guān)注該資源的控制器。這些控制器將異步的控制系統(tǒng)向設(shè)置的終態(tài)驅(qū)近;
  3. 這些控制器是自主運(yùn)行的,使得系統(tǒng)的自動化和無人值守成為可能;
  4. 因?yàn)?Kubernetes 的控制器和資源都是可以自定義的,因此可以方便的擴(kuò)展控制器模式。特別是對于有狀態(tài)應(yīng)用,我們往往通過自定義資源和控制器的方式,來自動化運(yùn)維操作。這個也就是后續(xù)會介紹的 operator 的場景。

從零開始入門 K8s| K8s 的應(yīng)用編排與管理

本文總結(jié)

這里為大家簡單總結(jié)一下本文的主要內(nèi)容:

  • Kubernetes 資源對象中的元數(shù)據(jù)部分,主要包括了用來識別資源的標(biāo)簽:Labels, 用來描述資源的注解;Annotations, 用來描述多個資源之間相互關(guān)系的 OwnerReference。這些元數(shù)據(jù)在 K8s 運(yùn)行中有非常重要的作用;
  • 控制型模式中最核心的就是控制循環(huán)的概念;
  • 兩種 API 設(shè)計(jì)方法:聲明式 API 和命令式 API ;Kubernetes 所采用的控制器模式,是由聲明式 API 驅(qū)動的;

阿里巴巴云原生微信公眾號(ID:Alicloudnative)關(guān)注微服務(wù)、Serverless、容器、Service Mesh 等技術(shù)領(lǐng)域、聚焦云原生流行技術(shù)趨勢、云原生大規(guī)模的落地實(shí)踐,做最懂云原生開發(fā)者的技術(shù)公眾號。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI