Kubernetes 教學系列 - 滾動更新就用 Deployment
上次介紹了如何使用 Replica Set 如何對 Pods 來進行管理,但其實官方並不推薦直接使用 Replica Set 來對 Pods 操作,更推薦可以使用 Deployment 來直接操作 Pods,可以理解當我們建造 Deployment 資源後會自動一併建立好 Replica Set 及 Pods,所以我們可以透過 Deployment 直接進行管理。
Deployment 的作用
- 透過創建 Deployment 來建立 Replica Set,Replica Set 又可以幫助管理 Pods
- 滾動更新 Deployment 版本,例如,如果當前的 Deployment 上線的 Pod 需要更新新上線的 code 版本,可以做到 zero downtime deployment
- 也可以 rollback 到先前版本,如果新版本的 code 上線造成不穩定或 bug 的情況。
Deployment 設定檔撰寫
直接上設定檔:
1 | apiVersion: apps/v1 |
- kind 為
Deployment
- spec 這邊定義的 selector 是代表要讓 Deployment 知道如何查找藥管理的 Pods,所以定義的 labels 應該要跟下面的 template 的 labels 一致才行。而這邊也可以用 Replica Set 複雜的 label 比對,例如使用
matchExpressions
。 - template 這邊就是描述 Pod 的相關的定義
先幫 Application Image 打上 Version
在我們 create Deployment 前,我們需要先將 web-app image 打上 Version Tag,這樣等等才方便示範滾動更新或回退的操作。
將之前只有 latest 版本打 tag 為 v1 版本:
1 | docker tag kennychenfight/web-app:latest kennychenfight/we |
之後 push 到 Docker Hub 上:
1 | docker push kennychenfight/web-app:v1 |
建立 Deployment 資源
接著就可以來建立 Deployment 資源:
1 | kubectl create -f deployment.yaml |
取得 Deployment 相關資源
1 | kubectl get deploy |
1 | kubectl get rs |
1 | kubectl get pods |
當建立完之後就會自動建立 Deployment、Replica Set、Pods 這些資源,根據以上的指令就可以知道 Name 都是以 Deployment Metadat 的 name 為 Prefix。
如何滾動更新
滾動更新有好多種指令可以達成。我們先將目前的 web-app 版本 tag 打上 v2 版本再來做示範。
1 | docker tag kennychenfight/web-app:latest kennychenfigh |
1 | docker push kennychenfight/web-app:v2 |
更新 Yaml 檔案
1 | apiVersion: apps/v1 |
這邊很簡單就將 image 的 tag 更改為 v2
即可。
透過 apply 指令來更新設定:
1 | kubectl apply -f deployment-update.yaml |
接著趕快用 kubectl get pods
來看看:
1 | kubectl get pods |
可以發現 Deployment 會幫我們將 Pods 做 Zero Down Time 更新,會一個一個將舊版本的 Pod 停掉,同時也會起一個新版本的 Pod 來運行,避免有服務完全停機而無法服務的情況。
透過 rollout status
指令可以知道目前升級的狀態:
1 | kubectl rollout status deploy web-app-deployment |
使用 set Image 指令
也可以透過 set Image
指令來做 Pod Image 的更新:
1 | kubectl set image deploy/web-app-deployment web-app=kennychenfight/web-app:v2 |
使用 edit 指令
透過 edit deploy
指令可以做 yaml 檔案欄位的更新,此外也會多許多欄位可以做更改:
1 | kubectl edit deploy web-app-deployment |
這邊除了直接更改 image 的版本之外,還有幾個欄位是關於滾動更新的:
1 | sepc: |
- maxSurge 可以用百分比也可以用數字設定,這是代表在滾動更新的時候新版本的 Pod 可以比原本 Deployment 定義的 Replicas 多幾個 Pod 出來
- maxUnavailable 則是在滾動更新的時候可以容忍多少 Pod 無法使用
查看 Deployment Rollout 的紀錄
1 | kubectl rollout history deploy web-app-deployment |
透過這個指令可以看到有兩次的歷史紀錄的 rollout,第一次是建立 Deployment 的時候,第二次是我們進行滾動更新的時候。而 CHANGE-CAUSE 怎麼設置的呢?可以透過以下三種方式:
kubectl annotate deployment.v1.apps/web-app-deployment kubernetes.io/change-cause="image updated to xxx"
- 追加
--record
指令來保存正在更改資源的 kubectl 指令
可以來看個示範:
第一種方式可以直接修改當前 Deployment 資源的 CHANGE-CAUSE 紀錄,因此我們設定如下:
1 | kubectl annotate deployment.v1.apps/web-app-deployment kubernetes.io/change-cause="image updated to version2" |
再來看是否有改變:
1 | kubectl rollout history deploy web-app-deployment |
這邊可以看出有改變了。
而第二種方式的意思是類似這樣:
1 | kubectl set image deploy/web-app-deployment web-app-pod=kennychenfight/web-app:v2 --record=true |
或是
1 | kubectl apply -f deployment-update.yaml --record=true |
這樣的話會自動將更新 Deployment 資源的指令紀錄上去。
如何回滾回退
撤銷當前上線版本,回滾到上一個版本:
1 | kubectl rollout undo deploy web-app-deployment |
透過 rollout undo 指令即可
透過使用 --to-revision
來回滾到特定版本:
1 | kubectl rollout undo deploy web-app-deployment --to-revision=1 |
接著透過 rollout history 指令就會發現又多了一個 REVISION:
1 | kubectl rollout history deploy web-app-deployment |
這邊會發現會將回滾版本 1 踢掉變成新的版本 3
暫停跟恢復 Deployment
如果說我們要對 Deployment 做很多設定的調整,那另外一種方式是可以選擇先將 Deployment 暫停,這個暫停是指原本的 Deployment 出來 Pods 仍然可以運作,但是我們對 Deployment 的更新會保留著,並且當我們解除暫停之後,Deployment 才會做更新的動作。
以避免當如果不小心更改到甚麼之後,就馬上進行上線的動作,可能會產生多餘的上線操作。
暫停 Deployment
1 | kubectl rollout pause deploy/web-app-deployment |
版本上到第二個版本
1 | kubectl set image deploy/web-app-deployment web-app-pod=kennychenfight/web-app:v2 --record=true |
這時來看一下 rollout status:
1 | kubectl rollout status deploy web-app-deployment |
可以看到還沒進行更新。必須 resume deployment 才會更新。
恢復 Deployment
1 | kubectl rollout resume deploy/web-app-deployment |
這時候恢復後,再看看 Pods:
1 | kubectl get pods |
可以看到在進行更新了~
再來看 status:
1 | kubectl rollout status deploy web-app-deployment |
成功 rolled out 了~
總結
這篇文章主要介紹了如何建立 Deployment 資源,以及常用的操作,例如如何滾動更新跟回退,這對於上線新版本是很好用的。下一篇文章會來介紹如何透過外部服務來跟 Pods 來進行連線溝通,也就是 Service 資源的建立。