概述#
三兄弟的最後一位是 Deployment。它為 Pod 與 ReplicaSet 提供宣告式 API(Declarative API)的設定方式,讓使用者只需描述「期望的容器執行狀態」,Kubernetes(K8s)就會持續比對並調整實際狀態。官方建議透過 Deployment 部署 Pod 與 ReplicaSet,而不要單獨使用後兩者。
Deployment 的典型使用情境:
- 建立 Pod 與 ReplicaSet。
- 滾動升級與回滾。
- 水平擴展與縮減。
- 暫停與繼續部署。
ReplicaSet 是什麼#
ReplicaSet 負責保證指定的 Pod 數量符合使用者期望(desired state)。當實際 Pod 數量少於期望時,它會建立新的 Pod;多於期望時則會刪除多餘的 Pod。
雖然 ReplicaSet 已經能完成這件事,但它的能力相對單純。Deployment 是更上層的抽象,內部會自動建立並管理 ReplicaSet,並額外提供更新策略、版本歷史等功能。三者的關係大致是:
Deployment → 管理多個 ReplicaSet → 各自管理一群 Pod實戰演練#
1. 建立 Deployment#
下列檔案宣告兩個 Deployment,分別管理 foo 與 bar 各一份 Pod:
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo-deployment
labels:
type: demo
spec:
replicas: 1
selector:
matchLabels:
type: demo
template:
metadata:
labels:
type: demo
spec:
containers:
- name: foo
image: mikehsu0618/foo
ports:
- containerPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: bar-deployment
labels:
type: demo
spec:
replicas: 1
selector:
matchLabels:
type: demo
template:
metadata:
labels:
type: demo
spec:
containers:
- name: bar
image: mikehsu0618/bar
ports:
- containerPort: 8080關鍵欄位說明:
- kind:選擇為
Deployment。 - spec.replicas:要產生多少個 Pod,是水平擴展的關鍵。
- spec.selector.matchLabels:用來選擇受此 Deployment 管理的 Pod,必須與
template.metadata.labels相同。 - spec.template:Pod 範本,內容與直接撰寫 Pod 設定幾乎一致。
套用設定:
kubectl apply -f ./deployment.yaml確認結果:
kubectl get all可以看到 Deployment、ReplicaSet、Pod 三者都被建立起來,Pod 名稱會帶有 ReplicaSet 的雜湊後綴,例如 foo-deployment-6bbf665b47-kfvxr。
2. 水平擴展 Deployment#
有三種常見方式調整 Pod 副本數:
方法一:修改 YAML 後重新 apply
把 foo-deployment 的 spec.replicas 改為 2,再執行:
kubectl apply -f ./deployment.yaml --record接著用以下指令觀察 rollout 是否完成:
kubectl rollout status deployment foo-deployment方法二:使用 scale 指令
kubectl scale deployment bar-deployment --replicas 3方法三:直接編輯執行中的設定
kubectl edit deploy bar-deployment執行後會打開預設編輯器,可即時修改設定。
完成後再次用 kubectl get all 觀察,會看到對應的 Pod 數量被調整,ReplicaSet 與 Deployment 的 READY、AVAILABLE 欄位也會跟著更新。
3. 用 Rollout 查看歷史與回滾#
更新 Deployment 時,Kubernetes 會在符合條件下產生新的 Revision(部署歷史版本)。
並非每次更新都會產生 Revision,僅當 Deployment 第一次建立、或是
spec.template範圍下的設定改變時才會記錄。例如只調整replicas並不會產生新的 Revision。
下面把 bar-deployment 的容器映像故意指向一個不存在的 tag mikehsu0618/bar:v1,模擬一次失敗的更新:
apiVersion: apps/v1
kind: Deployment
metadata:
name: bar-deployment
labels:
type: demo
spec:
replicas: 3
selector:
matchLabels:
type: demo
template:
metadata:
labels:
type: demo
spec:
containers:
- name: bar
image: mikehsu0618/bar:v1
ports:
- containerPort: 8080套用變更並記錄指令:
kubectl apply -f deployment.yaml --record
--record會在 Annotation 中存下實際執行的 kubectl 指令,便於日後在 rollout history 中查找變更原因。雖然--record已標示為將被棄用,但官方目前尚未提供等效的替代方案,仍是常見作法。
查看歷史版本:
kubectl rollout history deployment bar-deployment範例輸出:
REVISION CHANGE-CAUSE
1 <none>
2 kubectl apply --filename=deployment.yaml --record=true進一步檢視某個 Revision 的細節:
kubectl rollout history deployment bar-deployment --revision=2由於 tag 不存在,Pod 會卡在 ImagePullBackOff 狀態:
kubectl get all此時可以使用 rollout 回滾到先前能正常運作的版本:
# 回滾到上一個版本
kubectl rollout undo deployment bar-deployment --record
# 回滾到指定版本
kubectl rollout undo deployment bar-deployment --to-revision=1 --record回滾完成後,再次執行 kubectl get all,可以看到失敗的 ReplicaSet 副本數歸零,原本正常的 ReplicaSet 重新承擔流量。
小結#
Deployment 把 Pod 的生命週期管理變成「描述期望狀態」這件事,使用者不必親自處理擴展、升級、回滾的細節。透過 ReplicaSet 與 Revision 機制,藍綠部署、金絲雀部署等進階策略也能在這個基礎上實現。理解三兄弟的分工後,後續面對 Ingress、Volume、Autoscaling 等主題會更有脈絡可依。
原文出處#
- GitHub:https://github.com/MikeHsu0618/2022-ithelp/tree/main/Day8
- iThome:https://ithelp.ithome.com.tw/articles/10288602