Deployment-最基本的控制器對(duì)象

編排其實(shí)很簡(jiǎn)單:談?wù)劇翱刂破鳌蹦P?/h2>

Pod 這個(gè)看似復(fù)雜的 API 對(duì)象翔冀,實(shí)際上就是對(duì)容器的進(jìn)一步抽象和封裝而已。
“容器”鏡像雖然好用涝滴,但是容器這樣一個(gè)“沙盒”的概念涮瞻,對(duì)于描述應(yīng)用來(lái)說(shuō)鲤拿,還是太過(guò)簡(jiǎn)單了。這就好比署咽,集裝箱固然好用近顷,但是如果它四面都光禿禿的,吊車還怎么把這個(gè)集裝箱吊起來(lái)并擺放好呢艇抠?

Pod 對(duì)象幕庐,其實(shí)就是容器的升級(jí)版久锥。它對(duì)容器進(jìn)行了組合家淤,添加了更多的屬性和字段。這就好比給集裝箱四面安裝了吊環(huán)瑟由,使得 Kubernetes 這架“吊車”絮重,可以更輕松地操作它。

而 Kubernetes 操作這些“集裝箱”的邏輯歹苦,都由控制器(Controller)完成.

Deployment 這個(gè)最基本的控制器對(duì)象青伤。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

這個(gè) Deployment 定義的編排動(dòng)作非常簡(jiǎn)單,即:確保攜帶了 app=nginx 標(biāo)簽的 Pod 的個(gè)數(shù)殴瘦,永遠(yuǎn)等于 spec.replicas 指定的個(gè)數(shù)狠角,即 2 個(gè)蚪腋。

這就意味著丰歌,如果在這個(gè)集群中,攜帶 app=nginx 標(biāo)簽的 Pod 的個(gè)數(shù)大于 2 的時(shí)候屉凯,就會(huì)有舊的 Pod 被刪除立帖;反之,就會(huì)有新的 Pod 被創(chuàng)建悠砚。

kube-controller-manager 的組件晓勇,在執(zhí)行這些操作。

這個(gè)組件灌旧,就是一系列控制器的集合绑咱。我們可以查看一下 Kubernetes 項(xiàng)目的 pkg/controller 目錄:

$ cd kubernetes/pkg/controller/
$ ls -d */              
deployment/             job/                    podautoscaler/          
cloud/                  disruption/             namespace/              
replicaset/             serviceaccount/         volume/
cronjob/                garbagecollector/       nodelifecycle/          replication/            statefulset/            daemon/
...

這個(gè)目錄下面的每一個(gè)控制器,都以獨(dú)有的方式負(fù)責(zé)某種編排功能枢泰。而我們的 Deployment描融,正是這些控制器中的一種。

這些控制器之所以被統(tǒng)一放在 pkg/controller 目錄下宗苍,就是因?yàn)樗鼈兌甲裱?Kubernetes 項(xiàng)目中的一個(gè)通用編排模式稼稿,即:控制循環(huán)(control loop)

比如薄榛,現(xiàn)在有一種待編排的對(duì)象 X,它有一個(gè)對(duì)應(yīng)的控制器让歼。那么敞恋,我就可以用一段 Go 語(yǔ)言風(fēng)格的偽代碼,為你描述這個(gè)控制循環(huán):

for {
  實(shí)際狀態(tài) := 獲取集群中對(duì)象X的實(shí)際狀態(tài)(Actual State)
  期望狀態(tài) := 獲取集群中對(duì)象X的期望狀態(tài)(Desired State)
  if 實(shí)際狀態(tài) == 期望狀態(tài){
    什么都不做
  } else {
    執(zhí)行編排動(dòng)作谋右,將實(shí)際狀態(tài)調(diào)整為期望狀態(tài)
  }
}

在具體實(shí)現(xiàn)中硬猫,實(shí)際狀態(tài)往往來(lái)自于 Kubernetes 集群本身

  • 比如,kubelet 通過(guò)心跳匯報(bào)的容器狀態(tài)和節(jié)點(diǎn)狀態(tài)改执,或者監(jiān)控系統(tǒng)中保存的應(yīng)用監(jiān)控?cái)?shù)據(jù)啸蜜,或者控制器主動(dòng)收集的它自己感興趣的信息,這些都是常見(jiàn)的實(shí)際狀態(tài)的來(lái)源辈挂。

