利用kubernetes的滾動更新時,可能經常遇到釋出“太快不穩定”或“太慢體驗差”的情況。本文将介紹kubernetes滾動更新控制速率的特性。
金絲雀釋出
金絲雀釋出這個術語源自20世紀初期,當時英國的煤礦勞工在下井采礦之前,會把籠養的金絲雀攜帶到礦井中,如果礦井中一氧化碳等有毒氣體的濃度過高,在影響礦工之前,金絲雀相比人類表現的更加敏感快速,金絲雀中毒之後,煤礦勞工就知道該立刻撤離。金絲雀釋出是在将整個軟體的新版本釋出給所有使用者之前,先釋出給部分使用者,用真實的客戶流量來測試,以保證軟體不會出現嚴重問題,降低釋出風險。
在實踐中,金絲雀釋出一般會先釋出到一個小比例的機器,比如 2% 的伺服器做流量驗證,然後從中快速獲得回報,根據回報決定是擴大釋出還是復原。金絲雀釋出通常會結合監控系統,通過監控名額,觀察金絲雀機器的健康狀況。如果金絲雀測試通過,則把剩餘的機器全部更新成新版本,否則復原代碼。
優勢:
- 對使用者體驗影響較小,在金絲雀釋出過程中,隻有少量使用者會受影響
- 釋出安全能夠得到保障
劣勢:
- 金絲雀的機器數量比較少, 有一些問題并不能夠暴露出來
适用場景:
- 監控比較完備且與釋出系統內建
灰階/滾動釋出
灰階釋出是金絲雀釋出的延伸,是将釋出分成不同的階段/批次,每個階段/批次的使用者數量逐級增加。如果新版本在目前階段沒有發現問題,就再增加使用者數量進入下一個階段,直至擴充到全部使用者。
灰階釋出可以減小釋出風險,是一種零當機時間的釋出政策。它通過切換線上并存版本之間的路由權重,逐漸從一個版本切換為另一個版本。整個釋出過程會持續比較長的時間, 在這段時間内,新舊代碼共存,是以在開發過程中,需要考慮版本之間的相容性,新舊代碼共存不能影響功能可用性和使用者體驗。當新版本代碼出現問題時,灰階釋出能夠比較快的復原到老版本的代碼上。
結合特性開關等技術,灰階釋出可以實作更複雜靈活的釋出政策。
優勢:
- 使用者體驗影響比較小, 不需要停機釋出
- 能夠控制釋出風險
劣勢:
- 釋出時間會比較長
- 需要複雜的釋出系統和負載均衡器
- 需要考慮新舊版本共存時的相容性
适用場景:
- 适合可用性較高的生産環境釋出
滾動釋出
kubernetes預設的更新政策也就是主流釋出方案是滾動更新。
每次隻更新一個或多個服務,更新完成後加入生産環境, 不斷執行這個過程,直到叢集中的全部舊版更新新版本。
Kubernetes的預設釋出政策。
特點:
- 使用者無感覺,平滑過渡
缺點:
- 部署周期長(需要健康檢查,等它準備就緒,然後更新下一個,健康檢查還是需要花費一些時間的)
- 釋出政策較複雜
- 不易復原
- 有影響範圍較大
含義
服務在滾動更新時,deployment控制器的目的是:給舊版本(old_rs)副本數減少至0、給新版本(new_rs)副本數量增至期望值(replicas)。大家在使用時,通常容易忽視控制速率的特性,以下是kubernetes提供的兩個參數:
- maxUnavailable:和期望ready的副本數比,不可用副本數最大比例(或最大值),這個值越小,越能保證服務穩定,更新越平滑;
- maxSurge:和期望ready的副本數比,超過期望副本數最大比例(或最大值),這個值調的越大,副本更新速度越快。
取值範圍
數值
1. maxUnavailable: [0, 副本數]
2. maxSurge: [0, 副本數]
注意:兩者不能同時為0。
比例
1. maxUnavailable: [0%, 100%] 向下取整,比如10個副本,5%的話==0.5個,但計算按照0個;
2. maxSurge: [0%, 100%] 向上取整,比如10個副本,5%的話==0.5個,但計算按照1個;
注意:兩者不能同時為0。
建議配置
1. maxUnavailable == 0
2. maxSurge == 1
這是我們生産環境提供給使用者的預設配置。即“一上一下,先上後下”最平滑原則:1個新版本pod ready(結合readiness)後,才銷毀舊版本pod。此配置适用場景是平滑更新、保證服務平穩,但也有缺點,就是“太慢”了。
自定義政策
Deployment controller調整replicaset數量時,嚴格通過以下公式來控制釋出節奏。是以,如需快速釋出,可根據實際情況去調整這兩個值:
(目标副本數-maxUnavailable) <= 線上實際Ready副本數 <= (目标副本數+maxSurge)
舉例:如果期望副本數是10,期望能有至少80%數量的副本能穩定工作,是以:maxUnavailable = 2,maxSurge = 2 (可自定義,建議與maxUnavailable保持一緻)
8 <= 線上實際Ready副本數 <= 12
這樣,更新過程中,線上能夠正常提供服務的pod數總會保持在這個區間内。
現象(maxUnavailable = 1,maxSurge = 1)
#我這裡跟新了鏡像然後應用,也就是滾動更新
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: web
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
[root@k8s-master ~]# kubectl get ep -w
NAME ENDPOINTS AGE
kubernetes 192.168.179.102:6443 29d
web 10.244.169.141:80,10.244.169.142:80,10.244.36.78:80 8m8s
web 10.244.169.141:80,10.244.36.78:80 8m58s
web 10.244.169.141:80,10.244.36.78:80 10m
web 10.244.169.141:80,10.244.169.143:80,10.244.36.78:80 10m
web 10.244.169.143:80,10.244.36.78:80 10m
web 10.244.169.143:80,10.244.36.78:80 10m
web 10.244.169.143:80,10.244.169.144:80,10.244.36.78:80 10m
web 10.244.169.143:80,10.244.169.144:80 10m
web 10.244.169.143:80,10.244.169.144:80 11m
web 10.244.169.143:80,10.244.169.144:80,10.244.36.79:80 11m
[root@k8s-master ~]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
web-655569c6d8-96kmp 1/1 Running 0 15m
web-655569c6d8-n8nvk 1/1 Running 0 15m
web-655569c6d8-vmnj6 1/1 Running 0 15m
web-7cf4f6bf9f-kktpq 0/1 Pending 0 0s
web-7cf4f6bf9f-kktpq 0/1 Pending 0 0s
web-655569c6d8-n8nvk 1/1 Terminating 0 15m
web-7cf4f6bf9f-bbchz 0/1 Pending 0 0s
web-7cf4f6bf9f-bbchz 0/1 Pending 0 1s
web-655569c6d8-n8nvk 1/1 Terminating 0 15m
web-655569c6d8-n8nvk 0/1 Terminating 0 15m
web-655569c6d8-n8nvk 0/1 Terminating 0 15m
web-655569c6d8-n8nvk 0/1 Terminating 0 15m
web-7cf4f6bf9f-bbchz 0/1 Pending 0 15s
web-7cf4f6bf9f-bbchz 0/1 ContainerCreating 0 15s
web-7cf4f6bf9f-bbchz 0/1 ContainerCreating 0 18s
web-7cf4f6bf9f-bbchz 0/1 Running 0 63s
web-7cf4f6bf9f-bbchz 1/1 Running 0 75s
web-655569c6d8-vmnj6 1/1 Terminating 0 16m
web-7cf4f6bf9f-rgq9w 0/1 Pending 0 0s
web-7cf4f6bf9f-rgq9w 0/1 Pending 0 0s
web-655569c6d8-vmnj6 1/1 Terminating 0 16m
web-655569c6d8-vmnj6 0/1 Terminating 0 16m
web-655569c6d8-vmnj6 0/1 Terminating 0 16m
web-655569c6d8-vmnj6 0/1 Terminating 0 16m
web-7cf4f6bf9f-kktpq 0/1 Pending 0 79s
web-7cf4f6bf9f-kktpq 0/1 ContainerCreating 0 80s
web-7cf4f6bf9f-kktpq 0/1 ContainerCreating 0 81s
web-7cf4f6bf9f-kktpq 0/1 Running 0 82s
web-7cf4f6bf9f-kktpq 1/1 Running 0 92s
web-655569c6d8-96kmp 1/1 Terminating 0 17m
web-655569c6d8-96kmp 1/1 Terminating 0 17m
web-655569c6d8-96kmp 0/1 Terminating 0 17m
web-655569c6d8-96kmp 0/1 Terminating 0 17m
web-655569c6d8-96kmp 0/1 Terminating 0 17m
web-7cf4f6bf9f-rgq9w 0/1 Pending 0 19s
web-7cf4f6bf9f-rgq9w 0/1 ContainerCreating 0 19s
web-7cf4f6bf9f-rgq9w 0/1 ContainerCreating 0 21s
web-7cf4f6bf9f-rgq9w 0/1 Running 0 59s
web-7cf4f6bf9f-rgq9w 1/1 Running 0 68s
總結
## 檢視曆史
kubectl rollout history deployment/anyops-devopsdocker-ui
## 檢視具體某一個曆史版本資訊
kubectl rollout history deployment/anyops-devopsdocker-ui --revision=2
## 復原上個版本
kubectl rollout undo deployment/anyops-devopsdocker-ui -n anyops
## 復原指定版本
kubectl rollout undo deployment/nginx --to-revision=2