Kubernetes工作負(fù)載資源之Deployment

創(chuàng)建Deployment
Deployment是一種更高階的工作負(fù)載資源。其可以視作為對(duì)RS的再一次升級(jí)。其不僅可以部署應(yīng)用還可以通過(guò)聲明的方式升級(jí)應(yīng)用。具體地,Deployment被創(chuàng)建后,其內(nèi)部先創(chuàng)建相應(yīng)的RS資源。再利用該RS資源創(chuàng)建相應(yīng)的Pod。下面即是一個(gè)創(chuàng)建Deployment資源的示例
# 創(chuàng)建Deployment資源
apiVersion: apps/v1
# 資源類(lèi)型
kind: Deployment
metadata:
# Deployment名稱(chēng)
name: my-kubia-deployment
spec:
# Pod副本數(shù)量
replicas: 3
# 標(biāo)簽選擇器
selector:
matchLabels:
app: my-kubia-app
# Pod模板
template:
metadata:
# 標(biāo)簽信息
labels:
app: my-kubia-app
spec:
# 容器信息
containers:
- name: my-kubia
image: luksa/kubia:v1
# 僅用于展示容器所使用的端口
ports:
- containerPort: 8080
protocol: TCP
---
# 創(chuàng)建Service資源
# API組、版本
apiVersion: v1
# 資源類(lèi)型
kind: Service
metadata:
# 資源名稱(chēng)
name: my-kubia-svc
spec:
# Service類(lèi)型
type: NodePort
selector:
app: my-kubia-app
ports:
- port: 80 # 服務(wù)監(jiān)聽(tīng)端口
targetPort: 8080 # 服務(wù)將請(qǐng)求轉(zhuǎn)發(fā)到Pod的目標(biāo)端口
# 在集群各節(jié)點(diǎn)所打開(kāi)的端口, 使得可以通過(guò)集群中任一節(jié)點(diǎn)IP、nodePort端口號(hào)訪問(wèn)該服務(wù)
nodePort: 30123
---
# 創(chuàng)建一個(gè)Pod用于訪問(wèn)、測(cè)試Service提供的服務(wù)
apiVersion: v1
kind: Pod
metadata:
name: my-bootcamp-pod
spec:
containers:
- name: my-bootcamp
image: jocatalin/kubernetes-bootcamp:v1
ports:
- containerPort: 8080
protocol: TCP
效果如下所示。可以看到該Deployment會(huì)自行創(chuàng)建一個(gè)RS資源。同時(shí)再由該RS資源創(chuàng)建相應(yīng)的Pod。同時(shí)這些Pod的名稱(chēng)前綴和RS名稱(chēng)完全一樣。然后還可以通過(guò)Service進(jìn)行訪問(wèn)

特別地,對(duì)于Deployment而言,還可以通過(guò)下述命令查看部署狀態(tài)
# 查看指定名稱(chēng)的Deployment的部署結(jié)果
kubectl rollout status deployment <Deployment的名稱(chēng)>
# 查看名為my-kubia-deployment的Deployment的部署結(jié)果
kubectl rollout status deployment my-kubia-deployment
效果如下所示

