您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關(guān)如何進(jìn)行K8s 應(yīng)用編排與管理,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
首先來看一下背景問題。如下圖所示:如果我們直接管理集群中所有的 Pod,應(yīng)用 A、B、C 的 Pod,其實(shí)是散亂地分布在集群中。
現(xiàn)在有以下的問題:
首先,如何保證集群內(nèi)可用 Pod 的數(shù)量?也就是說我們應(yīng)用 A 四個 Pod 如果出現(xiàn)了一些宿主機(jī)故障,或者一些網(wǎng)絡(luò)問題,如何能保證它可用的數(shù)量?
如何為所有 Pod 更新鏡像版本?我們是否要某一個 Pod 去重建新版本的 Pod?
然后在更新過程中,如何保證服務(wù)的可用性?
以及更新過程中,如果發(fā)現(xiàn)了問題,如何快速回滾到上一個版本?
這里就引入了我們今天的主題:Deployment 管理部署發(fā)布的控制器。
可以看到我們通過 Deployment 將應(yīng)用 A、B、C 分別規(guī)劃到不同的 Deployment 中,每個 Deployment 其實(shí)是管理的一組相同的應(yīng)用 Pod,這組 Pod 我們認(rèn)為它是相同的一個副本,那么 Deployment 能幫我們做什么事情呢?
首先,Deployment 定義了一種 Pod 期望數(shù)量,比如說應(yīng)用 A,我們期望 Pod 數(shù)量是四個,那么這樣的話,controller 就會持續(xù)維持 Pod 數(shù)量為期望的數(shù)量。當(dāng)我們與 Pod 出現(xiàn)了網(wǎng)絡(luò)問題或者宿主機(jī)問題的話,controller 能幫我們恢復(fù),也就是新擴(kuò)出來對應(yīng)的 Pod,來保證可用的 Pod 數(shù)量與期望數(shù)量一致;
配置 Pod 發(fā)布方式,也就是說 controller 會按照用戶給定的策略來更新 Pod,而且更新過程中,也可以設(shè)定不可用 Pod 數(shù)量在多少范圍內(nèi);
如果更新過程中發(fā)生問題的話,即所謂“一鍵”回滾,也就是說你通過一條命令或者一行修改能夠?qū)?Deployment 下面所有 Pod 更新為某一個舊版本 。
下面我們用一個簡單的用例來解讀一下如何操作 Deployment。
上圖可以看到一個最簡單的 Deployment 的 yaml 文件。
“apiVersion:apps/v1”,也就是說 Deployment 當(dāng)前所屬的組是 apps,版本是 v1。“metadata”是我們看到的 Deployment 元信息,也就是往期回顧中的 Labels、Selector、Pod.image,這些都是在往期中提到的知識點(diǎn)
Deployment 作為一個 K8s 資源,它有自己的 metadata 元信息,這里我們定義的 Deployment.name 是 nginx.Deployment。Deployment.spec 中首先要有一個核心的字段,即 replicas,這里定義期望的 Pod 數(shù)量為三個;selector 其實(shí)是 Pod 選擇器,那么所有擴(kuò)容出來的 Pod,它的 Labels 必須匹配 selector 層上的 image.labels,也就是 app.nginx。
就如上面的 Pod 模板 template 中所述,這個 template 它其實(shí)包含了兩部分內(nèi)容:
一部分是我們期望 Pod 的 metadata,其中包含了 labels,即跟 selector.matchLabels 相匹配的一個 Labels;
第二部分是 template 包含的一個 Pod.spec。這里 Pod.spec 其實(shí)是 Deployment 最終創(chuàng)建出來 Pod 的時(shí)候,它所用的 Pod.spec,這里定義了一個 container.nginx,它的鏡像版本是 nginx:1.7.9。
下面是遇到的新知識點(diǎn):
第一個是 replicas,就是 Deployment 中期望的或者終態(tài)數(shù)量;
第二個是 template,也就是 Pod 相關(guān)的一個模板。
當(dāng)我們創(chuàng)建出一個 Deployment 的時(shí)候,可以通過 kubectl get deployment,看到 Deployment 總體的一個狀態(tài)。如下圖所示:
上圖中可以看到:
DESIRED:期望的 Pod 數(shù)量是 3 個;
CURRENT:當(dāng)前實(shí)際 Pod 數(shù)量是 3 個;
UP-TO-DATE:其實(shí)是到達(dá)最新的期望版本的 Pod 數(shù)量;
AVAILABLE:這個其實(shí)是運(yùn)行過程中可用的 Pod 數(shù)量。后面會提到,這里 AVAILABLE 并不簡單是可用的,也就是 Ready 狀態(tài)的,它其實(shí)包含了一些可用超過一定時(shí)間長度的 Pod;
AGE:deployment 創(chuàng)建的時(shí)長,如上圖 Deployment 就是已經(jīng)創(chuàng)建了 80 分鐘。
最后我們可以查看一下 Pod。如下圖所示:
上圖中有三個 Pod,Pod 名字格式我們不難看到。
最前面一段:nginx-deployment,其實(shí)是 Pod 所屬 Deployment.name;中間一段:template-hash,這里三個 Pod 是一樣的,因?yàn)檫@三個 Pod 其實(shí)都是同一個 template 中創(chuàng)建出來的。
最后一段,是一個 random 的字符串,我們通過 get.pod 可以看到,Pod 的 ownerReferences 即 Pod 所屬的 controller 資源,并不是 Deployment,而是一個 ReplicaSet。這個 ReplicaSet 的 name,其實(shí)是 nginx-deployment 加上 pod.template-hash,后面會提到。所有的 Pod 都是 ReplicaSet 創(chuàng)建出來的,而 ReplicaSet 它對應(yīng)的某一個具體的 Deployment.template 版本。
接下來我們可以看一下,如何對一個給定的 Deployment 更新它所有Pod的鏡像版本呢?這里我們可以執(zhí)行一個 kubectl 命令:
kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1
首先 kubectl 后面有一個 set image 固定寫法,這里指的是設(shè)定鏡像;
其次是一個 deployment.v1.apps,這里也是一個固定寫法,寫的是我們要操作的資源類型,deployment 是資源名、v1 是資源版本、apps 是資源組,這里也可以簡寫為 deployment 或者 deployment.apps,比如說寫為 deployment 的時(shí)候,默認(rèn)將使用 apps 組 v1 版本。
第三部分是要更新的 deployment 的 name,也就是我們的 nginx-deployment;再往后的 nginx 其實(shí)指的是 template,也就是 Pod 中的 container.name;這里我們可以注意到:一個 Pod 中,其實(shí)可能存在多個 container,而我們指定想要更新的鏡像的 container.name,就是 nginx。
最后,指定我們這個容器期望更新的鏡像版本,這里指的是 nginx: 1.9.1。如下圖所示:當(dāng)執(zhí)行完這條命令之后,可以看到 deployment 中的 template.spec 已經(jīng)更新為 nginx: 1.9.1。
如果我們在發(fā)布過程中遇到了問題,也支持快速回滾。通過 kubectl 執(zhí)行的話,其實(shí)是“kubectl rollout undo”這個命令,可以回滾到 Deployment 上一版本;通過“rollout undo”加上“to-revision”來指定可以回滾到某一個具體的版本。
最后我們來看一下 DeploymeStatus。每一個資源都有它的 spec.Status。這里可以看一下,deploymentStatus 中描述的三個其實(shí)是它的 conversion 狀態(tài),也就是 Processing、Complete 以及 Failed。
以 Processing 為例:Processing 指的是 Deployment 正在處于擴(kuò)容和發(fā)布中。比如說 Processing 狀態(tài)的 deployment,它所有的 replicas 及 Pod 副本全部達(dá)到最新版本,而且是 available,這樣的話,就可以進(jìn)入 complete 狀態(tài)。而 complete 狀態(tài)如果發(fā)生了一些擴(kuò)縮容的話,也會進(jìn)入 processing 這個處理工作狀態(tài)。
如果在處理過程中遇到一些問題:比如說拉鏡像失敗了,或者說 readiness probe 檢查失敗了,就會進(jìn)入 failed 狀態(tài);如果在運(yùn)行過程中即 complete 狀態(tài),中間運(yùn)行時(shí)發(fā)生了一些 pod readiness probe 檢查失敗,這個時(shí)候 deployment 也會進(jìn)入 failed 狀態(tài)。進(jìn)入 failed 狀態(tài)之后,除非所有點(diǎn) replicas 均變成 available,而且是 updated 最新版本,deployment 才會重新進(jìn)入 complete 狀態(tài)。
下面我們來進(jìn)行操作演示:這里連接一個阿里云服務(wù)集群。我們可以看到當(dāng)前集群已經(jīng)有幾個可用的 node。
首先創(chuàng)建對應(yīng)的 deployment??梢钥吹?deployment 中的 desired、current、up-to-date 以及 available 已經(jīng)都達(dá)到了可用的期望狀態(tài)。
這里看到 spec 中的 replicas 是三個,selector 以及 template labels中定義的標(biāo)簽都是 app:nginx,spec 中的 image 是我們期望的 nginx: 1.7.9;status 中的 available.replicas,readReplicas 以及 updatedReplicas 都是 3 個。
我們可以再選擇一個 Pod 看一下狀態(tài):
可以看到:Pod 中 ownerReferences 的功能是 ReplicaSet;pod.spec.container 里的鏡像是 1.7.9。這個 Pod 已經(jīng)是 Running 狀態(tài),而且它的 conditions.status 是“true”,表示它的服務(wù)已經(jīng)可用了。
當(dāng)前只有最新版本的 replicaset,那么現(xiàn)在嘗試對 deployment 做一次升級。
“kubectl set image”這個操作命令,后面接 “deployment”,加 deployment.name,最后指定容器名,以及我們期望升級的鏡像版本。
接下來我們看下 deployment 中的 template 中的 image 已經(jīng)更新為 1.9.1。
這個時(shí)候我們再 get pod 看一下狀態(tài)。
三個 pod 已經(jīng)升級為新版本,pod 名字中的 pod-template-hash 也已更新。
可以看到:舊版本 replicaset 的 spec 數(shù)量以及 pod 數(shù)量是都是 0,新版本的 pod 數(shù)量是 3 個。
假設(shè)又做了一次更新,這個時(shí)候 get.pod 其實(shí)可以看到:當(dāng)前的 pod 其實(shí)是有兩個舊版本的處于 running,另一個舊版本是在刪除中;而兩個新版本的 pod,一個已經(jīng)進(jìn)入 running,一個還在 creating 中。
這時(shí)我們可用的 pod 數(shù)量即非刪除狀態(tài)的 pod 數(shù)量,其實(shí)是 4 個,已經(jīng)超過了 replica 原先在 deployment 設(shè)置的數(shù)量 3 個。這個原因是我們在 deployment 中有 maxavailable 和 maxsugar 兩個操作,這兩個配置可以限制我們在發(fā)布過程中的一些策略。在后面架構(gòu)設(shè)計(jì)中會講到這個問題。
上圖看到,我們當(dāng)前最新版本的 replicaset 是 3 個 pod,另外還有兩個歷史版本的 replicaset,那么會不會存在一種情況:隨著 deployment 持續(xù)的更新,這個舊版本的 replicaset 會越積越多。其實(shí) deployment 提供了一個機(jī)制來避免這個問題:在 deployment spec 中,有一個 revisionHistoryLimit,它的默認(rèn)值為 10,它其實(shí)保證了保留歷史版本的 replicaset 的數(shù)量,我們嘗試把它改為 1。
由上面第二張圖,可以看到兩個 replicaset,也就是說,除了當(dāng)前版本的 replicaset 之外,舊版本的 replicaset 其實(shí)只保留了一個。
最后再嘗試做一下回滾。首先再來看一下 replicaset,這時(shí)發(fā)現(xiàn)舊版本的 replicaset 數(shù)量從 0 個增到 2 個,而新版本的 replicaset 數(shù)量從 3 個削減為 1 個,表示它已經(jīng)開始在做回滾的操作。然后再觀察一下, 舊版本的數(shù)量已經(jīng)是 3 個,即已經(jīng)回滾成功,而新版本的 pod 數(shù)量變?yōu)?0 個。
我們最后再 get pod 看一下:
這時(shí),3 個 pod.template-hash 已經(jīng)更新為舊版本的 hash,但其實(shí)這 3 個 pod 都是重新創(chuàng)建出來的,而并非我們在前一版本中創(chuàng)建的 3 個 pod。換句話說,也就是我們回滾的時(shí)候,其實(shí)是創(chuàng)建了 3 個舊版本的 pod,而并非把先前的 3 個 pod 找回來。
我們來看一下架構(gòu)設(shè)計(jì)。首先簡單看一下管理模式:Deployment 只負(fù)責(zé)管理不同版本的 ReplicaSet,由 ReplicaSet 來管理具體的 Pod 副本數(shù),每個 ReplicaSet 對應(yīng) Deployment template 的一個版本。在上文的例子中可以看到,每一次修改 template,都會生成一個新的 ReplicaSet,這個 ReplicaSet 底下的 Pod 其實(shí)都是相同的版本。
如上圖所示:Deployment 創(chuàng)建 ReplicaSet,而 ReplicaSet 創(chuàng)建 Pod。他們的 OwnerRef 其實(shí)都對應(yīng)了其控制器的資源。
我們先簡單看一下控制器實(shí)現(xiàn)原理。
首先,我們所有的控制器都是通過 Informer 中的 Event 做一些 Handler 和 Watch。這個地方 Deployment 控制器,其實(shí)是關(guān)注 Deployment 和 ReplicaSet 中的 event,收到事件后會加入到隊(duì)列中。而 Deployment controller 從隊(duì)列中取出來之后,它的邏輯會判斷 Check Paused,這個 Paused 其實(shí)是 Deployment 是否需要新的發(fā)布,如果 Paused 設(shè)置為 true 的話,就表示這個 Deployment 只會做一個數(shù)量上的維持,不會做新的發(fā)布。
如上圖,可以看到如果 Check paused 為 Yes 也就是 true 的話,那么只會做 Sync replicas。也就是說把 replicas sync 同步到對應(yīng)的 ReplicaSet 中,最后再 Update Deployment status,那么 controller 這一次的 ReplicaSet 就結(jié)束了。
那么如果 paused 為 false 的話,它就會做 Rollout,也就是通過 Create 或者是 Rolling 的方式來做更新,更新的方式其實(shí)也是通過 Create/Update/Delete 這種 ReplicaSet 來做實(shí)現(xiàn)的。
當(dāng) Deployment 分配 ReplicaSet 之后,ReplicaSet 控制器本身也是從 Informer 中 watch 一些事件,這些事件包含了 ReplicaSet 和 Pod 的事件。從隊(duì)列中取出之后,ReplicaSet controller 的邏輯很簡單,就只管理副本數(shù)。也就是說如果 controller 發(fā)現(xiàn) replicas 比 Pod 數(shù)量大的話,就會擴(kuò)容,而如果發(fā)現(xiàn)實(shí)際數(shù)量超過期望數(shù)量的話,就會刪除 Pod。
上面 Deployment 控制器的圖中可以看到,Deployment 控制器其實(shí)做了更復(fù)雜的事情,包含了版本管理,而它把每一個版本下的數(shù)量維持工作交給 ReplicaSet 來做。
下面來看一些操作模擬,比如說擴(kuò)容模擬。這里有一個 Deployment,它的副本數(shù)是 2,對應(yīng)的 ReplicaSet 有 Pod1 和 Pod2。這時(shí)如果我們修改 Deployment replicas, controller 就會把 replicas 同步到當(dāng)前版本的 ReplicaSet 中,這個 ReplicaSet 發(fā)現(xiàn)當(dāng)前有 2 個 Pod,不滿足當(dāng)前期望 3 個,就會創(chuàng)建一個新的 Pod3。
我們再模擬一下發(fā)布,發(fā)布的情況會稍微復(fù)雜一點(diǎn)。這里可以看到 Deployment 當(dāng)前初始的 template,比如說 template1 這個版本。template1 這個 ReplicaSet 對應(yīng)的版本下有三個 Pod:Pod1,Pod2,Pod3。
這時(shí)修改 template 中一個容器的 image, Deployment controller 就會新建一個對應(yīng) template2 的 ReplicaSet。創(chuàng)建出來之后 ReplicaSet 會逐漸修改兩個 ReplicaSet 的數(shù)量,比如它會逐漸增加 ReplicaSet2 中 replicas 的期望數(shù)量,而逐漸減少 ReplicaSet1 中的 Pod 數(shù)量。
那么最終達(dá)到的效果是:新版本的 Pod 為 Pod4、Pod5 和 Pod6,舊版本的 Pod 已經(jīng)被刪除了,這里就完成了一次發(fā)布。
來看一下回滾模擬,根據(jù)上面的發(fā)布模擬可以知道 Pod4、Pod5、Pod6 已經(jīng)發(fā)布完成。這時(shí)發(fā)現(xiàn)當(dāng)前的業(yè)務(wù)版本是有問題的,如果做回滾的話,不管是通過 rollout 命令還是通過回滾修改 template,它其實(shí)都是把 template 回滾為舊版本的 template1。
這個時(shí)候 Deployment 會重新修改 ReplicaSet1 中 Pod 的期望數(shù)量,把期望數(shù)量修改為 3 個,且會逐漸減少新版本也就是 ReplicaSet2 中的 replica 數(shù)量,最終的效果就是把 Pod 從舊版本重新創(chuàng)建出來。
發(fā)布模擬的圖中可以看到,其實(shí)初始版本中 Pod1、Pod2、Pod3 是舊版本,而回滾之后其實(shí)是 Pod7、Pod8、Pod9。就是說它的回滾并不是把之前的 Pod 重新找出來,而是說重新創(chuàng)建出符合舊版本 template 的 Pod。
最后再來簡單看一些 Deployment 中的字段解析。首先看一下 Deployment 中其他的 spec 字段:
MinReadySeconds:Deployment 會根據(jù) Pod ready 來看 Pod 是否可用,但是如果我們設(shè)置了 MinReadySeconds 之后,比如設(shè)置為 30 秒,那 Deployment 就一定會等到 Pod ready 超過 30 秒之后才認(rèn)為 Pod 是 available 的。Pod available 的前提條件是 Pod ready,但是 ready 的 Pod 不一定是 available 的,它一定要超過 MinReadySeconds 之后,才會判斷為 available;
revisionHistoryLimit:保留歷史 revision,即保留歷史 ReplicaSet 的數(shù)量,默認(rèn)值為 10 個。這里可以設(shè)置為一個或兩個,如果回滾可能性比較大的話,可以設(shè)置數(shù)量超過 10;
paused:paused 是標(biāo)識,Deployment 只做數(shù)量維持,不做新的發(fā)布,這里在 Debug 場景可能會用到;
progressDeadlineSeconds:前面提到當(dāng) Deployment 處于擴(kuò)容或者發(fā)布狀態(tài)時(shí),它的 condition 會處于一個 processing 的狀態(tài),processing 可以設(shè)置一個超時(shí)時(shí)間。如果超過超時(shí)時(shí)間還處于 processing,那么 controller 將認(rèn)為這個 Pod 會進(jìn)入 failed 的狀態(tài)。
最后來看一下升級策略字段解析。
Deployment 在 RollingUpdate 中主要提供了兩個策略,一個是 MaxUnavailable,另一個是 MaxSurge。這兩個字段解析的意思,可以看下圖中詳細(xì)的 comment,或者簡單解釋一下:
MaxUnavailable:滾動過程中最多有多少個 Pod 不可用;
MaxSurge:滾動過程中最多存在多少個 Pod 超過預(yù)期 replicas 數(shù)量。
上文提到,ReplicaSet 為 3 的 Deployment 在發(fā)布的時(shí)候可能存在一種情況:新版本的 ReplicaSet 和舊版本的 ReplicaSet 都可能有兩個 replicas,加在一起就是 4 個,超過了我們期望的數(shù)量三個。這是因?yàn)槲覀兡J(rèn)的 MaxUnavailable 和 MaxSurge 都是 25%,默認(rèn) Deployment 在發(fā)布的過程中,可能有 25% 的 replica 是不可用的,也可能超過 replica 數(shù)量 25% 是可用的,最高可以達(dá)到 125% 的 replica 數(shù)量。
這里其實(shí)可以根據(jù)用戶實(shí)際場景來做設(shè)置。比如當(dāng)用戶的資源足夠,且更注重發(fā)布過程中的可用性,可設(shè)置 MaxUnavailable 較小、MaxSurge 較大。但如果用戶的資源比較緊張,可以設(shè)置 MaxSurge 較小,甚至設(shè)置為 0,這里要注意的是 MaxSurge 和 MaxUnavailable 不能同時(shí)為 0。
理由不難理解,當(dāng) MaxSurge 為 0 的時(shí)候,必須要刪除 Pod,才能擴(kuò)容 Pod;如果不刪除 Pod 是不能新擴(kuò) Pod 的,因?yàn)樾聰U(kuò)出來的話,總共的 Pod 數(shù)量就會超過期望數(shù)量。而兩者同時(shí)為 0 的話,MaxSurge 保證不能新擴(kuò) Pod,而 MaxUnavailable 不能保證 ReplicaSet 中有 Pod 是 available 的,這樣就會產(chǎn)生問題。所以說這兩個值不能同時(shí)為 0。用戶可以根據(jù)自己的實(shí)際場景來設(shè)置對應(yīng)的、合適的值。
這里為大家簡單總結(jié)一下本文的主要內(nèi)容:
Deployment 是 Kubernetes 中常見的一種 Workload,支持部署管理多版本的 Pod;
Deployment 管理多版本的方式,是針對每個版本的 template 創(chuàng)建一個 ReplicaSet,由 ReplicaSet 維護(hù)一定數(shù)量的 Pod 副本,而 Deployment 只需要關(guān)心不同版本的 ReplicaSet 里要指定多少數(shù)量的 Pod;
因此,Deployment 發(fā)布部署的根本原理,就是 Deployment 調(diào)整不同版本 ReplicaSet 里的終態(tài)副本數(shù),以此來達(dá)到多版本 Pod 的升級和回滾。
以上就是如何進(jìn)行K8s 應(yīng)用編排與管理,小編相信有部分知識點(diǎn)可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。