而期望狀態(tài)衬横,一般來(lái)自于用戶提交的 YAML 文件

  • 比如,Deployment 對(duì)象中 Replicas 字段的值终蒂。很明顯蜂林,這些信息往往都保存在 Etcd 中。

以 Deployment 為例拇泣,我和你簡(jiǎn)單描述一下它對(duì)控制器模型的實(shí)現(xiàn):

  • Deployment 控制器從 Etcd 中獲取到所有攜帶了“app: nginx”標(biāo)簽的 Pod噪叙,然后統(tǒng)計(jì)它們的數(shù)量,這就是實(shí)際狀態(tài)霉翔;

  • Deployment 對(duì)象的 Replicas 字段的值就是期望狀態(tài)睁蕾;

  • Deployment 控制器將兩個(gè)狀態(tài)做比較,然后根據(jù)比較結(jié)果债朵,確定是創(chuàng)建 Pod子眶,還是刪除已有的 Pod。

可以看到葱弟,一個(gè) Kubernetes 對(duì)象的主要編排邏輯壹店,實(shí)際上是在第三步的“對(duì)比”階段完成的。這個(gè)操作芝加,通常被叫作調(diào)諧(Reconcile)硅卢。
這個(gè)調(diào)諧的過(guò)程,則被稱作“Reconcile Loop”(調(diào)諧循環(huán))或者“Sync Loop”(同步循環(huán))藏杖。

它們其實(shí)指的都是同一個(gè)東西:控制循環(huán)将塑。而調(diào)諧的最終結(jié)果,往往都是對(duì)被控制對(duì)象的某種寫操作蝌麸。

比如点寥,增加 Pod,刪除已有的 Pod来吩,或者更新 Pod 的某個(gè)字段敢辩。這也是 Kubernetes 項(xiàng)目“面向 API 對(duì)象編程”的一個(gè)直觀體現(xiàn)蔽莱。

其實(shí),像 Deployment 這種控制器的設(shè)計(jì)原理戚长,就是我們前面提到過(guò)的盗冷,“用一種對(duì)象管理另一種對(duì)象”的“藝術(shù)”。

其中同廉,這個(gè)控制器對(duì)象本身仪糖,負(fù)責(zé)定義被管理對(duì)象的期望狀態(tài)。比如迫肖,Deployment 里的 replicas=2 這個(gè)字段锅劝。

而被控制對(duì)象的定義,則來(lái)自于一個(gè)“模板”蟆湖。比如故爵,Deployment 里的 template 字段。

可以看到帐姻,Deployment 這個(gè) template 字段里的內(nèi)容稠集,跟一個(gè)標(biāo)準(zhǔn)的 Pod 對(duì)象的 API 定義奶段,絲毫不差饥瓷。

而所有被這個(gè) Deployment 管理的 Pod 實(shí)例,其實(shí)都是根據(jù)這個(gè) template 字段的內(nèi)容創(chuàng)建出來(lái)的痹籍。

像 Deployment 定義的 template 字段呢铆,在 Kubernetes 項(xiàng)目中有一個(gè)專有的名字,叫作 PodTemplate(Pod 模板)蹲缠。

這個(gè)概念非常重要棺克,因?yàn)楹竺嫖乙v解到的大多數(shù)控制器,都會(huì)使用 PodTemplate 來(lái)統(tǒng)一定義它所要管理的 Pod线定。

更有意思的是娜谊,我們還會(huì)看到其他類型的對(duì)象模板,比如 Volume 的模板斤讥。

對(duì) Deployment 以及其他類似的控制器纱皆,做一個(gè)簡(jiǎn)單總結(jié)了:


image

類似 Deployment 這樣的一個(gè)控制器,實(shí)際上都是由上半部分的控制器定義(包括期望狀態(tài))芭商,加上下半部分的被控制對(duì)象的模板組成的派草。