應(yīng)用升級(jí)
創(chuàng)建應(yīng)用的V1版本
現(xiàn)在來(lái)演示下如何利用Deployment升級(jí)應(yīng)用,先創(chuàng)建一個(gè)應(yīng)用的V1版本
apiVersion: apps/v1
# 資源類(lèi)型
kind: Deployment
metadata:
# Deployment名稱(chēng)
name: my-kubia-deployment-2
spec:
# Pod副本數(shù)量
replicas: 3
# Pod就緒后需要等待多長(zhǎng)時(shí)間, 才會(huì)將該P(yáng)od視為可用
minReadySeconds: 10
# 升級(jí)策略
strategy:
# 默認(rèn)策略類(lèi)型為滾動(dòng)升級(jí)
type: RollingUpdate
# 控制滾動(dòng)升級(jí)速率
rollingUpdate:
# 升級(jí)期間, 相對(duì)于Deployment中指定的Pod期望副本數(shù)而言, 允許多出的Pod數(shù)量
maxSurge: 1
# 升級(jí)期間, 相對(duì)于Deployment中指定的Pod期望副本數(shù)而言, 允許有多少個(gè)Pod處于不可用狀態(tài)
# 例如: 當(dāng)replicas=3、maxUnavailable=1, 則此時(shí)要求可用的Pod數(shù)量至少為 replicas - maxUnavailable = 3-1 = 2
maxUnavailable: 0
# 標(biāo)簽選擇器
selector:
matchLabels:
app: my-kubia-app-2
# Pod模板
template:
metadata:
# 標(biāo)簽信息
labels:
app: my-kubia-app-2
spec:
# 容器信息
containers:
- name: my-kubia-2
image: luksa/kubia:v1
# 僅用于展示容器所使用的端口
ports:
- containerPort: 8080
protocol: TCP
# 就緒探針
readinessProbe:
periodSeconds: 1
httpGet:
path: /
port: 8080
---
# 創(chuàng)建Service資源
# API組、版本
apiVersion: v1
# 資源類(lèi)型
kind: Service
metadata:
# 資源名稱(chēng)
name: my-kubia-svc-2
spec:
# Service類(lèi)型
type: NodePort
selector:
app: my-kubia-app-2
ports:
- port: 80 # 服務(wù)監(jiān)聽(tīng)端口
targetPort: 8080 # 服務(wù)將請(qǐng)求轉(zhuǎn)發(fā)到Pod的目標(biāo)端口
# 在集群各節(jié)點(diǎn)所打開(kāi)的端口, 使得可以通過(guò)集群中任一節(jié)點(diǎn)IP、nodePort端口號(hào)訪問(wèn)該服務(wù)
nodePort: 30123
---
# 創(chuàng)建一個(gè)Pod用于訪問(wèn)、測(cè)試Service提供的服務(wù)
apiVersion: v1
kind: Pod
metadata:
name: my-bootcamp-pod-2
spec:
containers:
- name: my-bootcamp
image: jocatalin/kubernetes-bootcamp:v1
ports:
- containerPort: 8080
protocol: TCP
效果如下所示

在Deployment升級(jí)應(yīng)用時(shí),支持兩種策略
「RollingUpdate」:其是Deployment的默認(rèn)升級(jí)策略。其會(huì)漸進(jìn)的刪除舊版本的Pod,與此同時(shí)創(chuàng)建新版本的Pod。這樣應(yīng)用在整個(gè)升級(jí)過(guò)程中都處于可用的狀態(tài),即通過(guò)舊版本、新版本的Pod同時(shí)對(duì)外提供服務(wù) 「Recreate」:該策略下,其會(huì)一次性刪除所有舊版本的Pod。再創(chuàng)建新版本的Pod。這樣應(yīng)用在整個(gè)升級(jí)過(guò)程中會(huì)有短暫的時(shí)間不可用。如果應(yīng)用不支持同時(shí)使用多個(gè)不同版本對(duì)外提供服務(wù),則可以選擇該策略
應(yīng)用升級(jí)
對(duì)于Deployment升級(jí)應(yīng)用來(lái)說(shuō),非常簡(jiǎn)單。只需設(shè)置該Deployment中容器的新鏡像信息即可
# 對(duì)于指定名稱(chēng)的Deployment,設(shè)置其中指定名稱(chēng)容器的鏡像信息
kubectl set image deployment <Deployment的名稱(chēng)> <容器的名稱(chēng)>=<鏡像名稱(chēng)>:<鏡像版本>
# 對(duì)于名為my-kubia-deployment-2的Deployment,設(shè)置名為my-kubia-2容器的鏡像為luksa/kubia:v2
kubectl set image deployment my-kubia-deployment-2 my-kubia-2=luksa/kubia:v2
與此同時(shí),通過(guò)my-bootcamp-pod-2這個(gè)Pod來(lái)訪問(wèn)my-kubia-svc-2服務(wù),命令如下所示
# 進(jìn)入名為my-bootcamp-pod-2的Pod
kubectl exec my-bootcamp-pod-2 -it -- bash
# 不停的訪問(wèn)my-kubia-svc-2的Service
while true; do curl 10.96.247.140:80 ; done
效果如下所示,右側(cè)顯示在RollingUpdate策略下V2版本的新Pod不斷被創(chuàng)建,與此同時(shí)V1版本的舊Pod逐漸被刪除

