一、理論:實(shí)現(xiàn)灰度發(fā)布的幾種場(chǎng)景
1、場(chǎng)景一:將新版本灰度給部分用戶
假設(shè)線上運(yùn)行了一套對(duì)外提供 7 層服務(wù)的 Service A 服務(wù),后來(lái)開(kāi)發(fā)了個(gè)新版本 Service AA需要上線,但不想直接替換掉原來(lái)的 Service A,希望先灰度一小部分用戶,等運(yùn)行一段時(shí)間足夠穩(wěn)定了再逐漸全量上線新版本,最后平滑下線舊版本。
這個(gè)時(shí)候就可以利用 Nginx Ingress 基于 Header 或 Cookie 進(jìn)行流量切分的策略來(lái)發(fā)布,業(yè)務(wù)使用 Header 或 Cookie 來(lái)標(biāo)識(shí)不同類型的用戶,我們通過(guò)配置 Ingress 來(lái)實(shí)現(xiàn)讓帶有指定 Header 或 Cookie 的請(qǐng)求被轉(zhuǎn)發(fā)到新版本,其它的仍然轉(zhuǎn)發(fā)到舊版本,從而實(shí)現(xiàn)將新版本灰度給部分用戶。
2、場(chǎng)景二:按照比例流程給新版本
假設(shè)線上運(yùn)行了一套對(duì)外提供 7 層服務(wù)的 Service B 服務(wù),后來(lái)修復(fù)了一些問(wèn)題,需要灰度上線一個(gè)新版本 Service BB,但又不想直接替換掉原來(lái)的 Service B而是讓先切 10% 的流量到新版本。
等觀察一段時(shí)間穩(wěn)定后再逐漸加大新版本的流量比例直至完全替換舊版本,最后再滑下線舊版本,從而實(shí)現(xiàn)切一定比例的流量給新版本。
3、實(shí)現(xiàn)灰度發(fā)布字段解釋
Ingress-Nginx是一個(gè)K8S ingress工具,支持配置Ingress Annotations來(lái)實(shí)現(xiàn)不同場(chǎng)景下的灰度發(fā)布和測(cè)試。 Nginx Annotations 支持以下幾種Canary規(guī)則:
假設(shè)我們現(xiàn)在部署了兩個(gè)版本的服務(wù),老版本和canary版本
-
nginx.ingress.kubernetes.io/canary-by-header:基于Request Header的流量切分,適用于灰度發(fā)布以及 A/B 測(cè)試。當(dāng)Request Header 設(shè)置為 always時(shí),請(qǐng)求將會(huì)被一直發(fā)送到 Canary 版本;當(dāng) Request Header 設(shè)置為 never時(shí),請(qǐng)求不會(huì)被發(fā)送到 Canary 入口。
-
nginx.ingress.kubernetes.io/canary-by-header-value:要匹配的 Request Header 的值,用于通知 Ingress 將請(qǐng)求路由到 Canary Ingress 中指定的服務(wù)。當(dāng) Request Header 設(shè)置為此值時(shí),它將被路由到 Canary 入口。
-
nginx.ingress.kubernetes.io/canary-weight:基于服務(wù)權(quán)重的流量切分,適用于藍(lán)綠部署,權(quán)重范圍 0 - 100 按百分比將請(qǐng)求路由到 Canary Ingress 中指定的服務(wù)。權(quán)重為 0 意味著該金絲雀規(guī)則不會(huì)向 Canary 入口的服務(wù)發(fā)送任何請(qǐng)求。權(quán)重為60意味著60%流量轉(zhuǎn)到canary。權(quán)重為 100 意味著所有請(qǐng)求都將被發(fā)送到 Canary 入口。
-
nginx.ingress.kubernetes.io/canary-by-cookie:基于 Cookie 的流量切分,適用于灰度發(fā)布與 A/B 測(cè)試。用于通知 Ingress 將請(qǐng)求路由到 Canary Ingress 中指定的服務(wù)的cookie。當(dāng) cookie 值設(shè)置為 always時(shí),它將被路由到 Canary 入口;當(dāng) cookie 值設(shè)置為 never時(shí),請(qǐng)求不會(huì)被發(fā)送到 Canary 入口。
二、實(shí)踐:
1、實(shí)驗(yàn)前提環(huán)境
1、增加V1環(huán)境:
cat v1.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-v1
spec:
replicas: 1
selector:
matchLabels:
app: nginx
version: v1
template:
metadata:
labels:
app: nginx
version: v1
spec:
containers:
- name: nginx
image: "openresty/openresty:centos"
imagePullPolicy: IfNotPresent
ports:
- name: http
protocol: TCP
containerPort: 80
volumeMounts: # 掛載卷
- mountPath: /usr/local/openresty/nginx/conf/nginx.conf
name: config
subPath: nginx.conf
volumes: # 定義卷,引用configMap
- name: config
configMap:
name: nginx-v1
---
apiVersion: v1
kind: ConfigMap
metadata:
labels:
app: nginx
version: v1
name: nginx-v1
data:
nginx.conf: |-
worker_processes 1;
events {
accept_mutex on;
multi_accept on;
use epoll;
worker_connections 1024;
}
http {
ignore_invalid_headers off;
server {
listen 80;
location / {
access_by_lua '
local header_str = ngx.say("nginx-v1")
';
}
}
}
---
apiVersion: v1
kind: Service
metadata:
name: nginx-v1
spec:
type: ClusterIP
ports:
- port: 80
protocol: TCP
name: http
selector:
app: nginx
version: v1
2、增加V2環(huán)境:
cat v2.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-v2
spec:
replicas: 1
selector:
matchLabels:
app: nginx
version: v2
template:
metadata:
labels:
app: nginx
version: v2
spec:
containers:
- name: nginx
image: "openresty/openresty:centos"
imagePullPolicy: IfNotPresent
ports:
- name: http
protocol: TCP
containerPort: 80
volumeMounts:
- mountPath: /usr/local/openresty/nginx/conf/nginx.conf
name: config
subPath: nginx.conf
volumes:
- name: config
configMap:
name: nginx-v2
---
apiVersion: v1
kind: ConfigMap
metadata:
labels:
app: nginx
version: v2
name: nginx-v2
data:
nginx.conf: |-
worker_processes 1;
events {
accept_mutex on;
multi_accept on;
use epoll;
worker_connections 1024;
}
http {
ignore_invalid_headers off;
server {
listen 80;
location / {
access_by_lua '
local header_str = ngx.say("nginx-v2")
';
}
}
}
---
apiVersion: v1
kind: Service
metadata:
name: nginx-v2
spec:
type: ClusterIP
ports:
- port: 80
protocol: TCP
name: http
selector:
app: nginx
version: v2
3、執(zhí)行YAML文件
kubectl apply -f v1.yaml
kubectl apply -f v2.yaml
4、驗(yàn)證Pod是啟動(dòng)
kubectl get pods -o wide
5、驗(yàn)證,請(qǐng)求Pod內(nèi)容
curl http://10.244.247.2
curl http://10.244.84.134
如上圖,請(qǐng)求不同版本的環(huán)境,返回不同版本號(hào),表示無(wú)誤。
2、基于Request Header(請(qǐng)求頭)進(jìn)行流量分割
1、創(chuàng)建v1版本的ingress規(guī)則
cat v1-ingress.yaml
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-v1
spec:
ingressClassName: nginx
rules:
- host: qinzt.ingress.com
http:
paths:
- path: / #配置訪問(wèn)路徑,如果通過(guò)url進(jìn)行轉(zhuǎn)發(fā),需要修改;空默認(rèn)為訪問(wèn)的路徑為"/"
pathType: Prefix
backend: #配置后端服務(wù)
service:
name: nginx-v1
port:
number: 80
執(zhí)行YAML文件:
kubectl apply -f v1-ingress.yaml
訪問(wèn)驗(yàn)證一下:16.32.15.201:30080
是我ingress-nginx訪問(wèn)地址
curl -H "Host: qinzt.ingress.com" http://16.32.15.201:30080
nginx-v1
2、創(chuàng)建ingress規(guī)則,基于Request Header進(jìn)行流量分割
cat v2-request.yaml
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "Region" #基于Request Header的流量切分
nginx.ingress.kubernetes.io/canary-by-header-pattern: "cd|sz" #Header信息中帶有 Region=cd,Region=sz的轉(zhuǎn)發(fā)到此ingress
name: nginx-request-v2
spec:
ingressClassName: nginx
rules:
- host: qinzt.ingress.com
http:
paths:
- path: / #配置訪問(wèn)路徑,如果通過(guò)url進(jìn)行轉(zhuǎn)發(fā),需要修改;空默認(rèn)為訪問(wèn)的路徑為"/"
pathType: Prefix
backend: #配置后端服務(wù)
service:
name: nginx-v2
port:
number: 80
執(zhí)行YAML文件:
kubectl apply -f v2-request.yaml
訪問(wèn)驗(yàn)證一下:16.32.15.201:30080
是我ingress-nginx訪問(wèn)地址
curl -H "Host: qinzt.ingress.com" -H "Region: cd" http://16.32.15.201:30080
curl -H "Host: qinzt.ingress.com" -H "Region: sz" http://16.32.15.201:30080
OK,可以看到上圖,攜帶Region: cd
、Region: sz
請(qǐng)求頭消息,會(huì)轉(zhuǎn)發(fā)到V2環(huán)境。
3、基于Cookie進(jìn)行流量切分
與前面 Header 類似,不過(guò)使用 Cookie 就無(wú)法自定義 value 了,這里以模擬灰度成都地域用戶為例,僅將帶有名為 user_from_cd
的 cookie 的請(qǐng)求轉(zhuǎn)發(fā)給當(dāng)前V2環(huán)境 。
1、先刪除前面基于 Header 的流量切分的 Ingress
kubectl delete -f v2-request.yaml
2、創(chuàng)建基于cookie 轉(zhuǎn)發(fā)的ingress規(guī)則
cat v2-cookie.yaml
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-cookie: "user_from_cd" # 匹配cookie攜帶user_from_cd,使用此ingress規(guī)則
name: nginx-cookie-v2
spec:
ingressClassName: nginx
rules:
- host: qinzt.ingress.com
http:
paths:
- path: / #配置訪問(wèn)路徑,如果通過(guò)url進(jìn)行轉(zhuǎn)發(fā),需要修改;空默認(rèn)為訪問(wèn)的路徑為"/"
pathType: Prefix
backend: #配置后端服務(wù)
service:
name: nginx-v2
port:
number: 80
執(zhí)行YAML文件
kubectl apply -f v2-cookie.yaml
3、測(cè)試驗(yàn)證,http://16.32.15.201:30080
是我ingress nginx地址
curl -s -H "Host: qinzt.ingress.com" --cookie "user_from_cd=always" http://16.32.15.201:30080
nginx-v2
curl -s -H "Host: qinzt.ingress.com" --cookie "user_from_bj=always" http://16.32.15.201:30080
nginx-v1
可以看到只有cookie=user_from_cd
的才會(huì)轉(zhuǎn)發(fā)到V2的ingress
4、基于服務(wù)權(quán)重進(jìn)行流量切分
基于服務(wù)權(quán)重的直接定義需要導(dǎo)入的流量比例,這里以導(dǎo)入 10% 流量到 v2 環(huán)境版本為。
1、刪除上面基于cookie的ingress規(guī)則
kubectl delete -f v2-cookie.yaml
2、創(chuàng)建基于權(quán)重流量分配的ingress規(guī)則
cat v2-weight.yaml
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"
name: nginx-weight-v2
spec:
ingressClassName: nginx
rules:
- host: qinzt.ingress.com
http:
paths:
- path: / #配置訪問(wèn)路徑,如果通過(guò)url進(jìn)行轉(zhuǎn)發(fā),需要修改;空默認(rèn)為訪問(wèn)的路徑為"/"
pathType: Prefix
backend: #配置后端服務(wù)
service:
name: nginx-v2
port:
number: 80
執(zhí)行YAML文件:
kubectl apply -f v2-weight.yaml
3、測(cè)試驗(yàn)證
for i in {1..10}; do curl -H "Host: qinzt.ingress.com" http://16.32.15.201:30080; done;
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-605998.html
OK,如上圖大約10%的記錄會(huì)請(qǐng)求到V2環(huán)境上面文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-605998.html
到了這里,關(guān)于【Kubernetes運(yùn)維篇】ingress-nginx實(shí)現(xiàn)業(yè)務(wù)灰度發(fā)布詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!