Kubernetes 使用 Ingress-nginx 實現灰度釋出功能
使用 Ingress 實現灰度釋出
一、Canary 規則說明
Ingress-Nginx 是一個K8S ingress工具,支援配置 Ingress Annotations 來實現不同場景下的灰度釋出和測試( Ingress-Nginx 是在0.21.0 版本 中,引入的Canary 功能)。 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
我們可以把以上的四個 annotation 規則可以總體劃分為以下兩類:
- 基於權重的 Canary 規則:
- 基於使用者請求的 Canary 規則:
二、部署測試用例
1. 部署正式版本服務
首先建立一個 deployment 代表正式版本的服務,編寫 yaml 內容如下:
---
apiVersion: v1
kind: Namespace
metadata:
name: ns-myapp
labels:
name: ns-myapp
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: production
namespace: ns-myapp
spec:
replicas: 1
selector:
matchLabels:
app: production
template:
metadata:
labels:
app: production
spec:
containers:
- name: production
image: mirrorgooglecontainers/echoserver:1.10
ports:
- containerPort: 8080
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
---
apiVersion: v1
kind: Service
metadata:
name: production
namespace: ns-myapp
labels:
app: production
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: production
為這個服務建立 Ingress 路由規則,yaml 檔案內容如下:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: production
namespace: ns-myapp
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: ingress.test.com
http:
paths:
- backend:
serviceName: production
servicePort: 80
應用以上 yaml 檔案,建立完成後在 k8s 中檢視到如下資訊:
[k8s-master ~]# kubectl get ingress -n ns-myapp
NAME CLASS HOSTS ADDRESS PORTS AGE
production <none> ingress.test.com 10.16.13.201 80 4m25s
[k8s-master ~]# kubectl get pod -n ns-myapp
NAME READY STATUS RESTARTS AGE
production-5698c4565c-jmjn5 1/1 Running 0 7m11s
此時在命令列中訪問 ingress.test.com
可以看到如下內容:
# curl ingress.test.com
Hostname: production-5698c4565c-jmjn5
Pod Information:
node name: dumlog013201
pod name: production-5698c4565c-jmjn5
pod namespace: ns-myapp
pod IP: 10.42.0.74
Server values:
server_version=nginx: 1.13.3 - lua: 10008
Request Information:
client_address=10.16.13.201
method=GET
real path=/
query=
request_version=1.1
request_scheme=http
request_uri=http://ingress.test.com:8080/
Request Headers:
accept=*/*
host=ingress.test.com
user-agent=curl/7.64.1
x-forwarded-for=10.2.130.18
x-forwarded-host=ingress.test.com
x-forwarded-port=80
x-forwarded-proto=http
x-real-ip=10.2.130.18
x-request-id=3019362be59228ee2284f5737fa39eb1
x-scheme=http
Request Body:
-no body in request-
2. 部署 Canary 版本服務
接下來建立一個 Canary 版本的服務,用於作為灰度測試。
參考將上述 Production 版本的 production.yaml
檔案,再建立一個 Canary 版本的應用,包括一個 Canary 版本的 deployment
和 service
(為方便快速演示,僅需將 production.yaml
的 deployment 和 service 中的關鍵字 production
直接替換為 canary
,實際場景中可能涉及業務程式碼變更)。
三、基於權重的 Canary 規則測試
基於權重的流量切分的典型應用場景就是藍綠部署
,可通過將權重設定為 0 或 100 來實現。例如,可將 Green 版本設定為主要部分,並將 Blue 版本的入口配置為 Canary。最初,將權重設定為 0,因此不會將流量代理到 Blue 版本。一旦新版本測試和驗證都成功後,即可將 Blue 版本的權重設定為 100,即所有流量從 Green 版本轉向 Blue。
使用以下 canary.ingress
的 yaml 檔案再建立一個基於權重的 Canary 版本的應用路由 (Ingress)。
注意:要開啟灰度釋出機制,首先需設定
nginx.ingress.kubernetes.io/canary: "true"
啟用 Canary,以下 Ingress 示例的 Canary 版本使用了基於權重進行流量切分的 annotation 規則,將分配 30% 的流量請求傳送至 Canary 版本。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: canary
namespace: ns-myapp
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "30"
spec:
rules:
- host: ingress.test.com
http:
paths:
- backend:
serviceName: canary
servicePort: 80
接下來在命令列中使用如下命令訪問域名 ingress.test.com 100次,計算每個版本分配流量的佔比:
c=0;p=0;for i in $(seq 100); do result=$(curl -s ingress.test.com | grep Hostname | awk -F: '{print $2}'); [[ ${result} =~ ^[[:space:]]canary ]] && let c++ || let p++; done;echo "production:${p}; canary:${c};"
可以得到如下結果:
production:73; canary:28;
四、基於使用者請求的 Canary 規則測試
1. 基於 Resquest Header
基於 Request Header 進行流量切分的典型應用場景即灰度釋出或 A/B 測試場景
。
給 Canary 版本的 Ingress 新增一條 annotation :nginx.ingress.kubernetes.io/canary-by-header: canary
(這裡的 annotation 的 value 可以是任意值),使當前的 Ingress 實現基於 Request Header 進行流量切分。
將 Canary 版本 Ingress 的 yaml 檔案修改為如下內容:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: canary
namespace: ns-myapp
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "30"
nginx.ingress.kubernetes.io/canary-by-header: "canary"
spec:
rules:
- host: ingress.test.com
http:
paths:
- backend:
serviceName: canary
servicePort: 80
說明:金絲雀規則按優先順序
canary-by-header - > canary-by-cookie - > canary-weight
進行如下排序,因此上面的 ingress 將忽略原有 canary-weight 的規則。
由於上面的 ingress 規則中沒有對 canary-by-header: "canary"
提供具體的值,也就是 nginx.ingress.kubernetes.io/canary-by-header-value
規則,所以在訪問的時候,只可以為 canary
賦值 never
或 always
,當 header 資訊為 canary:never
時,請求將不會傳送到 canary 版本;當 header 資訊為 canary:always
時,請求將會一直髮送到 canary 版本。示例如下:
[k8s-master ~ ]# curl -s -H "canary:never" ingress.test.com | grep Hostname
Hostname: production-5698c4565c-jmjn5
[k8s-master ~ ]# curl -s -H "canary:always" ingress.test.com | grep Hostname
Hostname: canary-79c899d85-992nw
也可以在上一個 annotation (即 canary-by-header)的基礎上新增一條 nginx.ingress.kubernetes.io/canary-by-header-value: user-value
。用於通知 Ingress 將匹配到的請求路由到 Canary Ingress 中指定的服務。
將 Canary 版本 Ingress 的 yaml 檔案修改為如下內容:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: canary
namespace: ns-myapp
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "30"
nginx.ingress.kubernetes.io/canary-by-header: "canary"
nginx.ingress.kubernetes.io/canary-by-header-value: "true"
spec:
rules:
- host: ingress.test.com
http:
paths:
- backend:
serviceName: canary
servicePort: 80
上面的 ingress 規則設定了 header 資訊為 canary:true
,也就是隻有滿足這個 header 值時才會路由到 canary 版本。示例如下:
[k8s-master ~ ]# curl -s ingress.test.com | grep Hostname
Hostname: production-5698c4565c-jmjn5
[k8s-master ~ ]# curl -s -H "canary:test" ingress.test.com | grep Hostname
Hostname: production-5698c4565c-jmjn5
[k8s-master ~ ]# curl -s -H "canary:true" ingress.test.com | grep Hostname
Hostname: canary-79c899d85-992nw
五、基於 Cookie 的 Canary 規則測試
與基於 Request Header 的 annotation 用法規則類似。例如在 A/B 測試場景
下,需要讓地域為北京的使用者訪問 Canary 版本。那麼當 cookie 的 annotation 設定為 nginx.ingress.kubernetes.io/canary-by-cookie: "users_from_Beijing"
,此時後臺可對登入的使用者請求進行檢查,如果該使用者訪問源來自北京則設定 cookieusers_from_Beijing
的值為 always
,這樣就可以確保北京的使用者僅訪問 Canary 版本。
將 Canary 版本 Ingress 的 yaml 檔案修改為如下內容:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: canary
namespace: ns-myapp
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-cookie: "user_from_beijing"
spec:
rules:
- host: ingress.test.com
http:
paths:
- backend:
serviceName: canary
servicePort: 80
訪問示例如下:
[k8s-master ~ ]# curl -s -b "user_from_beijing=always" ingress.test.com | grep Hostname
Hostname: canary-79c899d85-992nw
[k8s-master ~ ]# curl -s -b "user_from_beijing=no" ingress.test.com | grep Hostname
Hostname: production-5698c4565c-jmjn5
相關文章
- 使用 Nginx Ingress 實現金絲雀釋出/灰度釋出Nginx
- 乾貨分享|使用 Istio 實現灰度釋出
- nginx 實現實用的灰度釋出Nginx
- 如何實現灰度釋出輕量化?
- Kubernetes Ingress-nginx使用Nginx
- nginx+lua+redis實現灰度釋出NginxRedis
- 阿里雲基於ALB實現灰度釋出阿里
- 如何用istio實現應用的灰度釋出
- F5與Openshift整合,實現灰度釋出
- SpringCloud 應用在 Kubernetes 上的最佳實踐 — 線上釋出(可灰度)SpringGCCloud
- 一鍵實現自動化部署(灰度釋出)實踐
- CODING DevOps + Nginx-ingress 實現自動化灰度釋出devNginx
- GitLab整合kubernetes實現自動釋出Gitlab
- 架構設計:微服務模式下,實現灰度釋出模式架構微服務模式
- 灰度釋出的一種技術實踐
- Vue + Webpack 灰度釋出控制VueWeb
- mse~路由實現某個頁面的灰度功能路由
- Vue 灰度釋出新功能的那些事Vue
- 使用Kubernetes演示金絲雀釋出
- 基於 Istio 的灰度釋出架構方案實踐之路架構
- 分散式全鏈路灰度釋出的探索與實踐分散式
- 使用 JuiceFS 快照功能實現資料庫釋出與端到端測試UI資料庫
- kubernetes實踐之六十六:Istio實現金絲雀釋出原理
- 基於Nodejs的前端灰度釋出方案_20190228NodeJS前端
- Spring Cloud Alibaba Nacos 之 灰度釋出(思路分享)SpringCloud
- 關於灰度釋出,你得知道這些......
- Kubernetes 1.25正式釋出!
- k8s-服務網格實戰-配置 Mesh(灰度釋出)K8S
- Knativa 基於流量的灰度釋出和自動彈性實踐
- 手把手教你在 TKE 叢集中實現簡單的藍綠髮布和灰度釋出
- 基於Kubernetes實現前後端應用的金絲雀釋出後端
- 非技術探討:文章定時釋出功能如何實現
- 大規模微服務場景下灰度釋出與流量染色實踐微服務
- [原創]淺談我們需要灰度釋出嗎?
- HHDESK新功能釋出,歡迎大家使用
- 基於DotNetty實現自動釋出 - 實現一鍵打包釋出Netty
- 使用Kubernetes-Jenkins實現CI/CDJenkins
- 使用Devtron在Kubernetes上實現GitOpsdevGit