當(dāng)升級(jí)完成后,可以看到Deployment實(shí)際上是先創(chuàng)建了一個(gè)新RS。然后對(duì)新RS不斷擴(kuò)容、對(duì)舊RS不斷縮容。而且舊RS實(shí)際上依然保留在其中并未刪除

此外每次利用kubectl edit、kubectl apply命令修改、應(yīng)用Deployment中Pod模板相關(guān)字段值時(shí),同樣也會(huì)自動(dòng)觸發(fā)升級(jí)更新。為此可先通過(guò)kubectl rollout pause命令暫停該Deployment的升級(jí)更新,在完成所有對(duì)Deployment的更改后,再通過(guò)kubectl rollout resume命令恢復(fù)該Deployment的升級(jí)更新。對(duì)于回滾操作而言,不可以對(duì)處于暫停狀態(tài)的Deployment執(zhí)行 kubectl rollout undo命令,需要先恢復(fù)再回滾
# 暫停指定Deployment的升級(jí)更新
kubectl rollout pause deployment <Deployment的名稱(chēng)>
# 恢復(fù)指定Deployment的升級(jí)更新
kubectl rollout resume deployment <Deployment的名稱(chēng)>
應(yīng)用回滾
對(duì)于Deployment回滾應(yīng)用也很簡(jiǎn)單,可以先通過(guò)下述命令查看某Deployment的滾動(dòng)升級(jí)歷史
# 查看指定名稱(chēng)的Deployment的滾動(dòng)升級(jí)歷史
kubectl rollout history deployment <Deployment的名稱(chēng)>
# 查看名為my-kubia-deployment-2的Deployment的滾動(dòng)升級(jí)歷史
kubectl rollout history deployment my-kubia-deployment-2
然后通過(guò)指定版本號(hào)查看該版本的具體信息
# 查看指定名稱(chēng)Deployment的指定版本的信息
kubectl rollout history deployment <Deployment的名稱(chēng)> --revision=<版本號(hào)>
# 查看名為my-kubia-deployment-2的Deployment的版本號(hào)為1的信息
kubectl rollout history deployment my-kubia-deployment-2 --revision=1
效果如下所示

故如果我們想將應(yīng)用回滾到V1版本,只需使用kubectl rollout undo子命令即可。如果使用--to-revision選項(xiàng)指定版本號(hào)則會(huì)回滾到指定版本,如果不使用--to-revision選項(xiàng)則會(huì)直接回滾到上一個(gè)版本
# 將指定名稱(chēng)的Deployment回滾到上一個(gè)版本
kubectl rollout undo deployment <Deployment的名稱(chēng)>
# 將指定名稱(chēng)的Deployment回滾到指定版本
kubectl rollout undo deployment <Deployment的名稱(chēng)> --to-revision=<版本號(hào)>
# 將名為 my-kubia-deployment-2的Deployment 回滾到1號(hào)版本
kubectl rollout undo deployment my-kubia-deployment-2 --to-revision=1
效果如下所示。通過(guò)curl命令的結(jié)果不難看出Deployment已經(jīng)回滾到V1版本了。由于此前升級(jí)后V1版本所對(duì)應(yīng)的舊RS并沒(méi)有被刪除。所以可以直接利用舊RS進(jìn)行回滾。而一旦將舊RS刪除掉,就無(wú)法進(jìn)行回滾了

