編排其實(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é)了:
類似 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)系是:
是一種“層層控制”的關(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一罩。
如上所示杨幼,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í)筆記