Kubernetes學習筆記(八):Deployment–聲明式的升級應用

概述

本文核心問題是:如何升級應用。
對於Pod的更新有兩種策略:

  • 一是刪除全部舊Pod之後再創建新Pod。好處是,同一時間只會有一個版本的應用存在;缺點是,應用有一段時間不可用。
  • 二是先創建新Pod,再刪除舊Pod。可以一次性創建全部,再刪除全部,也可以逐漸創建刪除。好處是應用一直可用,缺點是要同時支援兩個版本。

藍綠部署

對於應用的版本v1和版本v2:

  • 在運行v1前,流量一直都在v2上
  • 部署v1,然後測試通過後,將流量切換到v2,v2就成為了新的生產環境
  • 一旦v2出現問題,可以在切回v1

金絲雀部署(也稱灰度部署)

金絲雀部署一種增量發布,先是在小範圍內發布,然後觀察測試,如無問題逐漸發布全部。

kubectl rolling-update

因為kubectl rolling-update的方式已經過時,所以只是做一下簡介。
假設現在有一個名為test-v1,Pod選擇器為app=order的ReplicationController要升級為test-v2,則執行下面命令可升級:

k rolling-update test-v1 test-v2 --image=test:v2

運行此命令後:

  1. 立刻創建一個名為test-v2的ReplicationController,他的Pod模板鏡像正是test:v2,並添加一個標籤deployment=xxxx
  2. test-v1以及app=order選中的Pod都會被加上一個標籤:deployment=yyyy。如此做法是防止Pod的管理混亂。
  3. 先將test-v2的Pod擴展為1,使用更新後的模板創建新Pod;再將test-v1縮小1,如此循環。
  4. 因為在滾動過程中Service的標籤選擇器一直是app=order,所以新老版本都會接收到流量。

過時的原因是:伸縮的請求時由kubectl發起的,如果因為任何原因丟失了網路連接,升級將處於中間狀態。另一個原因是:期望只修改Pod定義中的鏡像tag,就能時Kubernetes運行升級工作

使用Deployment聲明式的升級

Deployment是一種更高階的資源,用於部署程式並以聲明的方式升級應用,而不是通過ReplicationController或ReplicaSet進行部署。

在使用Deployment時,Pod是由Deployment的ReplicaSet創建的。

準備鏡像

將之前的文章(Kubernetes學習筆記(四):服務)里的拿過來做一下微小的改動,生成兩個鏡像。改動內容就是在輸出內容加上版本號。

fmt.Fprintf(w,"this is v1, hostname: %v\n",hostname)
docker push registry.cn-hangzhou.aliyuncs.com/orzi/goweb:v1

fmt.Fprintf(w,"this is v2, hostname: %v\n",hostname)
docker push registry.cn-hangzhou.aliyuncs.com/orzi/goweb:v2

創建Deployment

Deployment與ReplicaSet的配置相似,都含有標籤選擇器、副本數量和Pod模板。此外Deployment還會包含一個部署策略。

定義Service

定義了一個NodePort類型的Service

# goweb-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: goweb
spec:
  type: NodePort
  selector:
    app: goweb
  ports:
    - port: 80
      targetPort: 8000
      nodePort: 31234

定義Deployment

# goweb-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: goweb
spec:
  replicas: 3
  selector:
    matchLabels:
      app: goweb
  template:
    metadata:
      labels:
        app: goweb
    spec:
      containers:
      - name: goweb
        image: registry.cn-hangzhou.aliyuncs.com/orzi/goweb:v1

運行查看

可以看到名為goweb-fdfcfdcc6的RS,有個label是pod-template-hash=fdfcfdcc6,顧名思義,fdfcfdcc6就是pod模板的hash值。

創建Deployment時指定 –record 記錄歷史版本號,非常有用

-> [[email protected]] [~] k create -f goweb-svc.yaml
service/goweb created

-> [[email protected]] [~] k create -f goweb-deployment.yaml --record

deployment.apps/goweb created
-> [[email protected]] [~] k get all -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP            NODE       NOMINATED NODE   READINESS GATES
pod/goweb-fdfcfdcc6-4wklw   1/1     Running   0          9s    10.244.2.37   kube2.vm   <none>           <none>
pod/goweb-fdfcfdcc6-bw8c4   1/1     Running   0          9s    10.244.2.36   kube2.vm   <none>           <none>
pod/goweb-fdfcfdcc6-xjcwf   1/1     Running   0          9s    10.244.1.33   kube1.vm   <none>           <none>

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTOR
service/goweb        NodePort    10.100.193.94   <none>        80:31234/TCP   28s   app=goweb
service/kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        54s   <none>

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES                                            SELECTOR
deployment.apps/goweb   3/3     3            3           9s    goweb        registry.cn-hangzhou.aliyuncs.com/orzi/goweb:v1   app=goweb

NAME                              DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES                                            SELECTOR
replicaset.apps/goweb-fdfcfdcc6   3         3         3       9s    goweb        registry.cn-hangzhou.aliyuncs.com/orzi/goweb:v1   app=goweb,pod-template-hash=fdfcfdcc6

升級Deployment

只要修改Deployment的Pod模板定義,Kubernetes會自動的將實際狀態收斂為修改後的狀態。對於升級,只需要修改Pod中鏡像的tag。

升級策略由deployment.spec.strategy.type定義,值是Recreate或RollingUpdate,默認RollingUpdate。

kubectl patch及minReadySeconds

使用kubectl patch定義deployment.spec.minReadySeconds來減慢滾動升級時間,以便觀察升級過程

