灰度發佈(又名金絲雀發佈)介紹api
當應用上線之後,運維面臨的一大挑戰是如何可以在不影響已上線業務的狀況下進行升級。作過產品的同窗都清楚,無論在發佈前作過多麼完備的自動化和人工測試,在發佈後都會出現或多或少的故障。根據墨菲定律,可能會出錯的版本發佈必定會出錯。瀏覽器
「ANYTHING THAN CAN GO WRONG WILL GO WRONG」 –MURPHY’S LAW服務器
所以咱們不能寄但願於在線下測試時發現全部潛在故障。在沒法百分百避免版本升級故障的狀況下,須要經過一種方式進行可控的版本發佈,把故障影響控制在能夠接受的範圍內,並能夠快速回退。cookie
能夠經過灰度發佈(又名金絲雀發佈)來實現業務從老版本到新版本的平滑過渡,並避免升級過程當中出現的問題對用戶形成的影響。網絡
「金絲雀發佈」的來源於礦工們用金絲雀對礦井進行空氣測試的作法。之前礦工挖煤的時候,礦工下礦井前會先把金絲雀放進去,或者挖煤的時候一直帶着金絲雀。金絲雀對甲烷和一氧化碳濃度比較敏感,會先報警。因此你們都用「金絲雀」來搞最早的測試。app
下圖中,左下方的少部分用戶就被看成「金絲雀」來用於測試新上線的1.1版本。若是新版本出現問題,「金絲雀」們會報警,但不會影響其餘用戶業務的正常運行。運維
灰度發佈(金絲雀發佈)的流程以下:ide
準備和生產環境隔離的「金絲雀」服務器。微服務
將新版本的服務部署到「金絲雀」服務器上。測試
對「金絲雀」服務器上的服務進行自動化和人工測試。
測試經過後,將「金絲雀」服務器鏈接到生產環境,將少許生產流量導入到「金絲雀」服務器中。
若是在線測試出現問題,則經過把生產流量從「金絲雀」服務器中從新路由到老版本的服務的方式進行回退,修復問題後從新進行發佈。
若是在線測試順利,則逐漸把生產流量按必定策略逐漸導入到新版本服務器中。
待新版本服務穩定運行後,刪除老版本服務。
從上面的流程能夠看到,若是要實現一套灰度發佈的流程,須要應用程序和運維流程對該發佈過程進行支持,工做量和難度的挑戰是很是大的。雖然面對的問題相似,但每一個企業或組織通常採用不一樣的私有化實現方案來進行灰度發佈,爲解決該問題致使研發和運維花費了大量的成本。
Istio經過高度的抽象和良好的設計採用一致的方式解決了該問題,採用sidecar對應用流量進行了轉發,經過Pilot下發路由規則,能夠在不修改應用程序的前提下實現應用的灰度發佈。
備註:採用kubernetes的滾動升級(rolling update)功能也能夠實現不中斷業務的應用升級,但滾動升級是經過逐漸使用新版本的服務來替換老版本服務的方式對應用進行升級,在滾動升級不能對應用的流量分發進行控制,所以沒法採用受控地把生產流量逐漸導流到新版本服務中,也就沒法控制服務升級對用戶形成的影響。
採用Istio後,能夠經過定製路由規則將特定的流量(如指定特徵的用戶)導入新版本服務中,在生產環境下進行測試,同時經過漸進受控地導入生產流量,能夠最小化升級中出現的故障對用戶的影響。而且在同時存在新老版本服務時,還可根據應用壓力對不一樣版本的服務進行獨立的縮擴容,很是靈活。採用Istio進行灰度發佈的流程以下圖所示:
下面採用Istion自帶的BookinfoInfo示例程序來試驗灰度發佈的流程。
首先參考手把手教你從零搭建Istio及Bookinfo示例程序安裝Kubernetes及Istio控制面。
由於本試驗並不須要安裝所有3個版本的reviews服務,所以若是已經安裝了該應用,先採用下面的命令卸載。
istio-0.2.10/samples/bookinfo/kube/cleanup.sh
首先只部署V1版本的Bookinfo應用程序。因爲示例中的yaml文件中包含了3個版本的reviews服務,咱們先將V2和V3版本的Deployment從yaml文件istio-0.2.10/samples/bookinfo/kube/bookinfo.yaml中刪除。
從Bookinfo.yaml中刪除這部份內容:
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: reviews-v2 spec: replicas: 1 template: metadata: labels: app: reviews version: v2 spec: containers: - name: reviews image: istio/examples-bookinfo-reviews-v2:0.2.3 imagePullPolicy: IfNotPresent ports: - containerPort: 9080 --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: reviews-v3 spec: replicas: 1 template: metadata: labels: app: reviews version: v3 spec: containers: - name: reviews image: istio/examples-bookinfo-reviews-v3:0.2.3 imagePullPolicy: IfNotPresent ports: - containerPort: 9080 ---
部署V1版本的Bookinfo程序。
kubectl apply -f <(istioctl kube-inject -f istio-0.2.10/samples/bookinfo/kube/bookinfo.yaml)
經過kubectl命令行確認pod部署,能夠看到只有V1版本的服務。
kubectl get pods NAME READY STATUS RESTARTS AGE details-v1-3688945616-nhkqk 2/2 Running 0 2m productpage-v1-2055622944-m3fql 2/2 Running 0 2m ratings-v1-233971408-0f3s9 2/2 Running 0 2m reviews-v1-1360980140-0zs9z 2/2 Running 0 2m
在瀏覽器中打開應用程序頁面,地址爲istio-ingress的External IP。因爲V1版本的reviews服務並不會調用rating服務,所以能夠看到Product 頁面顯示的是不帶星級的評價信息。
http://10.12.25.116/productpage
此時系統中微服務的部署狀況以下圖所示(下面的示意圖均忽略和本例關係不大的details和ratings服務):
在部署V2版本的reviews服務前,須要先建立一條缺省路由規則route-rule-default-reviews.yaml,將全部生產流量都導向V1版本,避免對線上用戶的影響。
apiVersion: config.istio.io/v1alpha2 kind: RouteRule metadata: name: reviews-default spec: destination: name: reviews precedence: 1 route: - labels: version: v1
啓用該路由規則。
istioctl create -f route-rule-default-reviews.yaml -n default
建立一個V2版本的部署文件bookinfo-reviews-v2.yaml,內容以下
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: reviews-v2 spec: replicas: 1 template: metadata: labels: app: reviews version: v2 spec: containers: - name: reviews image: istio/examples-bookinfo-reviews-v2:0.2.3 imagePullPolicy: IfNotPresent ports: - containerPort: 9080
部署V2版本的reviews服務。
kubectl apply -f <(istioctl kube-inject -f bookinfo-reviews-v2.yaml)
此時系統中部署了V1和V2兩個版本的reviews服務,但全部的業務流量都被規則reviews-default導向了V1,以下圖所示:
在進行模擬測試時,因爲測試環境和生產環境的網絡,服務器,操做系統等環境存在差別,很難徹底模擬生產環境進行測試。爲了減小環境因素的對測試結果的影響,咱們但願能在生產環境中進行上線前的測試,但若是沒有很好的隔離措施,可能會致使測試影響已上線的業務,對企業形成損失。
經過採用Istio的路由規則,能夠在類生產環境中進行測試,又徹底隔離了線上用戶的生產流量和測試流量,最小化模擬測試對已上線業務的影響。以下圖所示:
建立一條規則,將用戶名爲 test-user 的流量導入到V2
apiVersion: config.istio.io/v1alpha2 kind: RouteRule metadata: name: reviews-test-user spec: destination: name: reviews precedence: 2 match: request: headers: cookie: regex: "^(.*?;)?(user=test-user)(;.*)?$" route: - labels: version: v2
注意:precedence屬性用於設置規則的優先級,在同時存在多條規則的狀況下,優先級高的規則將先執行。這條規則的precedence設置爲2,以確保其在缺省規則以前運行,將test-user用戶的請求導流到V2版本reviews服務中。
啓用該規則。
istioctl create -f route-rule-test-reviews-v2.yaml -n default
以test-user用戶登陸,能夠看到V2版本帶星級的評價頁面。
註銷test-user,只能看到V1版本不帶星級的評價頁面。以下圖所示:
在線上模擬測試完成後,若是系統測試狀況良好,能夠經過規則將一部分用戶流量導入到V2版本的服務中,進行小規模的「金絲雀」測試。
修改規則route-rule-default-reviews.yaml,將50%的流量導入V2版本。
備註:本例只是描述原理,所以爲簡單起見,將50%流量導入V2版本,在實際操做中,更多是先導入較少流量,而後根據監控的新版本運行狀況將流量逐漸導入,如採用5%,10%,20%,50% …的比例逐漸導入。
apiVersion: config.istio.io/v1alpha2 kind: RouteRule metadata: name: reviews-default spec: destination: name: reviews precedence: 1 route: - labels: version: v1 weight: 50 - labels: version: v2 weight: 50
istioctl replace -f route-rule-default-reviews.yaml -n default
此時系統部署以下圖所示:
若是新版本的服務運行正常,則能夠將全部流量導入到V2版本。
apiVersion: config.istio.io/v1alpha2 kind: RouteRule metadata: name: reviews-default spec: destination: name: reviews precedence: 1 route: - labels: version: v2 weight: 100
istioctl replace -f route-rule-default-reviews.yaml -n default
系統部署以下圖所示:
此時無論以任何用戶登陸,都只能看到V2版本帶星級的評價頁面,以下圖所示:
備註:若是灰度發佈的過程當中新版本的服務出現問題,則能夠經過修改路由規則,將流量從新導入到V1版本的服務中,將V2版本故障修復後再進行測試。
待V2版本上線穩定運行後,刪除V1版本的reviews服務和測試規則。
kubectl delete pod reviews-v1-1360980140-0zs9z istioctl delete -f route-rule-test-reviews-v2.yaml -n default