一、更新執行在 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