使用Kubernetes來實現Zero-downtime服務更新與移轉的策略

Posted by Kubeguts on 2020-10-19

通常若一有新版本服務要上線時,都需要考量到移轉到新的服務是否會對舊有的服務造成衝擊?

例如下面這張圖,目前k8s上運行著一個 nginx 1.14.2-alpine版本,現在打算想要更新nginx版本

deployment_rolling_update.png

一般來說會有以下2種做法

  1. 將所有存在的Pods都砍掉,再換成新的Pods
  • 可能會有一些down-time的狀況發生
  1. 先將新的Pods運行起來,然後再砍掉Pods
  • 新舊版本都會存在,同一時間會非常吃CPU與Memory的使用量

可以看到第1種策略勢必會影響到客戶的使用體驗,因為得中斷服務使用。

第2種策略在資源不足的情況下,更容易造成服務的不穩定。

這時候透過k8s本身提供的升版佈署的機制,可以避免上述的副作用。若新版的服務若有問題,k8s也提供了回滾機制,可以快速恢復為原本服務。

k8s 佈署的方法

以這張圖來看,負責進行升版與回滾的機制的元件為 “Deployment” 與 “Replicaset” 這兩個元件所組成

k8s_component_overview.png

k8s提供了三種作法,可以實現 “zero-downtime” 佈署的方法

  1. Rolling Updates
  2. Blue-Green Deployments
  3. Canary Deployments

1. Rolling Updates 滾動更新

在k8s中,透過取代Pods的方式,並且不會影響到客戶端使用服務(Pods)的流量!
這種做法就叫做 Rolling Update

rolling_update_process.png

作法&參數解析

k8s預設的策略就是RollingUpdate,可以在 spec/strategy 中設定

其各個參數說明如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: apps/v1
kind: Deployment
spec:
replicas: # pods數量
minReadySeconds: # 需等待幾秒才啟動Pod,預設為0秒
progressDeadlineSeconds: # 若發生停止的狀況,等待n秒後再報告停止的狀況
revisionHistoryLimit: # 可被Rollback的ReplicaSets數量,預設為10,若超過10的話,就會開始覆寫舊的pod
stretegy: # 設定Deployments的策略
type: # 預設是RollingUpdate,或是Recreate Stretegy
rollingUpdate:
maxSurge: # 請看註1 預設是 replicas數量的25%
maxUnavailable: #請看註2 預設是 replicas數量的25%
...
  • 註1: maxSurge: 在執行RollingUpdate過程中,最大的可超過replicas數值的Pod數量

    • 若maxSurge設置為1, 表示除了replicas設置的2個pods數量,還可以再多一個
    • 例如 2個 新版的pods, 1個舊版的pod
  • 註2: maxUnavailable: 在執行RollingUpdate過程中,沒有在運作的Pods數量

    • 若設置為maxUnavailable 1, replicas設置為2, 表示只會有一個pod在rolling update過程中停機。

相關指令

  • kubectl create -f [yaml file] --save-config --record

    • --save-config : 將configuration儲存到resource’s annotation
    • --record : 將部署的command儲存在Deployment revision history內
  • kubectl apply -f [yaml name] --record

    • --record : 將部署的command儲存在Deployment revision history內
  • kubectl rollout status deployment [deployment-name] --revision=2: 取得deployment rollout的狀態

    • --revision: 只會給指定的revision資訊
  • kubectl rollout history deployment [deployment-name]: 取得執行rollout的歷史紀錄

  • kubectl rollout undo [yaml file] --to-revision=2: rollback到指定的yaml檔案設定檔,或是指定的執行歷史

    • --to-revision: 回滾到之前曾執行過的rollout狀態
通常若要執行回滾,都會先用 kubectl rollout history deployment [name] 查看執行過的revision有哪些,並使用 kubectl rollout undo 做回滾

範例:Rolling Update範例:使用RollingUpdate策略部署 nginx

請至 Rolling Update範例:使用RollingUpdate策略部署 nginx 一節查看

議題:若Pods提供的是前端網頁服務,在Rolling Updates時會發生頁面中斷的情況

由於k8s Services層機制實現負載平衡的效果,使得我們很難事先曉得Client會使用的是哪一個Pods,故這時Rolling Update在此情況下無法解決此議題。

2. Canary Deployments 金絲雀部署

Canary Deployment的中文翻譯為 金絲雀部署,因為以前在礦工進入洞穴時,會先透過金絲雀進入洞穴,以便探路,就像軟體部署,也要有先測試的版本先出來。

Canary Deployment主要目的是先切割目前使用者為 大族群與小族群,
部署新版的給小族群測試使用,稱作 Canary版本,然而大族群的客戶一樣使用舊版本。

canary_deployments.png

  • 同時運行兩個Production環境
  • Canary版本獨立運作,不干擾原本的服務
  • Canary版本會被分配到較小的流量

配上K8S服務的概觀大概如下圖所示

change_to_canary_overview.png

