Kubernetes 滾動更新及回滾

當集群中的某個服務需要升級時,我們需要停止目前與該服務相關的所有Pod,然後重新拉取鏡像並啟動。如果集群規模比較大,則這個工作就變成了一個挑戰,而且先全部停止然後逐步升級的方式會導致長時間的服務不可用。Kubernetes提供了rolling-update滾動升級功能來解決上述問題

滾動升級通過執行kubectl rolling-update命令一鍵完成,該命令創建了一個新的RC,然後自動控制舊的RC中的Pod副本數量逐漸減少到0,同時新的RC中的Pod副本的數量從0逐步增加到目標值,最終實現了Pod的升級。系統會要求新的RC和舊的RC在相同的命名空間下

Kubernetes 滾動更新及回滾

image_1dnmokndp1bokahk12k2of66nfp.png-116.5kB

創建演示文件

cat >>abcdocker-test.yaml <apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.13.0-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
EOF

創建

[root@abcdocker ~]# kubectl apply -f abcdocker-test.yaml --record

已運行的Pod副本數量有3個

[root@abcdocker ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-859fff59fb-488zc 1/1 Running 0 75s
nginx-deployment-859fff59fb-b8vwq 1/1 Running 0 75s
nginx-deployment-859fff59fb-mzbwt 1/1 Running 0 75s

Kubernetes 更新

更新實際上就是替換鏡像版本,有以下幾種方式進行更新

① 修改deployment文件進行更新

sed -i 's#1.13.0-alpine#1.10.0-alpine#g' abcdocker-test.yaml
kubectl apply -f abcdocker-test.yaml --record
Kubernetes 滾動更新及回滾

image_1dnnj163ptqm1r24113p12bb1e6q16.png-107.4kB

我們可以看到pod執行過程是等待新的pod啟動完成,在進行銷燬舊的pod,這樣就完成了集群的更新工作

--record的作用是將當前命令記錄到 revision 記錄中,這樣我們就可以知道每個 revison 對應的是哪個配置文件。

② 直接修改deployment進行更新鏡像
deployment文件支持動態更新,我們使用edit參數可以直接更新deployment文件

[root@abcdocker ~]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 14m
[root@abcdocker ~]# kubectl edit deployments nginx-deployment
deployment.extensions/nginx-deployment edited

#再次查看pod的時候已經被更新
[root@abcdocker ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-5fc7b9784f-dq56f 0/1 Pending 0 1s
nginx-deployment-5fc7b9784f-r6v9w 1/1 Running 0 45s
nginx-deployment-66c45bd65-4f8zn 1/1 Terminating 0 6m47s
nginx-deployment-66c45bd65-64zsl 1/1 Running 0 7m22s
nginx-deployment-66c45bd65-ktjcd 1/1 Running 0 6m56s

不太推薦使用edit進行編輯,退出即保存,同時也會在我們的rollout裡面產生一個版本號

③ 接下來是使用kubectl set命令進行替換鏡像


命令格式如下

kubectl set image deployment/SVC_NAME -n namespace_name container_name=images:v1

#注意後面是容器名稱,並不是svc名稱

本次環境演示

[root@abcdocker ~]# kubectl set image deployment/nginx-deployment nginx=nginx:1.10.1
deployment.extensions/nginx-deployment image updated

回滾

我們使用上面的更新應用時Kubernetes都會記錄下當前的配置文件,保存為一個revision (版本),這樣就可以通過這個版本回滾到特定的時間

我們可以通過rollout參數查看當前版本號

#查看revison歷史記錄
[root@abcdocker ~]# kubectl rollout history deployment nginx-deployment

deployment.extensions/nginx-deployment
REVISION CHANGE-CAUSE
1 kubectl apply --filename=abcdocker-test.yaml --record=true
2 kubectl apply --filename=abcdocker-test.yaml --record=true
3 kubectl apply --filename=abcdocker-test.yaml --record=true
4 kubectl apply --filename=abcdocker-test.yaml --record=true

#nginx-deployment為deployment名稱,可以通過kubectl get deployment查看到

我們可以通過kubectl rollout undo 將deployment回滾到指定的版本,這裡模擬回滾到第一個版本

默認情況下,如果不加--to-revision=版本號,默認回退到上一個版本

[root@yzsjhl82-135 tmp]# kubectl rollout undo deployment nginx-deployment --to-revision=1
deployment.extensions/nginx-deployment rolled back
[root@yzsjhl82-135 tmp]#
[root@yzsjhl82-135 tmp]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-589c48ccfb-c74dk 1/1 Running 0 5m36s
nginx-deployment-589c48ccfb-r6nmr 1/1 Running 0 7m7s
nginx-deployment-589c48ccfb-wl8x9 1/1 Running 0 6m17s
nginx-deployment-859fff59fb-cswks 0/1 ContainerCreating 0 4s

如果我們使用kubectl apply -f xx.yaml不加任何參數,那麼在rollout將不會記錄任何描述

Kubernetes 滾動更新及回滾

image_1dnnkcqrapv4fu71rgm1abd1n2l1j.png-120.5kB

如果我們想讓rollout裡面記錄的文件帶有版本號,只需要將文件修改一個名稱更新時加上--record參數就可以,下面就會顯示版本號

[root@abcdocker ~]# cp abcdocker-test.yaml abcdocker-v1.yaml
[root@abcdocker ~]# kubectl apply -f abcdocker-v1.yaml --record
deployment.apps/nginx-deployment configured
[root@abcdocker ~]# kubectl rollout history deployment nginx-deployment

deployment.extensions/nginx-deployment
REVISION CHANGE-CAUSE
3 kubectl apply --filename=abcdocker-test.yaml --record=true
4 kubectl apply --filename=abcdocker-test.yaml --record=true
5 kubectl apply --filename=abcdocker-test.yaml --record=true
6 kubectl apply --filename=abcdocker-test.yaml --record=true
7 kubectl apply --filename=abcdocker-v1.yaml --record=true

rollout命令參數如下

[root@yzsjhl82-135 tmp]# kubectl rollout -h
Manage the rollout of a resource.

Valid resource types include: #支持的資源格式

* deployments
* daemonsets
* statefulsets

Examples:
# Rollback to the previous deployment
kubectl rollout undo deployment/abc

# Check the rollout status of a daemonset
kubectl rollout status daemonset/foo

Available Commands:
history 顯示 rollout 歷史
pause 標記提供的 resource 為中止狀態
resume 繼續一個停止的 resource
status 顯示 rollout 的狀態

undo 撤銷上一次的 rollout

參數使用格式kubectl rollout [XXXX] deployment nginx-deployment

默認配置下,Kubernetes 只會保留最近的幾個 revision,可以在 Deployment 配置文件中通過 revisionHistoryLimit 屬性增加 revision 數量。

revisionHistoryLimit(歷史版本記錄):
Deployment revision history存儲在它控制的ReplicaSets中。默認保存記錄5個  

  .spec.revisionHistoryLimit 是一個可選配置項,用來指定可以保留的舊的ReplicaSet數量。該理想值取決於心Deployment的頻率和穩定性。如果該值沒有設置的話,默認所有舊的Replicaset或會被保留,將資源存儲在etcd中,是用kubectl get rs查看輸出。每個Deployment的該配置都保存在ReplicaSet中,然而,一旦刪除的舊的RepelicaSet,Deployment就無法再回退到那個revison了。

  如果將該值設置為0,所有具有0個replica的ReplicaSet都會被刪除。在這種情況下,新的Deployment rollout無法撤銷,因為revision history都被清理掉了。

PS:為了保存版本升級的歷史,需要再創建Deployment對象時,在命令中使用"--record"選項

一般配合revisionHistoryLimit使用的strategy (更新策略)

strategy(更新策略):
  .spec.strategy 指定新的Pod替換舊的Pod的策略。 .spec.strategy.type 可以是"Recreate"或者是 "RollingUpdate"。"RollingUpdate"是默認值。


  Recreate: 重建式更新,就是刪一個建一個。類似於ReplicaSet的更新方式,即首先刪除現有的Pod對象,然後由控制器基於新模板重新創建新版本資源對象。

  rollingUpdate:滾動更新,簡單定義 更新期間pod最多有幾個等。可以指定maxUnavailable 和 maxSurge 來控制 rolling update 進程。

  maxSurge:.spec.strategy.rollingUpdate.maxSurge 是可選配置項,用來指定可以超過期望的Pod數量的最大個數。該值可以是一個絕對值(例如5)或者是期望的Pod數量的百分比(例如10%)。當MaxUnavailable為0時該值不可以為0。通過百分比計算的絕對值向上取整。默認值是1。

  例如,該值設置成30%,啟動rolling update後新的ReplicatSet將會立即擴容,新老Pod的總數不能超過期望的Pod數量的130%。舊的Pod被殺掉後,新的ReplicaSet將繼續擴容,舊的ReplicaSet會進一步縮容,確保在升級的所有時刻所有的Pod數量和不會超過期望Pod數量的130%。

  maxUnavailable:.spec.strategy.rollingUpdate.maxUnavailable 是可選配置項,用來指定在升級過程中不可用Pod的最大數量。該值可以是一個絕對值(例如5),也可以是期望Pod數量的百分比(例如10%)。通過計算百分比的絕對值向下取整。 如果.spec.strategy.rollingUpdate.maxSurge 為0時,這個值不可以為0。默認值是1。

  例如,該值設置成30%,啟動rolling update後舊的ReplicatSet將會立即縮容到期望的Pod數量的70%。新的Pod ready後,隨著新的ReplicaSet的擴容,舊的ReplicaSet會進一步縮容確保在升級的所有時刻可以用的Pod數量至少是期望Pod數量的70%。


PS:maxSurge和maxUnavailable的屬性值不可同時為0,否則Pod對象的副本數量在符合用戶期望的數量後無法做出合理變動以進行更新操作。

  在配置時,用戶還可以使用Deployment控制器的spec.minReadySeconds屬性來控制應用升級的速度。新舊更替過程中,新創建的Pod對象一旦成功響應就緒探測即被認為是可用狀態,然後進行下一輪的替換。而spec.minReadySeconds能夠定義在新的Pod對象創建後至少需要等待多長的時間才能會被認為其就緒,在該段時間內,更新操作會被阻塞。

這裡我提供revisionHistoryLimit和rollingUpdate的yaml文件 (完整yaml如下)

[root@abcdocker ~]# cat abcdocker-test.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
revisionHistoryLimit: 10
selector:
matchLabels:
app: nginx
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.13.0

imagePullPolicy: IfNotPresent
ports:
- containerPort: 80

具體參數可以查看上面解釋!


分享到:


相關文章: