目錄
- 滾動部署
- 藍綠發布 為什么還需要藍綠
- 金絲雀發布(canary) 金絲雀和藍綠的對比
- 灰度發布
- A/B Test
- 實現 kubernetesistIOSpring cloud 網關
- 參考
滾動部署
在滾動部署中,應用的新版本逐步替換舊版本。實際的部署發生在一段時間內。在此期間,新舊版本會共存,而不會影響功能和用戶體驗。這個過程可以更輕易的回滾和舊組件不兼容的任何新組件。
下圖顯示了該部署模式:舊版本顯示為藍色,新版本顯示為綠色,它們部署在集群中的每一臺服務器上。
應用程序套件升級是一個滾動部署的典型例子。如果原始應用部署在容器中,升級可以一次處理一個容器。修改每個容器從應用供應商的站點上下載最新的鏡像。如果其中的一個應用存在兼容性問題,舊的鏡像可以重新創建這個容器。在這種情況下,套件的新舊版本應用可以共存,直到每個應用都更新完畢。
但是滾動升級有一個問題,在開始滾動升級后,流量會直接流向已經啟動起來的新版本,但是這個時候,新版本是不一定可用的,比如需要進一步的測試才能確認。那么在滾動升級期間,整個系統就處于非常不穩定的狀態,如果發現了問題,也比較難以確定是新版本還是老版本造成的問題。
為了解決這個問題,我們需要為滾動升級實現流量控制能力。
藍綠發布
藍綠發布提供了一種零宕機的部署方式。不停老版本,部署新版本進行測試,確認OK,將流量切到新版本,然后老版本同時也升級到新版本。始終有兩個版本同時在線,有問題可以快速切換。
藍綠發布的特點:
在部署應用的過程中,應用始終在線。并且新版本上線過程中,不會修改老版本的任何內容,在部署期間老版本狀態不受影響。只要老版本的資源不被刪除,可以在任何時間回滾到老版本。
以下示意圖可描述灰度發布的大致流程:先切分20%的流量到新版本,若表現正常,逐步增加流量占比,繼續測試新版本表現。若新版本一直很穩定,那么將所有流量都切分到新版本,并下線老版本。
切分20%的流量到新版本后,新版本出現異常,則快速將流量切回老版本。
藍綠部署要求在升級過程中,同時運行兩套程序,對硬件的要求就是日常所需的二倍,比如日常運行時,需要10臺服務器支撐業務,那么使用藍綠部署,你就需要購置二十臺服務器。
為什么還需要藍綠
有了灰度發布之后,為什么還需要藍綠發布呢?主要有如下幾點考慮:
- 應用在生產環境全量發布后,發現故障時回滾時間慢。當線上核心應用存在幾十上百的服務實例時,應用實例分批滾動回滾,部分業務應用啟動時間需要幾分鐘,導致整個回滾過程的時間可能超過十分鐘,甚至幾十分鐘。
- 灰度發布期間能發現的問題有限。如數據庫慢查問題、死鎖問題等,10%流量很難發現,可能只會在100%流量中才容易暴露。
- 灰度發布成功后,仍然需要進行全量發布,在此過程中仍有較多不確定性,如因一些未預料的異常導致發布失敗等。
對于上面幾個問題,使用藍綠發布系統都可以較好地解決:
- 藍綠發布期間,流量全部切至新集群時,原穩定集群繼續保持在線,若新集群有問題,可通過流量控制秒級切回至原穩定集群,沒有應用啟動以及其他等待時間。
- 藍綠發布期間,新集群規模與原穩定集群規模一致,即使是瞬時大流量也沒有問題。
- 藍綠發布期間,新集群承載全站流量,容易驗證各種場景,如數據庫死鎖等并發問題。
- 藍綠發布新集群驗證完成后,已經處于正常服務狀態,不會再引入不確定性的變更操作。
金絲雀發布(canary)
在生產環境上引一部分實際流量對一個新版本進行測試,測試新版本的性能和表現,在保證系統整體穩定運行的前提下,盡早發現新版本在實際環境上的問題。
“
為什么叫金絲雀發布呢,是因為金絲雀對礦場中的毒氣比較敏感,所以在礦場開工前工人們會放一只金絲雀進去,以驗證礦場是否存在毒氣,這便是金絲雀發布名稱的由來。
”
金絲雀發布的特點:
通過在線上運行的服務中,新加入少量的新版本的服務,然后從這少量的新版本中快速獲得反饋,根據反饋決定最后的交付形態。
下圖為華為云的金絲雀發布界面:
步驟一:將流量從待部署節點移出,更新該節點服務到待發布狀態,將該節點稱為金絲雀節點;
步驟二:根據不同策略,將流量引入金絲雀節點。策略可以根據情況指定,比如隨機樣本策略(隨機引入)、狗糧策略(就是內部用戶或員工先嘗鮮)、分區策略(不同區域用戶使用不同版本)、用戶特征策略(這種比較復雜,需要根據用戶個人資料和特征進行分流,類似于千人千面);
步驟三:金絲雀節點驗證通過后,選取更多的節點稱為金絲雀節點,重復步驟一和步驟二,直到所有節點全部更新
金絲雀部署和藍綠有點像,但是它更加規避風險。你可以階段性的進行,而不用一次性從藍色版本切換到綠色版本。
采用金絲雀部署,你可以在生產環境的基礎設施中小范圍的部署新的應用代碼。一旦應用簽署發布,只有少數用戶被路由到它。最大限度的降低影響。如果沒有錯誤發生,新版本可以逐漸推廣到整個基礎設施。下圖示范了金絲雀部署:
金絲雀和藍綠的對比
名稱 特點 優勢 劣勢 藍綠部署 同時存在兩個集群,兩個集群中只有一個集群真正提供服務,另外一個集群測試、驗證或待命 服務文檔,版本回退簡單,適用于各種場景的升級,大版本不兼容升級的或迭代兼容升級 浪費硬件資源,需要同時有兩個集群,如果集群比較大,比如有1000個節點,這種方式幾乎不可用 金絲雀部署 逐點部署,逐步替換線上服務 小步快跑,快速迭代 只能適用于兼容迭代的方式,如果是大版本不兼容的場景,就沒辦法使用這種方式了
灰度發布
灰度發布是迭代的軟件產品在生產環境安全上線的一種重要手段。
灰度發布,也叫金絲雀發布。是指在黑與白之間,能夠平滑過渡的一種發布方式。AB test就是一種灰度發布方式,讓一部分用戶繼續用A,一部分用戶開始用B,如果用戶對B沒有什么反對意見,那么逐步擴大范圍,把所有用戶都遷移到B上面來。灰度發布可以保證整體系統的穩定,在初始灰度的時候就可以發現、調整問題,以保證其影響度,而我們平常所說的金絲雀部署也就是灰度發布的一種方式。
A/B Test
A/B測試和藍綠發布、滾動發布以及金絲雀發布,完全是兩回事。
藍綠發布、滾動發布和金絲雀是發布策略,目標是確保新上線的系統穩定,關注的是新系統的BUG、隱患。
A/B測試是效果測試,同一時間有多個版本的服務對外服務,這些服務都是經過足夠測試,達到了上線標準的服務,有差異但是沒有新舊之分(它們上線時可能采用了藍綠部署的方式)。
A/B測試關注的是不同版本的服務的實際效果,譬如說轉化率、訂單情況等。
A/B測試時,線上同時運行多個版本的服務,這些服務通常會有一些體驗上的差異,譬如說頁面樣式、顏色、操作流程不同。相關人員通過分析各個版本服務的實際效果,選出效果最好的版本。
實現
kubernetes
官方的金絲雀發布方式
https://kubernetes.io/zh/docs/concepts/cluster-administration/manage-deployment/#canary-deployments
Deployment滾動更新策略實現金絲雀發布
利用Deployment的滾動更新策略maxSurge和maxUnavailable設置最大可超期望的節點數和最大不可用節點數可實現簡單的金絲雀發布。
rollingUpdate.maxSurge最大可超期望的節點數,百分比 10% 或者絕對數值 5
rollingUpdate.maxUnavailable最大不可用節點數,百分比或者絕對數值
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: demo-deployment
namespace: default
spec:
replicas: 10
selector:
matchLabels:
name: hello-deployment
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 10%
maxUnavailable: 0
template:
metadata:
labels:
name: demo-deployment
spec:
containers:
- name: webserver
image: Nginx:1.14
ports:
- containerPort:80
Ingress-Nginx配置Ingress Annotations實現金絲雀發布
Ingress-Nginx 支持配置 Ingress Annotations 來實現不同場景下的金絲雀發布。Nginx Annotations 支持以下 4 種 Canary 規則:
- nginx.ingress.kubernetes.io/canary-by-header:基于 Request Header 的流量切分,適用于灰度發布以及 A/B 測試。當 Request Header 設置為 always時,請求將會被一直發送到 Canary 版本;當 Request Header 設置為 never時,請求不會被發送到 Canary 入口;對于任何其他 Header 值,將忽略 Header,并通過優先級將請求與其他金絲雀規則進行優先級的比較。
- nginx.ingress.kubernetes.io/canary-by-header-value:要匹配的 Request Header 的值,用于通知 Ingress 將請求路由到 Canary Ingress 中指定的服務。當 Request Header 設置為此值時,它將被路由到 Canary 入口。該規則允許用戶自定義 Request Header 的值,必須與上一個 annotation (即:canary-by-header)一起使用。
- nginx.ingress.kubernetes.io/canary-weight:基于服務權重的流量切分,適用于藍綠部署,權重范圍 0 - 100 按百分比將請求路由到 Canary Ingress 中指定的服務。權重為 0 意味著該金絲雀規則不會向 Canary 入口的服務發送任何請求。權重為 100 意味著所有請求都將被發送到 Canary 入口。
- nginx.ingress.kubernetes.io/canary-by-cookie:基于 Cookie 的流量切分,適用于灰度發布與 A/B 測試。用于通知 Ingress 將請求路由到 Canary Ingress 中指定的服務的cookie。當 cookie 值設置為 always時,它將被路由到 Canary 入口;當 cookie 值設置為 never時,請求不會被發送到 Canary 入口;對于任何其他值,將忽略 cookie 并將請求與其他金絲雀規則進行優先級的比較。
注意:金絲雀規則按優先順序進行如下排序:canary-by-header - > canary-by-cookie - > canary-weight很顯然
canary-weight是一種隨機策略。
canary-by-cookie和canary-by-header-value適合后端金絲雀發布實現
canary-by-cookie適合前端金絲雀發布實現。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: demo-canary
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "canary"
nginx.ingress.kubernetes.io/canary-by-cookie: "canary"
spec:
rules:
- host: demo-api.fulu.com
http:
paths:
- backend:
serviceName: demo-api-canary
servicePort: 80
具體流程
- 如果是第一次發布,必須是正常版本。
- 如果發布金絲雀版本,則先檢測是否有-canary后綴的ingress、service、deployment,如果有則替換金絲雀版本的鏡像,如果沒有則創建-canary后綴的ingress、service、deployment。
- 如果發布正常版本,則先檢測是否有-canary后綴的ingress、service、deployment,如果有則先刪除它們,再替換正常版本的鏡像。
藍綠部署實現: https://www.cnblogs.com/itzgr/p/14602827.html
以上這些方式只是實現了一種非常簡單的金絲雀發布流程,是沒有辦法做更精細,比如說按用戶信息去灰度的規則的。對于同一個用戶,也有可能一次請求到了金絲雀中,下一次請求又到了正式環境中。假如需要更加精細的灰度規則,可以考慮采用spring cloud, istio等工具
istio
Kubernetes 中的金絲雀部署
假設我們有一個已部署的 helloworld 服務 v1 版本,我們想要測試(或簡單上線)新版本 v2。使用 Kubernetes,您可以通過簡單地更新服務的 [Deployment] 中的鏡像并自動進行部署來[上線]新版本的 helloworld 服務。如果我們特能夠小心保證在啟動并且在僅啟動一個或兩個 v2 副本[暫停]上線時有足夠的 v1 副本運行,則能夠保持金絲雀發布對系統的影響非常小。后續我們可以觀察效果,或在必要時進行[回滾]。最好,我們也能夠對 Deployment 設置 [HPA],在上線過程中減少或增加副本以處理流量負載時,也能夠保持副本比例一致。
盡管這種機制能夠很好工作,但這種方式只適用于部署的經過適當測試的版本,也就是說,更多的是藍/綠發布,又稱紅/黑發布,而不是 “蜻蜓點水“ 式的金絲雀部署。實際上,對于后者(例如,并沒有完全準備好或者無意對外暴露的版本),Kubernetes 中的金絲雀部署將使用具有[公共 pod 標簽]的兩個 Deployment 來完成。在這種情況下,我們不能再使用自動縮放器,因為是有由兩個獨立的自動縮放器來進行控制,不同負載情況下,副本比例(百分比)可能與所需的比例不同。
無論我們使用一個或者兩個部署,使用 Docker,Mesos/Marathon 或 Kubernetes 等容器編排平臺進行的金絲雀發布管理都存在一個根本問題:使用實例擴容來管理流量;版本流量分發和副本部署在上述平臺中并獨立。所有 pod 副本,無論版本如何,在 kube-proxy 循環池中都被一視同仁地對待,因此管理特定版本接收的流量的唯一方法是控制副本比例。以小百分比維持金絲雀流量需要許多副本(例如,1% 將需要至少 100 個副本)。即使我們可以忽略這個問題,部署方式功能仍然非常有限,因為它只支持簡單(隨機百分比)金絲雀部署。如果我們想根據某些特定規則將請求路由到金絲雀版本上,我們仍然需要另一種解決方案。
使用 Istio,流量路由和副本部署是兩個完全獨立的功能。服務的 pod 數量可以根據流量負載靈活伸縮,與版本流量路由的控制完全正交。這在自動縮放的情況下能夠更加簡單地管理金絲雀版本。事實上,自動縮放管理器仍然獨立運行,其在響應因流量路由導致的負載變化與其他原因導致負載變化的行為上沒有區別。
Istio 的[路由規則]也帶來了其他的便利;你可以輕松實現細粒度控制流量百分比(例如,路由 1% 的流量而不需要 100 個 pod),當然也可以使用其他規則來控制流量(例如,將特定用戶的流量路由到金絲雀版本)。作為展示,讓我們看一下采用這種方式部署 helloworld 服務的簡單便捷。
首先我們定義 helloworld 服務,和普通 Kubernetes 服務一樣,如下所示:
apiVersion: v1
kind: Service
metadata:
name: helloworld
labels:
App: helloworld
spec:
selector:
app: helloworld
...
然后我們添加 2 個 Deployment,分別為版本 v1 和 v2,這兩個版本都包含服務選擇標簽 app:helloworld
kind: Deployment
metadata:
name: helloworld-v1
spec:
replicas: 1
template:
metadata:
labels:
app: helloworld
version: v1
spec:
containers:
- image: helloworld-v1
...
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: helloworld-v2
spec:
replicas: 1
template:
metadata:
labels:
app: helloworld
version: v2
spec:
containers:
- image: helloworld-v2
...
需要注意的是,這與使用普通 Kubernetes 進行[金絲雀部署]的方式完全相同,但是在 Kubernetes 方式下控制流量分配需要調整每個 Deployment 的副本數目。例如,將 10% 的流量發送到金絲雀版本(v2),v1 和 v2 的副本可以分別設置為 9 和 1。
但是在[啟用 Istio] 的集群中,我們可以通過設置路由規則來控制流量分配。如將 10% 的流量發送到金絲雀版本本,我們可以使用 kubectl 來設置以下的路由規則:
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: helloworld
spec:
hosts:
- helloworld
http:
- route:
- destination:
host: helloworld
subset: v1
weight: 90
- destination:
host: helloworld
subset: v2
weight: 10
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: helloworld
spec:
host: helloworld
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
EOF
當規則設置生效后,Istio 將確保只有 10% 的請求發送到金絲雀版本,無論每個版本的運行副本數量是多少。
以上是使用istio 進行的金絲雀部署,當然藍綠也是類似的。
spring cloud
spring cloud gateway也可以實現灰度發布,另外還有一款 spring cloud 的增強組件,可以實現灰度、藍綠等功能(Discovery: https://github.com/Nepxion/Discovery)
網關
利用云原生網關比如 APISIX :
- https://apisix.Apache.org/zh/docs/apisix/plugins/traffic-split/#藍綠發布
- https://apisix.apache.org/zh/docs/apisix/plugins/traffic-split/#灰度發布
參考
- https://cloud.tencent.com/developer/article/1835861
- https://www.infoq.cn/article/lei4vsfpiw5a6en-aso4
- https://zhuanlan.zhihu.com/p/42671353
- https://www.cnblogs.com/fulu/p/15648351.html
- https://tech.youzan.com/gray-deloyments-and-blue-green-deployments-practices-in-youzan/](https://tech.youzan.com/gray-deloyments-and-blue-green-deployments-practices-in-youzan/
- https://cloud.tencent.com/developer/article/1835861](https://cloud.tencent.com/developer/article/1835861
- https://istio.io/latest/zh/blog/2017/0.1-canary/
- https://www.zerchin.xyz/2020/08/10/K8s-1-18-6版本基于-ingress-nginx-實現金絲雀發布(灰度發布)
- https://www.cnblogs.com/Courage129/p/14498788.html
- https://cloud.tencent.com/developer/article/1620795