Kubernetes 實戰——升級應用(Deployment)

LB477發表於2021-06-18

一、更新執行在 Pod 內的應用程式

1. 修改 Pod 模板

將導致應用程式在一定時間內不可用

2. 修改 Service 的 Pod 選擇器

需要同時執行兩倍的 Pod

3. 滾動升級

應用程式需支援兩個版本同時對外提供服務

舊版本 ReplicationController 縮容,同時新版本擴容

通過新舊 ReplicationController 副本數的改變,逐漸將所有 Pod 替換成新版本,結束後刪除原有的 ReplicationController

二、使用 Deployment

用於部署應用程式,並以宣告的方式升級應用

建立 Deployment 時自動建立 ReplicaSet,Pod 由 ReplicaSet 建立和管理

1. 建立 Deployment

定義類似於 ReplicationController。但能指定部署策略:在修改 Deployment 資源時如何執行更新

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kubia
spec:
  replicas: 3
  selector:
    matchLabels:
      app: kubia
  template:
    metadata:
      name: kubia
      labels:
        app: kubia
    spec:
      containers:
      - image: luksa/kubia:v1
        name: nodejs
# --record:記錄歷史版本號
$ kubectl create -f kubia-deployment-v1.yaml --record
# 檢視部署狀態
$ kubectl rollout status deployment kubia
deployment "kubia" successfully rolled out
# 檢視部署的資源
$ kubectl get all
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/kubia   3/3     3            3           3m34s

NAME                               DESIRED   CURRENT   READY   AGE
replicaset.apps/kubia-59d857b444   3         3         3       3m34s

NAME                         READY   STATUS    RESTARTS   AGE
pod/kubia-59d857b444-4c7v8   1/1     Running   0          3m34s
pod/kubia-59d857b444-7r76k   1/1     Running   0          3m34s
pod/kubia-59d857b444-lrjtp   1/1     Running   0          3m34s
  • ReplicaSet 建立的 Pod 名稱是由 ReplicaSet 名稱加上執行時生成的隨機字串組成的
  • Deployment 建立的 ReplicaSet 包含 Pod 模板的雜湊值

2. 升級 Deployment

只需修改 Deployment 資源中定義的 Pod 模板,K8s 會自動將系統狀態收斂到定義的狀態

升級策略:

  • RollingUpdate:滾動更新。預設策略
    • 漸進刪除舊 Pod,同時建立新 Pod
    • Pod 數量會浮動,其上下限可配置
  • Recreate:一次性刪除所有舊 Pod,之後建立新 Pod
    • 適用:系統不支援多個版本同時對外提供服務。但會出現短暫不可用

演示 RollingUpdate

# 1. 減慢滾動升級速度
# kubectl patch 常用於修改單個或少量資源屬性,無需編輯器編輯
$ kubectl patch deployment kubia -p '{"spec": {"minReadySeconds": 10}}'
# 因為 Pod 模板沒變,故不會觸發滾動升級

# 2. 觸發滾動升級
# 指定新的映象(可設定任何包含容器的資源)
$ kubectl set image deployment kubia nodejs=luksa/kubia:v2

# 3. 檢視滾動升級
$ while true; do curl 10.109.157.15; done
# 可以看到剛開始請求 v1,後來慢慢全部切換到 v2

升級過程由 Deployment 控制器完成。流程為:建立新的 ReplicaSet 然後擴容,同時之前的 ReplicaSet 會縮容至 0。舊的 ReplicaSet 仍被保留

若 Deployment 的 Pod 模板引用了 ConfigMap/Secret,更改 ConfigMap/Secret 資源本身不會觸發升級操作

若想觸發更新可建立新的 ConfigMap/Secret 並修改模板引用

3. 回滾 Deployment

使用新映象

# v3 版本請求 5 次後會出錯
$ kubectl set image deployment kubia nodejs=luksa/kubia:v3
# 檢視整個升級過程
$ kubectl rollout status deployment kubia
# 模擬應用出錯
$ while true; do curl 10.109.157.15; done

回滾