這就是為什么,在所有 API 對(duì)象的 Metadata 里铛楣,都有一個(gè)字段叫作 ownerReference近迁,用于保存當(dāng)前這個(gè) API 對(duì)象的擁有者(Owner)的信息。

實(shí)際上簸州,跟 Deployment 相似鉴竭,這些控制循環(huán)最后的執(zhí)行結(jié)果歧譬,要么就是創(chuàng)建、更新一些 Pod(或者其他的 API 對(duì)象搏存、資源)缴罗,要么就是刪除一些已經(jīng)存在的 Pod(或者其他的 API 對(duì)象、資源)祭埂。

但也正是在這個(gè)統(tǒng)一的編排框架下面氓,不同的控制器可以在具體執(zhí)行過(guò)程中,設(shè)計(jì)不同的業(yè)務(wù)邏輯蛆橡,從而達(dá)到不同的編排效果舌界。這個(gè)實(shí)現(xiàn)思路,正是 Kubernetes 項(xiàng)目進(jìn)行容器編排的核心原理泰演。

deployment會(huì)創(chuàng)建rs(ReplicaSet),然后由rs創(chuàng)建pod,所以pod的owner應(yīng)該是rs

經(jīng)典 PaaS 的記憶之作業(yè)副本與水平擴(kuò)展呻拌。

Deployment:
實(shí)現(xiàn)了 Kubernetes 項(xiàng)目中一個(gè)非常重要的功能:Pod 的“水平擴(kuò)展 / 收縮”(horizontal scaling out/in)
如果你更新了 Deployment 的 Pod 模板(比如,修改了容器的鏡像)睦焕,那么 Deployment 就需要遵循一種叫作“滾動(dòng)更新”(rolling update)的方式藐握,來(lái)升級(jí)現(xiàn)有的容器。

而這個(gè)能力的實(shí)現(xiàn)垃喊,依賴的是 Kubernetes 項(xiàng)目中的一個(gè)非常重要的概念(API 對(duì)象):ReplicaSet猾普。

ReplicaSet(副本) 的結(jié)構(gòu)非常簡(jiǎn)單,我們可以通過(guò)這個(gè) YAML 文件查看一下:

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: nginx-set
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9

一個(gè) ReplicaSet 對(duì)象本谜,其實(shí)就是由副本數(shù)目的定義和一個(gè) Pod 模板組成的初家。不難發(fā)現(xiàn),它的定義其實(shí)是 Deployment 的一個(gè)子集乌助。

溜在,Deployment 控制器實(shí)際操縱的,正是這樣的 ReplicaSet 對(duì)象他托,而不是 Pod 對(duì)象掖肋。

分析一個(gè)如下所示的 Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

這是一個(gè)常用的 nginx-deployment,它定義的 Pod 副本個(gè)數(shù)是 3(spec.replicas=3)赏参。

在具體的實(shí)現(xiàn)上咆瘟,這個(gè) Deployment戏仓,與 ReplicaSet喜命,以及 Pod 的關(guān)系是:


image

是一種“層層控制”的關(guān)系爱葵。其中,ReplicaSet 負(fù)責(zé)通過(guò)“控制器模式”纸俭,保證系統(tǒng)中 Pod 的個(gè)數(shù)永遠(yuǎn)等于指定的個(gè)數(shù)(比如皇耗,3 個(gè))。這也正是 Deployment 只允許容器的 restartPolicy=Always 的主要原因:只有在容器能保證自己始終是 Running 狀態(tài)的前提下揍很,ReplicaSet 調(diào)整 Pod 的個(gè)數(shù)才有意義郎楼。

而在此基礎(chǔ)上万伤,Deployment 同樣通過(guò)“控制器模式”,來(lái)操作 ReplicaSet 的個(gè)數(shù)和屬性呜袁,進(jìn)而實(shí)現(xiàn)“水平擴(kuò)展 / 收縮”和“滾動(dòng)更新”這兩個(gè)編排動(dòng)作敌买。

其中,“水平擴(kuò)展 / 收縮”非常容易實(shí)現(xiàn)阶界,Deployment Controller 只需要修改它所控制的 ReplicaSet 的 Pod 副本個(gè)數(shù)就可以了虹钮。