控制升級(jí)速率
在RollingUpdate策略下,可以通過(guò)maxSurge、maxUnavailable參數(shù)控制滾動(dòng)升級(jí)的速率。具體地:
「maxSurge參數(shù)」
升級(jí)期間, 相對(duì)于Deployment中指定的Pod期望副本數(shù)而言, 允許多出的Pod數(shù)量。同時(shí)該值可以是絕對(duì)數(shù)字也可以是一個(gè)百分比。例如: 當(dāng)Deployment中指定的Pod期望副本數(shù)replicas為4時(shí),如果maxSurge值為2,則表明不會(huì)運(yùn)行超過(guò)4+2=6個(gè)Pod實(shí)例;如果maxSurge值為25%,則表明不會(huì)運(yùn)行超過(guò)4+4*25% = 4+1 =5 個(gè)Pod實(shí)例
「maxUnavailable參數(shù)」
升級(jí)期間, 相對(duì)于Deployment中指定的Pod期望副本數(shù)而言, 允許有多少個(gè)Pod處于不可用狀態(tài)。同時(shí)該值可以是絕對(duì)數(shù)字也可以是一個(gè)百分比。當(dāng)Deployment中指定的Pod期望副本數(shù)replicas為4時(shí),如果maxUnavailable值為1。則表明此時(shí)要求可用的Pod數(shù)量至少為 replicas - maxUnavailable = 4-1 = 3個(gè);如果maxUnavailable值為50%。則表明此時(shí)要求可用的Pod數(shù)量至少為 replicas - maxUnavailable = 4-4*50% = 4-2 =2個(gè)。換言之,該參數(shù)不是限制不可用Pod的數(shù)量,而是通過(guò)replicas值計(jì)算出可用Pod的最少數(shù)量
此外,還可以使用minReadySeconds參數(shù)來(lái)避免升級(jí)缺陷版本的應(yīng)用時(shí),造成大范圍的影響。在RollingUpdate滾動(dòng)升級(jí)策略條件下,可以實(shí)現(xiàn)自動(dòng)阻止升級(jí)過(guò)程。具體地:
「minReadySeconds參數(shù)」
該參數(shù)指定Pod就緒后需要等待多少秒, 才會(huì)將該P(yáng)od視為可用。由于maxUnavailable參數(shù)的存在,會(huì)導(dǎo)致Pod可用之前,滾動(dòng)升級(jí)過(guò)程不會(huì)再繼續(xù)。minReadySeconds參數(shù)通過(guò)搭配就緒探針共同使用,可以實(shí)現(xiàn)將只有少量Pod升級(jí)到缺陷版本。由于滾動(dòng)升級(jí)過(guò)程自動(dòng)被阻止,故可以避免將所有Pod全部升級(jí)到缺陷版本。默認(rèn)值為0意為Pod一旦就緒后,會(huì)立即將該P(yáng)od視為可用狀態(tài)
在之前的Deployment中我們定義minReadySeconds參數(shù)為10秒,同時(shí)還定義了一個(gè)就緒探針?,F(xiàn)在我們將應(yīng)用升級(jí)到V3版本,該版本有一個(gè)缺陷。即其只能正確處理前四個(gè)請(qǐng)求,后續(xù)所有HTTP請(qǐng)求都將會(huì)失敗。效果如下所示,可以看到由于V3版本的Pod處于未就緒,自然其也是不可用的狀態(tài)?,F(xiàn)在滾動(dòng)升級(jí)已經(jīng)被自動(dòng)阻止了,避免了更大范圍的影響。我們只需將Deployment回滾到歷史版本即可

參考文獻(xiàn)
Kubernetes in Action中文版 Marko Luksa著 深入剖析Kubernetes 張磊著