-> [[email protected]] [~] k patch deployment goweb -p '{"spec":{"minReadySeconds":5}}'
deployment.apps/goweb patched

循環請求服務

在執行升級前新開窗口,運行下面的命令查看輸出

-> [[email protected]] [~] while true; do curl //192.168.199.231:31234/ ; sleep 1; done
this is v1, hostname: goweb-fdfcfdcc6-pw7b4
this is v1, hostname: goweb-fdfcfdcc6-pw7b4
this is v1, hostname: goweb-fdfcfdcc6-x8n7h
this is v1, hostname: goweb-fdfcfdcc6-pw7b4
this is v1, hostname: goweb-fdfcfdcc6-x8n7h
this is v1, hostname: goweb-fdfcfdcc6-j4mz8
this is v1, hostname: goweb-fdfcfdcc6-j4mz8
# 以上是升級之前的輸出、以下是開始升級後的
this is v1, hostname: goweb-fdfcfdcc6-x8n7h
this is v1, hostname: goweb-fdfcfdcc6-pw7b4
this is v1, hostname: goweb-fdfcfdcc6-pw7b4
this is v1, hostname: goweb-fdfcfdcc6-j4mz8
this is v2, hostname: goweb-65cc575865-25988
this is v2, hostname: goweb-65cc575865-25988
this is v1, hostname: goweb-fdfcfdcc6-x8n7h
this is v1, hostname: goweb-fdfcfdcc6-j4mz8
this is v2, hostname: goweb-65cc575865-bfd98
this is v2, hostname: goweb-65cc575865-bfd98
this is v2, hostname: goweb-65cc575865-25988
this is v2, hostname: goweb-65cc575865-25988
this is v2, hostname: goweb-65cc575865-25988
# 這之後就是升級完成了

kubectl set

使用 kubectl set image 更新任何包含容器資源的鏡像。

-> [[email protected]] [~] k set image deployment goweb goweb=registry.cn-hangzhou.aliyuncs.com/orzi/goweb:v2
deployment.apps/goweb image updated

kubectl rollout

查看升級狀態資訊。執行完kubectl set image,立刻執行下面的命令。手速得快,不然趕不上熱乎的。

-> [[email protected]] [~] k rollout status deployment goweb
Waiting for deployment "goweb" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "goweb" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "goweb" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "goweb" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "goweb" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "goweb" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "goweb" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "goweb" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "goweb" rollout to finish: 1 old replicas are pending termination...
deployment "goweb" successfully rolled out

修改Deployment或其他資源的方式

方法 作用
kubectl edit 使用編輯器打開資源配置
kubectl patch 在命令行以merge的方式修改配置
kubectl apply 通過yaml或者json文件,修改新改動的值。如果指定的對象不存在則創建。
kubectl replace 使用yaml或者json文件替換一個必須已存在的對象配置。
kubectl set image 修改鏡像

回滾

使用kubectl rollout undo 回滾到上一個版本

-> [[email protected]] [~] k rollout undo deployment goweb
deployment.apps/goweb rolled back

使用 kubectl rollout history 查看版本記錄

-> [[email protected]] [~] k rollout history deployment goweb
deployment.apps/goweb
REVISION  CHANGE-CAUSE
6         kubectl create --filename=goweb-deployment.yaml --record=true
7         kubectl create --filename=goweb-deployment.yaml --record=true

回滾到特定版本

-> [[email protected]] [~] k rollout undo deployment goweb --to-revision=5
error: unable to find specified revision 5 in history

-> [[email protected]] [~] k rollout undo deployment goweb --to-revision=7
deployment.apps/goweb skipped rollback (current template already matches revision 7)

-> [[email protected]] [~] k rollout undo deployment goweb --to-revision=6
deployment.apps/goweb rolled back

通過deployment.spec.revisionHistoryLimit指定歷史版本個數,默認為2。也就是當前和上一個版本。

控制滾動升級速率

deployment.spec.strategy.rollingUpdate下有兩個欄位,用來控制升級速率

  • maxSurge:超出期望副本數的Pod實例的比例或個數。默認25%,轉換成絕對值後四捨五入,也可以直接指定為絕對值。
  • maxUnavailable:滾動升級時,最多允許有多少實例不可用,默認25%,轉換成絕對值後四捨五入,也可以直接指定為絕對值。

暫停、恢復升級

  • 使用kubectl rollout pause暫停升級
  • 使用kubectl rollout resume取消暫停

阻止出錯版本的滾動升級

  • minReadySeconds:指定新創建的Pod至少要運行多久才視為可用。
  • 配置就緒探針
  • 為滾動升級配置progressDeadlineSeconds

小結

  • kubectl rolling-update 過時的原因:伸縮的請求時由kubectl發起的,如果因為任何原因丟失了網路連接,升級將處於中間狀態
  • Deployment是一種更高階的資源,用於部署程式並以聲明的方式升級應用,而不是通過ReplicationController或ReplicaSet進行部署。
  • 創建Deployment時指定 –record 記錄歷史版本號
  • Deployment下的ReplicaSet命名是DeploymentName+Pod模板Hash,而ReplicaSet下的Pod是在此基礎拼接個隨機字元串。
  • 升級策略由deployment.spec.strategy.type定義,值是Recreate或RollingUpdate,默認RollingUpdate。
  • 定義deployment.spec.minReadySeconds來減慢滾動升級時間
  • maxSurge與maxUnavailable控制滾動升級速率
  • 命令:patch、set、rollout
  • kubectl rollout:status、undo、pause、resume、history。