比如,把這個(gè)值從 3 改成 4膘融,那么 Deployment 所對(duì)應(yīng)的 ReplicaSet芙粱,就會(huì)根據(jù)修改后的值自動(dòng)創(chuàng)建一個(gè)新的 Pod。這就是“水平擴(kuò)展”了氧映;“水平收縮”則反之春畔。

而用戶想要執(zhí)行這個(gè)操作的指令也非常簡(jiǎn)單,就是 kubectl scale岛都,比如:

$ kubectl scale deployment nginx-deployment --replicas=4
deployment.apps/nginx-deployment scaled

“滾動(dòng)更新”

創(chuàng)建這個(gè) nginx-deployment:

$ kubectl create -f nginx-deployment.yaml --record

–record 參數(shù)律姨。它的作用,是記錄下你每次操作所執(zhí)行的命令臼疫,以方便后面查看择份。

檢查一下 nginx-deployment 創(chuàng)建后的狀態(tài)信息:

$ kubectl get deployments
NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3         0         0            0           1s

在返回結(jié)果中,我們可以看到四個(gè)狀態(tài)字段

  • DESIRED:用戶期望的 Pod 副本個(gè)數(shù)(spec.replicas 的值)多矮;

  • CURRENT:當(dāng)前處于 Running 狀態(tài)的 Pod 的個(gè)數(shù)缓淹;

  • UP-TO-DATE:當(dāng)前處于最新版本的 Pod 的個(gè)數(shù),所謂最新版本指的是 Pod 的 Spec 部分與 Deployment 里 Pod 模板里定義的完全一致塔逃;

  • AVAILABLE:當(dāng)前已經(jīng)可用的 Pod 的個(gè)數(shù),即:既是 Running 狀態(tài)料仗,又是最新版本湾盗,并且已經(jīng)處于 Ready(健康檢查正確)狀態(tài)的 Pod 的個(gè)數(shù)。

只有這個(gè) AVAILABLE 字段立轧,描述的才是用戶所期望的最終狀態(tài).

實(shí)時(shí)查看 Deployment 對(duì)象的狀態(tài)變化格粪。這個(gè)指令就是 kubectl rollout status:

$ kubectl rollout status deployment/nginx-deployment
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
deployment.apps/nginx-deployment successfully rolled out

2 out of 3 new replicas have been updated”意味著已經(jīng)有 2 個(gè) Pod 進(jìn)入了 UP-TO-DATE 狀態(tài)。

等待:

NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3         3         3            3           20s

看一下這個(gè) Deployment 所控制的 ReplicaSet

$ kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-3167673210   3         3         3       20s

這個(gè) ReplicaSet 的名字氛改,則是由 Deployment 的名字和一個(gè)隨機(jī)字符串共同組成帐萎。
這個(gè)隨機(jī)字符串叫作 pod-template-hash,在我們這個(gè)例子里就是:3167673210胜卤。ReplicaSet 會(huì)把這個(gè)隨機(jī)字符串加在它所控制的所有 Pod 的標(biāo)簽里疆导,從而保證這些 Pod 不會(huì)與集群里的其他 Pod 混淆。

而 ReplicaSet 的 DESIRED葛躏、CURRENT 和 READY 字段的含義澈段,和 Deployment 中是一致的悠菜。

相比之下,Deployment 只是在 ReplicaSet 的基礎(chǔ)上败富,添加了 UP-TO-DATE 這個(gè)跟版本有關(guān)的狀態(tài)字段悔醋。

這個(gè)時(shí)候,如果我們修改了 Deployment 的 Pod 模板兽叮,“滾動(dòng)更新”就會(huì)被自動(dòng)觸發(fā).

修改 Deployment 有很多方法芬骄。比如,我可以直接使用 kubectl edit 指令編輯 Etcd 里的 API 對(duì)象鹦聪。

$ kubectl edit deployment/nginx-deployment
... 
    spec:
      containers:
      - name: nginx
        image: nginx:1.9.1 # 1.7.9 -> 1.9.1 (將 nginx 鏡像的版本升級(jí)到了 1.9.1德玫。)
        ports:
        - containerPort: 80