# 回滾到先前版本
$ kubectl rollout undo deployment kubia
# 顯示升級的版本(歷史版本號會被儲存到 ReplicaSet 中)
$ kubectl rollout history deployment kubia
deployment.apps/kubia 
REVISION  CHANGE-CAUSE  # 若不指定 --record,CHANGE-CAUSE 會為空
1         kubectl create --filename=kubia-deployment-v1.yaml --record=true
3         kubectl create --filename=kubia-deployment-v1.yaml --record=true
4         kubectl create --filename=kubia-deployment-v1.yaml --record=true
# 回滾到指定版本
$ kubectl rollout undo deployment kubia --to-revision=1

undo 也可以在滾動升級過程中執行:停止升級並刪除已建立 pod

可通過指定 Deployment 的 revisionHistoryLimit 來限制歷史版本數量,預設 10

4. 控制滾動升級速率

spec:
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  • maxSurge:決定 Deployment 配置中期望的副本數之外,最多允許超出的 Pod 例項數量。預設值為 25%(四捨五入)
  • maxUnavailable:決定在滾動升級期間,相對於期望副本數能夠允許多少 Pod 例項處於不可用狀態。預設值為 25%(四捨五入)

本例中,replicas=3,因此 Pod 數最多可達到 4 且必須有 2 個 Pod 可用

5. 暫停滾動升級

只升級部分,方便使用者驗證新版本 Pod

kubectl set image deployment kubia nodejs=luksa/kubia:v4
kubectl rollout pause deployment kubia
# 這樣會建立一個(數量不可控)新的 Pod
# 若部署被暫停,在恢復部署之前,撤銷命令不會撤銷它

恢復滾動升級

kubectl rollout resume deployment kubia

暫停功能還可用於阻止更新 Deployment 後的自動升級行為。可更改多次,完成更改後再升級

6. 滾動升級前檢查

minReadySeconds 屬性主要是避免部署出錯版本的應用,而不是單單減緩部署的速度。它指定新建立的 Pod 至少要成功執行多久之後,才能將其視為可用。在 Pod 可用前,滾動升級的過程不會繼續

當容器的所有就緒探針都返回成功時,Pod 被標記為就緒狀態。Pod 就緒後等待 minReadySeconds 後才可用,才繼續滾動升級

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kubia
spec:
  # 更新可以不用加 replicas
  selector:
    matchLabels:
      app: kubia
  minReadySeconds: 10
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0  # 挨個替換
    type: RollingUpdate
  template:
    metadata:
      name: kubia
      labels:
        app: kubia
    spec:
      containers:
      - image: luksa/kubia:v3
        name: nodejs
        readinessProbe:
          periodSeconds: 1  # 1s 執行一次就緒探針
          httpGet:  # 探針傳送的請求
            path: /
            port: 8080
kubectl apply -f kubia-deployment-v3.yaml

預設 10min(spec.progressDeadlineSeconds)內不能完成滾動升級就視為失敗,滾動升級會自動取消

可通過 rollout undo 取消滾動升級



修改資源的不同方式

方法 作用 例子
kubectl edit 使用預設編輯器開啟資源配置 kubectl edit pod test
kubectl patch 修改單個資源屬性 kubectl patch pod test -p '{"spec": {"replicas": 4}}'
kubectl apply 通過 YAML/JSON 檔案修改或建立資源 kubectl apply -f test.yaml
kubectl replace 通過 YAML/JSON 檔案修改資源(資源需存在) kubectl replace -f test.yaml
kubectl set image 修改包含容器資源的映象 kubectl set image pod test nodejs=kubia:v2

映象拉取策略

  • 若更改後的映象推到相同的 tag,會導致映象不被重新拉取。可設定容器的 imagePullPolicy 為 Always
  • 若容器使用 latest 的 tag,則 imagePullPolicy 預設為 Always,否則為 IfNotPresent

命令

kubectl delete pod --all
kubectl set selector ...
# 提高日誌級別,輸出所有 kubectl 發起的 API 伺服器請求
kubectl ... --v 6

相關文章