本篇已加入《.NET Core on K8S學習實踐系列文章索引》,可以點擊查看更多容器化技術相關系列文章。
之前一篇介紹了Ingress的基本概念和Nginx Ingress的基本配置和使用,本篇繼續Ingress的使用,來看看如何使用Ingress實現灰度發布(金絲雀發布)。此外,我也有錄制一個10min+的小視頻介紹藍綠發布和金絲雀發布的基本概念,視頻入口點擊這里。
一、准備工作
1.1 WebAPI項目准備
首先,我們還是准備兩個版本的ASP.NET Core WebAPI項目,具體項目代碼參見這里。
他們之間的差別在於一個接口的返回JSON數據,比如V1.0版本中返回的是Version: 1.0,而V1.1版本中返回的是Version:1.1。
[Route("api/[controller]")] [ApiController] public class HomeController : ControllerBase { // GET api/home [HttpGet] public ActionResult<IEnumerable<string>> Get() { return new string[] { "Hello, welcome to EDC's demo. Version: 1.0" }; } }
運行結果為:
(2)將此項目各個版本根據Dockerfile打成鏡像,分別是xilife/canary-api-demo:1.0,1.1。
(3)將本地鏡像push到遠程鏡像倉庫,這里我傳送到了docker hub的一個公共倉庫里邊:
docker push xilife/canary-api-demo:1.0 docker push xilife/canary-api-demo:1.1
1.2 WebAPI項目部署
其次,我們將這兩個WebAPI項目部署到K8s集群中,還是通過熟悉的yaml文件來將其部署為Service:
(1)V1.0版本(假設為線上版本)
apiVersion: apps/v1 kind: Deployment metadata: name: canary-api-demo namespace: xdp-poc labels: name: canary-api-demo spec: replicas: 2 selector: matchLabels: name: canary-api-demo template: metadata: labels: name: canary-api-demo spec: containers: - name: canary-api-demo image: xilife/canary-api-demo:1.0 ports: - containerPort: 80 imagePullPolicy: IfNotPresent --- kind: Service apiVersion: v1 metadata: name: canary-api-svc namespace: xdp-poc spec: type: NodePort ports: - port: 80 targetPort: 80 selector: name: canary-api-demo
(2)V1.1版本(假設為灰度版本)
apiVersion: apps/v1 kind: Deployment metadata: name: canary-api-demo-gray namespace: xdp-poc labels: name: canary-api-demo-gray spec: replicas: 2 selector: matchLabels: name: canary-api-demo-gray template: metadata: labels: name: canary-api-demo-gray spec: containers: - name: canary-api-demo-gray image: xilife/canary-api-demo:1.1 ports: - containerPort: 80 imagePullPolicy: IfNotPresent --- kind: Service apiVersion: v1 metadata: name: canary-api-svc-gray namespace: xdp-poc spec: type: NodePort ports: - port: 80 targetPort: 80 selector: name: canary-api-demo-gray
將這兩個應用部署至K8s集群:
kubectl apply -f deploy-canary-api-svc.yml
kubectl apply -f deploy-canary-api-gray-svc.yml
二、Ingress灰度發布應用
Ingress-Nginx 支持配置 Ingress Annotations 來實現不同場景下的灰度發布和測試,可以滿足金絲雀發布、藍綠部署與 A/B 測試等業務場景。
因此我們准備兩個版本的Ingress的yml文件,它提供了兩種方式:
一是基於用戶請求的流量切分,具體又包括了基於Request Header的流量切分與基於Cookie的流量切分兩種方式;如下圖所示:
二是基於服務權重的流量切分;如下圖所示:
2.1 基於Request Header的流量切分方式
根據Request Header的流量切分方式的約定,適用於灰度發布及A/B測試。當 Request Header 設置為 always時,請求將會被一直發送到 Canary 版本;當 Request Header 設置為 never時,請求不會被發送到 Canary 入口;對於任何其他 Header 值,將忽略 Header,並通過優先級將請求與其他金絲雀規則進行優先級的比較。
為1.0版本准備一個Ingress,讓它先工作着:
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: nginx-ingress namespace: xdp-poc annotations: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/rewrite-target: /api/$2 spec: rules: - host: portal.k8s.xi-life.cn http: paths: - path: /api(/|$)(.*) backend: serviceName: canary-api-svc servicePort: 80
應用至K8s集群:
kubectl apply -f ingress-nginx.yaml
再為1.1版本准備一個Ingress,讓它作為灰度版本的入口逐步替換原v1版本的流量接入:
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: nginx-ingress-gray namespace: xdp-poc annotations: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/rewrite-target: /api/$2 nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-by-header: "canary" nginx.ingress.kubernetes.io/canary-by-header-value: "true" spec: rules: - host: portal.k8s.xi-life.cn http: paths: - path: /api(/|$)(.*) backend: serviceName: canary-api-svc-gray servicePort: 80
應用至K8s集群:
kubectl apply -f ingress-nginx-gray.yaml
快速驗證:
2.2 基於Cookie的流量切分方式
根據基於 Cookie 的流量切分方式的約定,當 Cookie 值設置為 always時,它將被路由到 Canary 入口;當 Cookie 值設置為 never時,請求不會被發送到 Canary 入口;對於任何其他值,將忽略 Cookie 並將請求與其他金絲雀規則進行優先級的比較。
為灰度版本准備Ingress:
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: nginx-ingress-gray namespace: xdp-poc annotations: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/proxy-body-size: "100m" nginx.ingress.kubernetes.io/limit-rps: '10' nginx.ingress.kubernetes.io/rewrite-target: /api/$2 nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-by-cookie: "xdp-v2-cookie" spec: rules: - host: portal.k8s.xi-life.cn http: paths: - path: /api(/|$)(.*) backend: serviceName: canary-api-svc-gray servicePort: 80
應用至K8s集群:
kubectl apply -f ingress-nginx-gray.yaml
快速驗證:
(1)未添加Cookie
(2)為要訪問的域名添加一個Cookie
(3)再次請求驗證
2.3 基於服務權重的流量切分方式
根據基於服務權重的流量切分方式的約定,適用於藍綠部署,權重范圍 0 - 100 按百分比將請求路由到 Canary Ingress 中指定的服務。權重為 0 意味着該金絲雀規則不會向 Canary 入口的服務發送任何請求。權重為 100 意味着所有請求都將被發送到 Canary 入口。
為灰度版本准備Ingress:
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: nginx-ingress-gray namespace: xdp-poc annotations: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/proxy-body-size: "100m" nginx.ingress.kubernetes.io/limit-rps: '10' nginx.ingress.kubernetes.io/rewrite-target: /api/$2 nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-weight: "50" spec: rules: - host: portal.k8s.xi-life.cn http: paths: - path: /api(/|$)(.*) backend: serviceName: canary-api-svc-gray servicePort: 80
應用至K8s集群:
kubectl apply -f ingress-nginx-gray.yaml
快速驗證:這里我直接通過瀏覽器來測試,需要注意的是這里的50%是一個近似分布值,可能實際中不會太精確。
三、三種方式的對比
canary-by-header -> canary-by-cookie -> canary-weight
四、小結
本文介紹了Nginx Ingress提供的三種灰度發布(canary)的方式,然后介紹了如何使用Nginx Ingress並進行配置實現ASP.NET Core WebAPI應用服務的灰度發布實踐,最后對比三種方式的優先級及限制,希望對你有所幫助。
參考資料
(1)JadePeng,《K8s基於Nginx Ingress實現灰度發布》
(2)我的小碗湯,《Nginx Ingress實現灰度和金絲雀發布》
(3)梁寬,《再也不踩坑的K8s實戰指南》
(4)WangT,《K8s基於Nginx Ingress進行藍綠部署/金絲雀發布》
(5)linus.lin,《一文明白藍綠部署、滾動部署、灰度發布、金絲雀發布》