概述Deployment 基礎建立 DeploymentReplicaSet滾動更新失敗回滾歷史版本回滾其他特性小結
概述
Deployment 是最常用的 Kubernetes 原生 Workload 資源之一,我們一開始嘗試使用 Kubernetes 的時候大概率就是從執行一個 Deployment 型別的工作負載開始的。今天開始我們計劃分成幾講來從 Deployment 的特性介紹、原始碼分析等方面深度剖析 Deployment 資源和其背後的 Deployment 控制器。
Deployment 的基礎特性大家基本都熟悉,所以本文我們不計劃贅述 Deployment 的所有功能細節,而是從滾動更新等不算太基礎的特性入手,看下 Deployment 支援哪些玩法,為後面分析原始碼做準備。
Deployment 基礎
我們建立一個簡單的 Deployment,然後看下一些小細節。
建立 Deployment
以執行 nginx 為例,我們可以通過 Deployment 來拉起一個 3 副本的 nginx 負載:nginx-dp
- nginx-dp.yaml
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4 name: nginx-dp
5 labels:
6 app: nginx
7spec:
8 replicas: 3
9 selector:
10 matchLabels:
11 app: nginx
12 template:
13 metadata:
14 labels:
15 app: nginx
16 spec:
17 containers:
18 - name: nginx
19 image: nginx:1.14.2
20 ports:
21 - containerPort: 80
通過 kubectl create -f nginx-dp.yaml
我們可以建立這個 Deployment 資源。
1# kubectl create -f nginx-dp.yaml
2deployment.apps/nginx-dp created
3# kubectl get deploy
4NAME READY UP-TO-DATE AVAILABLE AGE
5nginx-dp 1/3 3 1 3s
6# kubectl get deploy
7NAME READY UP-TO-DATE AVAILABLE AGE
8nginx-dp 3/3 3 3 10s
等一會,就可以通過 kubectl get deploy
命令看到所有 Pod 都起來了,這裡關注下輸出欄位含義(NAME 和 AGE 就不用說了):
- UP-TO-DATE:多少副本已經更新到期望狀態了
- AVAILABLE:多少副本已經可以提供服務了
- READY:可以提供服務的副本數/期望副本數
ReplicaSet
- 查詢 ReplicaSet
1# kubectl get rs --selector=app=nginx
2NAME DESIRED CURRENT READY AGE
3nginx-dp-66b6c48dd5 3 3 3 9m54s
前面建立了 Deployment 之後可以看到叢集裡多了一個 ReplicaSet 資源,也就是說 Deployment 管理的其實是 ReplicaSet 而不是直接管理 Pod,我們繼續看下這個 ReplicaSet 的定義來驗證下這個想法:
1# kubectl get rs nginx-dp-66b6c48dd5 -o yaml
2apiVersion: apps/v1
3kind: ReplicaSet
4// ……
5 ownerReferences:
6 - apiVersion: apps/v1
7 blockOwnerDeletion: true
8 controller: true
9 kind: Deployment
10 name: nginx-dp
11 uid: 97736b65-0171-4916-bb18-feccc343ac14
12 resourceVersion: "1099157"
13 uid: 83ac5660-28eb-4d40-beb1-cb5ceb6928b6
14// ……
這裡可以看到這個 ReplicaSet 屬於 Deployment 型別的 nginx-dp 資源。同樣的方法可以看到對應 Pod 是屬於 ReplicaSet 管理的。
到這裡,我們可以猜下 Deployment Controller 的實現原理,大概可以想到其通過管理 ReplicaSet 的生命週期,藉助 ReplicaSet Controller 提供的能力間接完成了 Pod 生命週期的管理;另外可以通過建立多個 ReplicaSet 資源,控制其副本數來實現滾動更新和回滾等操作。這樣 Deployment Controller 的實現邏輯就相對“高層”了。
滾動更新
- 通過
kubectl set
命令來更新映象:
1# kubectl set image deployment/nginx-dp nginx=nginx:1.16.1
2deployment.apps/nginx-dp image updated
- 檢視 Event
1# kubectl describe deploy nginx-dp
2// ……
3
4Events:
5 Type Reason Age From Message
6 ---- ------ ---- ---- -------
7 Normal ScalingReplicaSet 26m deployment-controller Scaled up replica set nginx-dp-66b6c48dd5 to 3
8 Normal ScalingReplicaSet 88s deployment-controller Scaled up replica set nginx-dp-559d658b74 to 1
9 Normal ScalingReplicaSet 87s deployment-controller Scaled down replica set nginx-dp-66b6c48dd5 to 2
10 Normal ScalingReplicaSet 87s deployment-controller Scaled up replica set nginx-dp-559d658b74 to 2
11 Normal ScalingReplicaSet 86s deployment-controller Scaled down replica set nginx-dp-66b6c48dd5 to 1
12 Normal ScalingReplicaSet 86s deployment-controller Scaled up replica set nginx-dp-559d658b74 to 3
13 Normal ScalingReplicaSet 84s deployment-controller Scaled down replica set nginx-dp-66b6c48dd5 to 0
從 Event 裡可以看到 deployment-controller 通過調整 ReplicaSet 資源 nginx-dp-66b6c48dd5 和 nginx-dp-559d658b74 的副本數完成了這次滾動更新,先看下這兩個 ReplicaSet:
1# kubectl get rs --selector=app=nginx
2NAME DESIRED CURRENT READY AGE
3nginx-dp-559d658b74 3 3 3 134m
4nginx-dp-66b6c48dd5 0 0 0 159m
可以看到這時候新增了一個 nginx-dp-559d658b74,副本數是 3,同時老的 nginx-dp-66b6c48dd5 變成了 0 副本。這個過程大概是這樣:
- nginx-dp-66b6c48dd5 to 3 / replica set nginx-dp-559d658b74 to 1 -> 新 rs 增加一個副本到 1;合計 4 副本
- Scaled down replica set nginx-dp-66b6c48dd5 to 2 -> 老 rs 減少一個副本到 2;合計 3 副本
- Scaled up replica set nginx-dp-559d658b74 to 2 -> 新 rs 增加一個副本到 2;合計 4 副本
- Scaled down replica set nginx-dp-66b6c48dd5 to 1 -> 老 rs 減少一個副本到 1;合計 3 副本
- Scaled up replica set nginx-dp-559d658b74 to 3 -> 新 rs 增加一個副本到 3;合計 4 副本
- Scaled down replica set nginx-dp-66b6c48dd5 to 0 -> 老 rs 減少一個副本到 0;合計 3 副本
失敗回滾
歷史版本
先看下怎麼查詢更新歷史:
1# kubectl rollout history deployments/nginx-dp
2deployment.apps/nginx-dp
3REVISION CHANGE-CAUSE
41 <none>
52 <none>
這裡可以看到一個細節,CHANGE-CAUSE 是空的,這個欄位其實是從 kubernetes.io/change-cause 註解中拿的,我們加個註解試一下:
1kubectl annotate deployment/nginx-dp kubernetes.io/change-cause="image updated to 1.16.1"
再查一次:
1# kubectl rollout history deployments/nginx-dp
2deployment.apps/nginx-dp
3REVISION CHANGE-CAUSE
41 <none>
52 image updated to 1.16.1
第一個版本怎麼辦呢?這裡大概可以猜到要儲存多個版本的 CHANGE-CAUSE 資訊,這個註解應該是用的 ReplicaSet 裡的,所以我們嘗試這樣補充第一個版本的註解:
1kubectl annotate rs/nginx-dp-66b6c48dd5 kubernetes.io/change-cause="nginx deployment created"
再查一次:
1# kubectl rollout history deployments/nginx-dp
2deployment.apps/nginx-dp
3REVISION CHANGE-CAUSE
41 nginx deployment created
52 image updated to 1.16.1
現在就比較和諧了,需要指定版本回滾的時候不迷路。
回滾
- 設定一個不存在的映象版本來模擬更新失敗場景:
1# kubectl set image deployment/nginx-dp nginx=nginx:1.161
2deployment.apps/nginx-dp image updated
3# kubectl get rs --selector=app=nginx
4NAME DESIRED CURRENT READY AGE
5nginx-dp-559d658b74 3 3 3 168m
6nginx-dp-66b6c48dd5 0 0 0 3h13m
7nginx-dp-66bc5d6c8 1 1 0 6s
8# kubectl get pod --selector=app=nginx
9NAME READY STATUS RESTARTS AGE
10nginx-dp-559d658b74-l4bq7 1/1 Running 0 170m
11nginx-dp-559d658b74-qhh8m 1/1 Running 0 170m
12nginx-dp-559d658b74-vbtl5 1/1 Running 0 170m
13nginx-dp-66bc5d6c8-tl848 0/1 ImagePullBackOff 0 2m2s
- 設定個註解:
1# kubectl annotate deployment/nginx-dp kubernetes.io/change-cause="image updated to 1.161"
2deployment.apps/nginx-dp annotated
3# kubectl rollout history deployments/nginx-dp
4deployment.apps/nginx-dp
5REVISION CHANGE-CAUSE
61 nginx deployment created
72 image updated to 1.16.1
83 image updated to 1.161
- 回滾到 revision 2:
1# kubectl rollout undo deployment/nginx-dp
2deployment.apps/nginx-dp rolled back
3# kubectl rollout history deployments/nginx-dp
4deployment.apps/nginx-dp
5REVISION CHANGE-CAUSE
61 nginx deployment created
73 image updated to 1.161
84 image updated to 1.16.1
這時候版本 2 變成了最新的版本:4
- 檢視某個版本的詳細配置:
1# kubectl rollout history deployments/nginx-dp --revision=1
2deployment.apps/nginx-dp with revision #1
3Pod Template:
4 Labels: app=nginx
5 pod-template-hash=66b6c48dd5
6 Annotations: kubernetes.io/change-cause: nginx deployment created
7 Containers:
8 nginx:
9 Image: nginx:1.14.2
10 Port: 80/TCP
11 Host Port: 0/TCP
12 Environment: <none>
13 Mounts: <none>
14 Volumes: <none>
- 指定版本回滾:
1# kubectl rollout undo deployment/nginx-dp --to-revision=1
2deployment.apps/nginx-dp rolled back
3# kubectl rollout history deployments/nginx-dp
4deployment.apps/nginx-dp
5REVISION CHANGE-CAUSE
63 image updated to 1.161
74 image updated to 1.16.1
85 nginx deployment created
其他特性
最後我們看下 Deployment 型別 spec 的全部屬性:
- minReadySeconds:預設值為 0,表示一個 pod reday 之後多長時間可以提供服務;換句話說配置成1就是 pod ready 之後 1s 才對外提供服務;
- paused:掛起;
- progressDeadlineSeconds:預設 600,表示處理一個 Deployment 任務的超時時間,比如 10 分鐘到了還沒有升級成功,則標記為 failed 狀態;
- replicas:副本數;
- revisionHistoryLimit:預設是 10,表示保留的歷史版本數量;
- selector:標籤選擇器;
- strategy:表示 Deployment 更新 pod 時的替換策略;
- template:Pod 模板;
這裡的 strategy 有兩個屬性,分別是:type 和 rollingUpdate。type 可選值是:"Recreate" 和 "RollingUpdate",預設為 "RollingUpdate"。strategy.rollingUpdate 有兩個屬性:
- maxSurge: 表示滾動更新的時候最多可以比期望副本數多幾個,數字或者百分比配置都行;比如 1 表示更新過程中最多同時新增 1 個副本,然後等一個老副本刪掉之後才能繼續增加 1 個新副本;百分比計算的時候向上取整;
- maxUnavailable:表示滾動更新的時候可以有多少副本不可用,同樣是數字或者百分比配置;比如期望副本數是 3,1 則表示最多刪除副本到剩下 2,然後要等新副本建立才能繼續刪除;百分比計算的時候向下取整;
小結
本文我們的目的是知道 Deployment 的全部特性,進而為後面的原始碼分析做準備。在這個過程中我們沒有贅述 Deployment 的基礎特性,而是主要介紹“滾動更新”和“回滾”等主要功能,另外簡單過一下 Deployment 的 spec 包含的全量配置項,從而心中有個概念,知道 Deployment 的能力邊界在那裡,從而後面看原始碼時更有針對性。
(轉載請保留本文原始連結 https://www.danielhu.cn)