...
deployment.extensions/nginx-deployment edited

kubectl edit 不過(guò)是把 API 對(duì)象的內(nèi)容下載到了本地文件,讓你修改完成后再提交上去椎麦。

kubectl edit 指令編輯完成后宰僧,保存退出,Kubernetes 就會(huì)立刻觸發(fā)“滾動(dòng)更新”的過(guò)程观挎。你還可以通過(guò) kubectl rollout status 指令查看 nginx-deployment 的狀態(tài)變化.

可以通過(guò)查看 Deployment 的 Events琴儿,看到這個(gè)“滾動(dòng)更新”的流程:

$ kubectl describe deployment nginx-deployment
...
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
...
  Normal  ScalingReplicaSet  24s   deployment-controller  Scaled up replica set nginx-deployment-1764197365 to 1
  Normal  ScalingReplicaSet  22s   deployment-controller  Scaled down replica set nginx-deployment-3167673210 to 2
  Normal  ScalingReplicaSet  22s   deployment-controller  Scaled up replica set nginx-deployment-1764197365 to 2
  Normal  ScalingReplicaSet  19s   deployment-controller  Scaled down replica set nginx-deployment-3167673210 to 1
  Normal  ScalingReplicaSet  19s   deployment-controller  Scaled up replica set nginx-deployment-1764197365 to 3
  Normal  ScalingReplicaSet  14s   deployment-controller  Scaled down replica set nginx-deployment-3167673210 to 0

修改了 Deployment 里的 Pod 定義之后,Deployment Controller 會(huì)使用這個(gè)修改后的 Pod 模板嘁捷,創(chuàng)建一個(gè)新的 ReplicaSet(hash=1764197365)造成,這個(gè)新的 ReplicaSet 的初始 Pod 副本數(shù)是:0。

在 Age=22 s 的位置雄嚣,Deployment Controller 又將舊的 ReplicaSet(hash=3167673210)所控制的舊 Pod 副本數(shù)減少一個(gè)晒屎,即:“水平收縮”成兩個(gè)副本。

在 Age=24 s 的位置缓升,Deployment Controller 開(kāi)始將這個(gè)新的 ReplicaSet 所控制的 Pod 副本數(shù)從 0 個(gè)變成 1 個(gè)鼓鲁,即:“水平擴(kuò)展”出一個(gè)副本。

如此交替進(jìn)行港谊,新 ReplicaSet 管理的 Pod 副本數(shù)骇吭,從 0 個(gè)變成 1 個(gè),再變成 2 個(gè)歧寺,最后變成 3 個(gè)燥狰。而舊的 ReplicaSet 管理的 Pod 副本數(shù)則從 3 個(gè)變成 2 個(gè),再變成 1 個(gè)斜筐,最后變成 0 個(gè)龙致。這樣,就完成了這一組 Pod 的版本升級(jí)過(guò)程顷链。

像這樣目代,將一個(gè)集群中正在運(yùn)行的多個(gè) Pod 版本,交替地逐一升級(jí)的過(guò)程,就是“滾動(dòng)更新”像啼。

在這個(gè)“滾動(dòng)更新”過(guò)程完成之后俘闯,你可以查看一下新、舊兩個(gè) ReplicaSet 的最終狀態(tài):

$ kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-1764197365   3         3         3       6s
nginx-deployment-3167673210   0         0         0       30s

其中忽冻,舊 ReplicaSet(hash=3167673210)已經(jīng)被“水平收縮”成了 0 個(gè)副本真朗。

一定要使用 Pod 的 Health Check 機(jī)制檢查應(yīng)用的運(yùn)行狀態(tài),而不是簡(jiǎn)單地依賴于容器的 Running 狀態(tài)僧诚。要不然的話遮婶,雖然容器已經(jīng)變成 Running 了,但服務(wù)很有可能尚未啟動(dòng)湖笨,“滾動(dòng)更新”的效果也就達(dá)不到了旗扑。