作法&參數解析

基本上進行canary部署,只需要改動deployment設定檔中的replicas數量與container服務就好,並配置適當的 service服務做負載平衡

範例:使用Canary佈署策略, 以Web App為例

請至 範例:使用Canary佈署策略, 以Web App為例 一節查看

3. Blue-Gree Deployments 藍綠部署

藍綠佈署是一個釋出軟體程式碼的變動策略,保證系統再不中斷時,能提供服務的部署方式。

藍色通常代表舊的運行服務,綠色代表新的運行服務

需要有相同的硬體設備,以及相同的設定

blue_green_deployment.png

作法&參數解析

將標注藍色的服務保持正常運作,持續提供給用戶,另外一個綠色的服務則是佈署完新版本的服務,待測試完畢後進行待命

Step 1. 藍綠部署流程第一步會先建立藍色代號的Pod與Service,並與既有運作系統的Service導入到相同的Pods

blue_green_deployment_overview_1.png

此階段會有著

  • Blue Service 設定檔
  • Public Service 設定檔
  • Deployment 設定檔

通常會在PublicBlue Test的Service yaml檔案內的labels -> role 標註為 blue

Blue Test Serivce

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
kind: Service
apiVersion: v1
metadata:
name: 服務名稱-blue-test
labels:
app: 服務名稱
role: blue-test # Service的角色定義為blue-test
env: test
spec:
type: LoadBalancer
selector:
app: 服務名稱
role: blue # 會將流量導入到標註為blue的label的Pod服務
ports:
- port: 9000
targetPort: 80

Public Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
kind: Service
apiVersion: v1
metadata:
name: 服務名稱-blue-test
labels:
app: 服務名稱
role: blue # Service的角色定義為blue
env: prod
spec:
type: LoadBalancer
selector:
app: 服務名稱
role: blue # 會將流量導入到標註為blue的label的Pod服務
ports:
- port: 9000
targetPort: 80

Deployment設定檔

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
apiVersion: apps/v1
kind: Deployment
metadata:
name: 服務名稱-deployment-$TARGET_ROLE
spec:
replicas: 2
selector:
matchLabels:
app: 服務名稱
role: blue # 套用至標註為blue的Pods
template:
metadata:
labels:
app: 服務名稱
role: blue # 將Pods的label標註成blue
spec:
containers:
- name: 服務名稱-$TARGET_ROLE
image: $IMAGE_VERSION
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /
port: 80
livenessProbe:
httpGet:
path: /
port: 80
resources:
limits:
memory: "128Mi" #128 MB
cpu: "200m" #200 millicpu (.2 cpu or 20% of the cpu)

Step 2: 接著再部署綠色代號 (新版本) 的Pod與Service,並給QA做測試

blue_gree_deployment_overview_2.png

這時可看到與canary deployment的差異,blue-green deployment不會讓使用者同時呼叫到舊版本與新版的服務

Green Deployment設定檔

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
apiVersion: apps/v1
kind: Deployment
metadata:
name: 服務名稱-deployment-$TARGET_ROLE
spec:
replicas: 2
selector:
matchLabels:
app: 服務名稱
role: blue # 套用至標註為blue的Pods
template:
metadata:
labels:
app: 服務名稱
role: green # 將Pods的label標註成green
spec:
containers:
- name: 服務名稱-$TARGET_ROLE
image: $IMAGE_VERSION
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /
port: 80
livenessProbe:
httpGet:
path: /
port: 80
resources:
limits:
memory: "128Mi" #128 MB
cpu: "200m" #200 millicpu (.2 cpu or 20% of the cpu)

Step 3: 轉移到綠色服務

若QA team測試完綠色代號的新版本服務,就可以將 Public Test Service的流量從舊版本的服務 Blue 切換到新版的Green 服務了

blue_gree_deployment_overview_3.png

透過更改Public Serivce內的selector為 green,就可以將流量導到labels標註為green 新版本的Pods了

Public Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
kind: Service
apiVersion: v1
metadata:
name: 服務名稱-blue-test
labels:
app: 服務名稱
role: blue
env: prod
spec:
type: LoadBalancer
selector:
app: 服務名稱
role: green # 會將流量導入到標註為green的label的Pod服務
ports:
- port: 9000
targetPort: 80

相關指令

  • kubectl apply -f [yaml]: 套用更動後的設定檔

  • kubectl set selector svc [service-name] 'role=green': 將service內的role更改為green

可看到Blue-Green與Canary的部署差異,前者(blue-green)是新環境測試完畢後,才將Production環境做移轉,後者(canary)則是將一小部分的流量導引到測試環境,在做移轉

範例:使用Blue-Green佈署策略, 以Web App為例

請至 使用Blue-Green佈署策略, 以Web App為例 一節查看

參考

Pluralsight: Kubernetes for Developers: Deploying Your Code
https://app.pluralsight.com/library/courses/kubernetes-developers-deploying-code/table-of-contents