滾動升級/回滾,在 k8s 中算是很方便的功能。你可以利用滾動升級正在運作的系統且不需要停機!另外,如果新的部署有發生問題的時候,透過回滾機制,你也可以簡單把系統回復。在 Day 10 - 建構組件 我們曾經提到過 Deployment 這個物件裡面會包含了 ReplicaSet,然後再透過 ReplicaSet 來掌管 Pod 運行數。而 k8s 中回滾機制 (Rolling Update / Back),就是透過 ReplicasSet 來達到。如下圖,每次的更新都會產生新的 ReplicaSet 來管控 Pod,你也可以把它想成產生一個新版本。而回滾則是把現有版本切換到上一個或指定的版本。
首先,我們先部署 Day 10 - 建構組件 用到過的 simple.yaml
到 k8s 中
# kubectl apply -f simple.yaml
deployment "nginx" created
$ kubectl get replicaset
NAME DESIRED CURRENT READY AGE
nginx-969897d56 3 3 0 26s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-969897d56-dkfdk 1/1 Running 0 1m
nginx-969897d56-mj7z9 1/1 Running 0 1m
nginx-969897d56-r4bx5 1/1 Running 0 1m
<=== 其實看字首就能分辨是由哪個 ReplicaSet 管控
$ kubectl describe po nginx-969897d56-mj7z9 | grep ReplicaSet
Created By: ReplicaSet/nginx-969897d56
Controlled By: ReplicaSet/nginx-969897d56
當部署個 Deployment 時,同時會產生一個 ReplicaSet (即 nginx-969897d56
),然後再透過這個 ReplicaSet 在產生三個 Pod (即 Created By: ReplicaSet/nginx-969897d56
)。
底下是滾動升級的相關設定
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
minReadySeconds: 5
minReadySeconds
:有容器建立後需要一些時間啟動服務,這時候就可以設置這個參數。k8s 會等待設定的時間後再進行升級。如果沒有設定,則 k8s 會在容器一啟動後就直接進行升級服務。maxSurge
:1 表示當一個新 Pod 被建立後才會刪除一個舊 Pod,2 表示在更新過程最多會多兩個 Pod 被建立以此類推。maxUnavailable
:表示在升級過程中,最多可以有幾個 Pod 無法服務。請注意,當 maxSurge
不為 0
的時候,maxUnavailable
也不能為 0
底下是完整的 yaml
# simple.rolling.yaml
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 5 <=== 這裡我們將數量從 3 增加為 5 個
strategy: <=== 從這裡是 Rolling Update 的設定
type: RollingUpdate
rollingUpdate:
maxSurge: 1 <=== 表示升級過程最多會有 6 個 Pod
maxUnavailable: 1 <=== 最多允許一個 Pod 不能服務
minReadySeconds: 5 <=== 容器啟動後 5 秒再開始進行升級
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.10.2 <=== 這裡指定更新後的容器
ports:
- containerPort: 80
如果要進行滾動升級 (Rolling Update)
$ kubectl apply -f simple.rolling.yaml --record
--record
參數通知 k8s 把指令記錄起來以方便之後檢查你可以透過
$ kubectl rollout history deployment [name]
來查看,[name]
請記得換成 Deployment 的名稱。
當你下達指令後,你會發現有新的 ReplicaSet 被產生,然後 Pod 也會發生變化
$ kubectl get replicaset
NAME DESIRED CURRENT READY AGE
nginx-5bffddbbdb 2 2 0 25s <=== 新建立的
nginx-969897d56 4 4 3 19m <=== 原本的
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-5bffddbbdb-bbt9c 1/1 Running 0 21s
nginx-5bffddbbdb-fg6dg 1/1 Running 0 1m
nginx-5bffddbbdb-jwlvj 1/1 Running 0 1m
nginx-5bffddbbdb-pv6zj 1/1 Running 0 15s
nginx-5bffddbbdb-qt6v6 0/1 ContainerCreating 0 10s
nginx-969897d56-dkfdk 0/1 Terminating 0 20m
nginx-969897d56-mj7z9 0/1 Terminating 0 20m
nginx-969897d56-r4bx5 1/1 Running 0 20m
nginx-969897d56-xt6wr 0/1 Terminating 0 1m
從 Pod 的字首應該就能分辨出是哪個 ReplicaSet 建立的 Pod,上面就可以看到舊的 ReplicaSet nginx-969897d56
管控的 Pod 正在被刪除中,而新建立的 ReplicaSet nginx-5bffddbbdb
則是根據 simple.rolling.yaml
所指定的內容正在建立 Pod。
你可以透過指令觀察一下更新的紀錄
$ kubectl rollout history deployment nginx
deployments "nginx"
REVISION CHANGE-CAUSE
1 <none>
2 kubectl apply --filename=simple.rolling.yaml --record=true
CHANGE-CAUSE
就會把你當時下達的命令記錄下來。不過要使用上面的指令,你必須要在每次下達更新的時候帶上 --record
的參數,不然你可能會看到
$ kubectl rollout history deployment nginx
deployments "nginx"
REVISION CHANGE-CAUSE
1 <none>
2 <none>
這樣是不是比較不清楚發生什麼事情,只知道有 1
跟 2
兩個版本。
另外,你還可以透過指令更新映像檔
$ kubectl set image deployment [name] [container]=[image] --record
<=== 例如將 nginx 更新為 1.11.1 版
$ kubectl set image deployment nginx nginx=nginx:1.11.1 --record
deployment "nginx" image updated
<=== 再次查看就會發現多了一筆紀錄
$ kubectl rollout history deployment nginx
deployments "nginx"
REVISION CHANGE-CAUSE
1 <none>
2 kubectl apply --filename=simple.rolling.yaml --record=true
3 kubectl set image deployment nginx nginx=nginx:1.11.1 --record=true
當更新後發現系統有問題時,可以利用回滾功能把系統回復。你可以
$ kubectl rollout undo deployment [name]
$ kubectl rollout undo deployment [name] --to-revision=[version]
底下舉個例子,剛剛我們有更新過一次,如果要回到版本 1,我們可以利用下面指令
$ kubectl rollout undo deployment nginx --to-revision=1
deployment "nginx" rolled back
$ kubectl get replicaset
NAME DESIRED CURRENT READY AGE
nginx-5bffddbbdb 1 1 1 12m
nginx-969897d56 5 5 4 31m
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-5bffddbbdb-bbt9c 0/1 Terminating 0 11m
nginx-5bffddbbdb-fg6dg 0/1 Terminating 0 12m
nginx-5bffddbbdb-jwlvj 1/1 Running 0 12m
nginx-5bffddbbdb-pv6zj 0/1 Terminating 0 11m
nginx-969897d56-4cn5g 0/1 ContainerCreating 0 14s
nginx-969897d56-7jtj4 1/1 Running 0 37s
nginx-969897d56-jr2kq 1/1 Running 0 26s
nginx-969897d56-sbn4m 1/1 Running 0 37s
nginx-969897d56-ttg28 1/1 Running 0 19s
下達更新回滾後,你就會發現 ReplicaSet 與 Pod 又會開始發生變化,原本的 nginx-969897d56
又會開始建立 Pod,而 nginx-5bffddbbdb
管控的 Pod 則會被刪除。
本文與部署檔案同步發表於 https://jlptf.github.io/ironman2018-day18/
你好,
圖片中看起來一個 replica set 下有多個 pods
但我看了些文章,都說這兩者的個數相同
還是說我有些甚麼誤解?