而為了進(jìn)一步保證服務(wù)的連續(xù)性,Deployment Controller 還會(huì)確保慈省,在任何時(shí)間窗口內(nèi)臀防,只有指定比例的 Pod 處于離線狀態(tài)。同時(shí)边败,它也會(huì)確保袱衷,在任何時(shí)間窗口內(nèi),只有指定比例的新 Pod 被創(chuàng)建出來(lái)笑窜。這兩個(gè)比例的值都是可以配置的致燥,默認(rèn)都是 DESIRED 值的 25%。

它有 3 個(gè) Pod 副本排截,那么控制器在“滾動(dòng)更新”的過(guò)程中永遠(yuǎn)都會(huì)確保至少有 2 個(gè) Pod 處于可用狀態(tài)嫌蚤,至多只有 4 個(gè) Pod 同時(shí)存在于集群中。這個(gè)策略断傲,是 Deployment 對(duì)象的一個(gè)字段脱吱,名叫 RollingUpdateStrategy,如下所示:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
...
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  • maxSurge 指定的是除了 DESIRED 數(shù)量之外艳悔,在一次“滾動(dòng)”中急凰,Deployment 控制器還可以創(chuàng)建多少個(gè)新 Pod;

  • maxUnavailable 指的是猜年,在一次“滾動(dòng)”中,Deployment 控制器可以刪除多少個(gè)舊 Pod疾忍。

兩個(gè)配置還可以用前面我們介紹的百分比形式來(lái)表示乔外,比如:maxUnavailable=50%,指的是我們最多可以一次刪除“50%*DESIRED 數(shù)量”個(gè) Pod一罩。

image

如上所示杨幼,Deployment 的控制器,實(shí)際上控制的是 ReplicaSet 的數(shù)目,以及每個(gè) ReplicaSet 的屬性差购。

而一個(gè)應(yīng)用的版本四瘫,對(duì)應(yīng)的正是一個(gè) ReplicaSet;這個(gè)版本應(yīng)用的 Pod 數(shù)量欲逃,則由 ReplicaSet 通過(guò)它自己的控制器(ReplicaSet Controller)來(lái)保證找蜜。

通過(guò)這樣的多個(gè) ReplicaSet 對(duì)象,Kubernetes 項(xiàng)目就實(shí)現(xiàn)了對(duì)多個(gè)“應(yīng)用版本”的描述.

Deployment 對(duì)應(yīng)用進(jìn)行版本控制的具體原理

使用 kubectl set image 的指令稳析,直接修改 nginx-deployment 所使用的鏡像洗做。這個(gè)命令的好處就是,你可以不用像 kubectl edit 那樣需要打開(kāi)編輯器彰居。

$ kubectl set image deployment/nginx-deployment nginx=nginx:1.91
deployment.extensions/nginx-deployment image updated

這個(gè) nginx:1.91 鏡像在 Docker Hub 中并不存在诚纸,所以這個(gè) Deployment 的“滾動(dòng)更新”被觸發(fā)后,會(huì)立刻報(bào)錯(cuò)并停止陈惰。

檢查一下 ReplicaSet 的狀態(tài):

$ kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-1764197365   2         2         2       24s
nginx-deployment-3167673210   0         0         0       35s
nginx-deployment-2156724341   2         2         0       7s

它已經(jīng)創(chuàng)建了兩個(gè) Pod畦徘,但是它們都沒(méi)有進(jìn)入 READY 狀態(tài)。這當(dāng)然是因?yàn)檫@兩個(gè) Pod 都拉取不到有效的鏡像抬闯。

舊版本的 ReplicaSet(hash=1764197365)的“水平收縮”井辆,也自動(dòng)停止了。此時(shí)画髓,已經(jīng)有一個(gè)舊 Pod 被刪除掘剪,還剩下兩個(gè)舊 Pod。

如何讓這個(gè) Deployment 的 3 個(gè) Pod奈虾,都回滾到以前的舊版本呢夺谁?

執(zhí)行一條 kubectl rollout undo 命令,就能把整個(gè) Deployment 回滾到上一個(gè)版本.

$ kubectl rollout undo deployment/nginx-deployment
deployment.extensions/nginx-deployment

在具體操作上肉微,Deployment 的控制器匾鸥,其實(shí)就是讓這個(gè)舊 ReplicaSet(hash=1764197365)再次“擴(kuò)展”成 3 個(gè) Pod,而讓新的 ReplicaSet(hash=2156724341)重新“收縮”到 0 個(gè) Pod碉纳。

我想回滾到更早之前的版本:
使用 kubectl rollout history 命令勿负,查看每次 Deployment 變更對(duì)應(yīng)的版本。而由于我們?cè)趧?chuàng)建這個(gè) Deployment 的時(shí)候劳曹,指定了–record 參數(shù)奴愉,所以我們創(chuàng)建這些版本時(shí)執(zhí)行的 kubectl 命令,都會(huì)被記錄下來(lái)

$ kubectl rollout history deployment/nginx-deployment
deployments "nginx-deployment"
REVISION    CHANGE-CAUSE
1           kubectl create -f nginx-deployment.yaml --record
2           kubectl edit deployment/nginx-deployment
3           kubectl set image deployment/nginx-deployment nginx=nginx:1.91

還可以通過(guò)這個(gè) kubectl rollout history 指令铁孵,看到每個(gè)版本對(duì)應(yīng)的 Deployment 的 API 對(duì)象的細(xì)節(jié):

kubectl rollout history deployment/nginx-deployment --revision=2

回滾到的指定版本的版本號(hào)锭硼,就可以回滾到指定版本了:

$ kubectl rollout undo deployment/nginx-deployment --to-revision=2
deployment.extensions/nginx-deployment

Deployment Controller 還會(huì)按照“滾動(dòng)更新”的方式,完成對(duì) Deployment 的降級(jí)操作蜕劝。

我們對(duì) Deployment 進(jìn)行的每一次更新操作檀头,都會(huì)生成一個(gè)新的 ReplicaSet 對(duì)象轰异,是有些多余,甚至浪費(fèi)資源.

所以暑始,搭独,在更新 Deployment 前 執(zhí)行 kubectl rollout pause 指令,使得我們對(duì) Deployment 的多次更新操作廊镜,最后 只生成一個(gè) ReplicaSet牙肝。

$ kubectl rollout pause deployment/nginx-deployment
deployment.extensions/nginx-deployment paused

作用,是讓這個(gè) Deployment 進(jìn)入了一個(gè)“暫推谏”狀態(tài).

所以我們對(duì) Deployment 的所有修改惊奇,都不會(huì)觸發(fā)新的“滾動(dòng)更新”,也不會(huì)創(chuàng)建新的 ReplicaSet播赁。

修改操作都完成之后颂郎,只需要再執(zhí)行一條 kubectl rollout resume 指令,就可以把這個(gè) Deployment“恢復(fù)”回來(lái).

$ kubectl rollout resume deploy/nginx-deployment
deployment.extensions/nginx-deployment resumed

而在這個(gè) kubectl rollout resume 指令執(zhí)行之前容为,在 kubectl rollout pause 指令之后的這段時(shí)間里乓序,我們對(duì) Deployment 進(jìn)行的所有修改,最后只會(huì)觸發(fā)一次“滾動(dòng)更新”.

可以通過(guò)檢查 ReplicaSet 狀態(tài)的變化坎背,來(lái)驗(yàn)證一下 kubectl rollout pause 和 kubectl rollout resume 指令的執(zhí)行效果

$ kubectl get rs
NAME               DESIRED   CURRENT   READY     AGE
nginx-1764197365   0         0         0         2m
nginx-3196763511   3         3         3         28s

只有一個(gè) hash=3196763511 的 ReplicaSet 被創(chuàng)建了出來(lái)替劈。

即使你像上面這樣小心翼翼地控制了 ReplicaSet 的生成數(shù)量,隨著應(yīng)用版本的不斷增加得滤,Kubernetes 中還是會(huì)為同一個(gè) Deployment 保存很多很多不同的 ReplicaSet陨献。

為了控制這些“歷史”ReplicaSet 的數(shù)量,Deployment 對(duì)象有一個(gè)字段懂更,叫作 spec.revisionHistoryLimit眨业,就是 Kubernetes 為 Deployment 保留的“歷史版本”個(gè)數(shù)。所以沮协,如果把它設(shè)置為 0龄捡,你就再也不能做回滾操作了。

Deployment 實(shí)際上是一個(gè)兩層控制器慷暂。首先聘殖,它通過(guò) ReplicaSet 的個(gè)數(shù)來(lái)描述應(yīng)用的版本;然后行瑞,它再通過(guò) ReplicaSet 的屬性(比如 replicas 的值)奸腺,來(lái)保證 Pod 的副本數(shù)量.

Deployment 控制 ReplicaSet(版本),ReplicaSet 控制 Pod(副本數(shù))

Kubernetes 項(xiàng)目對(duì) Deployment 的設(shè)計(jì)血久,實(shí)際上是代替我們完成了對(duì)“應(yīng)用”的抽象洋机,使得我們可以使用這個(gè) Deployment 對(duì)象來(lái)描述應(yīng)用,使用 kubectl rollout 命令控制應(yīng)用的版本洋魂。

應(yīng)用可能有會(huì)話黏連(session sticky),這就意味著“滾動(dòng)更新”的時(shí)候,哪個(gè) Pod 能下線副砍,是不能隨便選擇的衔肢。這種場(chǎng)景,光靠 Deployment 自己就很難應(yīng)對(duì)了豁翎。對(duì)于這種需求角骤,“自定義控制器”就可以幫我們實(shí)現(xiàn)一個(gè)功能更加強(qiáng)大的 Deployment Controller。

補(bǔ)充:
金絲雀部署:優(yōu)先發(fā)布一臺(tái)或少量機(jī)器升級(jí)心剥,等驗(yàn)證無(wú)誤后再更新其他機(jī)器邦尊。優(yōu)點(diǎn)是用戶影響范圍小,不足之處是要額外控制如何做自動(dòng)更新优烧。
藍(lán)綠部署:2組機(jī)器蝉揍,藍(lán)代表當(dāng)前的V1版本,綠代表已經(jīng)升級(jí)完成的V2版本畦娄。通過(guò)LB將流量全部導(dǎo)入V2完成升級(jí)部署又沾。優(yōu)點(diǎn)是切換快速,缺點(diǎn)是影響全部用戶熙卡。
本文學(xué)習(xí)的滾動(dòng)更新杖刷,我覺(jué)得就是一個(gè)自動(dòng)化更新的金絲雀發(fā)布。

備注: 摘自極客時(shí)間 學(xué)習(xí)筆記

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末驳癌,一起剝皮案震驚了整個(gè)濱河市滑燃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌颓鲜,老刑警劉巖表窘,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異灾杰,居然都是意外死亡蚊丐,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門艳吠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)麦备,“玉大人,你說(shuō)我怎么就攤上這事昭娩×莞荩” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵栏渺,是天一觀的道長(zhǎng)呛梆。 經(jīng)常有香客問(wèn)我,道長(zhǎng)磕诊,這世上最難降的妖魔是什么填物? 我笑而不...
    開(kāi)封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任纹腌,我火速辦了婚禮,結(jié)果婚禮上滞磺,老公的妹妹穿的比我還像新娘升薯。我一直安慰自己,他們只是感情好击困,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布涎劈。 她就那樣靜靜地躺著,像睡著了一般阅茶。 火紅的嫁衣襯著肌膚如雪蛛枚。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天脸哀,我揣著相機(jī)與錄音蹦浦,去河邊找鬼。 笑死企蹭,一個(gè)胖子當(dāng)著我的面吹牛白筹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播谅摄,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼徒河,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了送漠?” 一聲冷哼從身側(cè)響起顽照,我...
    開(kāi)封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎闽寡,沒(méi)想到半個(gè)月后代兵,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡爷狈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年植影,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涎永。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡思币,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出羡微,到底是詐尸還是另有隱情谷饿,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布妈倔,位于F島的核電站博投,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏盯蝴。R本人自食惡果不足惜毅哗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一听怕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧黎做,春花似錦叉跛、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)鸣峭。三九已至宏所,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間摊溶,已是汗流浹背爬骤。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留莫换,地道東北人霞玄。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像拉岁,于是被迫代替她去往敵國(guó)和親坷剧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353