日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
如何通過(guò) Ingress-Nginx 實(shí)現(xiàn)應(yīng)用灰度發(fā)布?

大家好,我是喬克。

成都創(chuàng)新互聯(lián)主要從事成都網(wǎng)站制作、做網(wǎng)站、外貿(mào)營(yíng)銷(xiāo)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)房縣,十多年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專(zhuān)業(yè),歡迎來(lái)電咨詢建站服務(wù):13518219792

今天是元宵,祝大家元宵節(jié)快樂(lè)!

在日常的工作中,我們會(huì)經(jīng)常對(duì)應(yīng)用進(jìn)行發(fā)版升級(jí),在互聯(lián)網(wǎng)公司尤為頻繁,主要是為了滿足快速的業(yè)務(wù)發(fā)展。我們經(jīng)常用到的發(fā)布方式有滾動(dòng)更新、藍(lán)綠發(fā)布、灰度發(fā)布。

  • 滾動(dòng)更新:依次進(jìn)行新舊替換,直到舊的全部被替換為止。
  • 藍(lán)綠發(fā)布:兩套獨(dú)立的系統(tǒng),對(duì)外提供服務(wù)的稱(chēng)為綠系統(tǒng),待上線的服務(wù)稱(chēng)為藍(lán)系統(tǒng),當(dāng)藍(lán)系統(tǒng)里面的應(yīng)用測(cè)試完成后,用戶流量接入藍(lán)系統(tǒng),藍(lán)系統(tǒng)將稱(chēng)為綠系統(tǒng),以前的綠系統(tǒng)就可以銷(xiāo)毀。
  • 灰度發(fā)布:在一套集群中存在穩(wěn)定和灰度兩個(gè)版本,灰度版本可以限制只針對(duì)部分人員可用,待灰度版本測(cè)試完成后,可以將灰度版本升級(jí)為穩(wěn)定版本,舊的穩(wěn)定版本就可以下線了,我們也稱(chēng)之為金絲雀發(fā)布。

這里主要給大家分享如果通過(guò)ingress-nginx controller實(shí)現(xiàn)灰度發(fā)布。

本文大綱如下。

如何通過(guò)ingress-nginx實(shí)現(xiàn)灰度發(fā)布

ingress-nginx是Kubernetes官方推薦的ingress controller,它是基于nginx實(shí)現(xiàn)的,增加了一組用于實(shí)現(xiàn)額外功能的Lua插件。

為了實(shí)現(xiàn)灰度發(fā)布,ingress-nginx通過(guò)定義annotation來(lái)實(shí)現(xiàn)不同場(chǎng)景的灰度發(fā)布,其支持的規(guī)則如下:

  • 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 入口;對(duì)于任何其他 Header 值,將忽略 Header,并通過(guò)優(yōu)先級(jí)將請(qǐng)求與其他金絲雀規(guī)則進(jìn)行優(yōu)先級(jí)的比較。
  • nginx.ingress.kubernetes.io/canary-by-header-value:要匹配的 Request Header 的值,用于通知 Ingress 將請(qǐng)求路由到 Canary Ingress 中指定的服務(wù)。當(dāng) Request Header 設(shè)置為此值時(shí),它將被路由到 Canary 入口。該規(guī)則允許用戶自定義 Request Header 的值,必須與上一個(gè) annotation (即:canary-by-header)一起使用。
  • 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)重為 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 入口;對(duì)于任何其他值,將忽略 cookie 并將請(qǐng)求與其他金絲雀規(guī)則進(jìn)行優(yōu)先級(jí)的比較。

我們也是通過(guò)上面的annotation來(lái)實(shí)現(xiàn)灰度發(fā)布,其思路如下:

在集群中部署兩套系統(tǒng),一套是stable版本,一套是canary版本,兩個(gè)版本都有自己的service

定義兩個(gè)ingress配置,一個(gè)正常提供服務(wù),一個(gè)增加canary的annotation

待canary版本無(wú)誤后,將其切換成stable版本,并且將舊的版本下線,流量全部接入新的stable版本

發(fā)布場(chǎng)景介紹

上面介紹了ingress-nginx實(shí)現(xiàn)灰度發(fā)布的方法以及咱們自己的實(shí)現(xiàn)思路,這里來(lái)探討一下灰度發(fā)布有哪些發(fā)布場(chǎng)景。

基于權(quán)重的發(fā)布場(chǎng)景

假如在生產(chǎn)上已經(jīng)運(yùn)行了A應(yīng)用對(duì)外提供服務(wù),此時(shí)開(kāi)發(fā)修復(fù)了一些Bug,需要發(fā)布A2版本將其上線,但是我們又不希望直接的將所有流量接入到新的A2版本,而是希望將10%的流量進(jìn)入到A2中,待A2穩(wěn)定后,才會(huì)將所有流量接入進(jìn)來(lái),再下線原來(lái)的A版本。

image.png

要實(shí)現(xiàn)這種,只需要在canary的ingress中添加如下annotation。

nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"



其中nginx.ingress.kubernetes.io/canary表示開(kāi)啟canary,nginx.ingress.kubernetes.io/canary-weight表示我們?cè)O(shè)置的權(quán)重大小。

基于用戶請(qǐng)求的發(fā)布場(chǎng)景

基于權(quán)重的發(fā)布場(chǎng)景比較粗糙,它是所有用戶中的20%,無(wú)法限制具體的用戶。

我們有時(shí)候會(huì)有這樣的需求,比如我們有廣東、北京、四川這三個(gè)地區(qū)的用戶,并且已經(jīng)有A版本的應(yīng)用為這三個(gè)地區(qū)提供服務(wù),由于更新了需求,我們需要發(fā)布A2應(yīng)用,但是我們不想所有地區(qū)都訪問(wèn)A2應(yīng)用,而是希望只有四川的用戶可以訪問(wèn),待四川地區(qū)反饋沒(méi)問(wèn)題后,才開(kāi)放其他地區(qū)。

image.png

對(duì)于這種我們需要在canary的ingress中添加如下annotation。

nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "region"
nginx.ingress.kubernetes.io/canary-by-header-value: "sichuan"



主要就是上面兩種發(fā)布場(chǎng)景,下面會(huì)針對(duì)這兩種場(chǎng)景分別進(jìn)行實(shí)驗(yàn)。

灰度發(fā)布具體實(shí)現(xiàn)

我這里準(zhǔn)備了兩個(gè)鏡像,一個(gè)是穩(wěn)定stable版本,一個(gè)是灰度canary版本。

  • registry.cn-hangzhou.aliyuncs.com/rookieops/go-test:v1
  • registry.cn-hangzhou.aliyuncs.com/rookieops/go-test:v2

由于兩個(gè)場(chǎng)景只有在ingress處的配置不一致,其他都一樣的,所以這里先將兩個(gè)版本的應(yīng)用都部署好。

(1)stable版本

apiVersion: apps/v1 
kind: Deployment
metadata:
name: app-server-stable
spec:
selector:
matchLabels:
app: go-test
version: stable
replicas: 1
template:
metadata:
labels:
app: go-test
version: stable
spec:
containers:
- name: app-server
image: registry.cn-hangzhou.aliyuncs.com/rookieops/go-test:v1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: app-server-stable-svc
spec:
selector:
app: go-test
version: stable
ports:
- name: http
port: 8080

訪問(wèn)效果如下:

# curl 10.97.112.137:8080
{"data":"hello world","version":"v1"}

(2)canary版本

apiVersion: apps/v1 
kind: Deployment
metadata:
name: app-server-canary
spec:
selector:
matchLabels:
app: go-test
version: canary
replicas: 1
template:
metadata:
labels:
app: go-test
version: canary
spec:
containers:
- name: app-server
image: registry.cn-hangzhou.aliyuncs.com/rookieops/go-test:v2
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: app-server-canary-svc
spec:
selector:
app: go-test
version: canary
ports:
- name: http
port: 8080

訪問(wèn)效果如下:

# curl 10.110.178.174:8080
{"data":"hello SB","version":"v2"}

上面已經(jīng)將應(yīng)用部署好了,下面將針對(duì)權(quán)重和用戶請(qǐng)求兩個(gè)場(chǎng)景進(jìn)行測(cè)試。

基于權(quán)重的發(fā)布場(chǎng)景

(1)配置stable版本的ingress

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: app-server-stable-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: joker.coolops.cn
http:
paths:
- path:
backend:
serviceName: app-server-stable-svc
servicePort: 8080

(2)配置canary版本的ingress

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: app-server-canary-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
rules:
- host: joker.coolops.cn
http:
paths:
- path:
backend:
serviceName: app-server-canary-svc
servicePort: 8080

然后我們通過(guò)訪問(wèn)測(cè)試,效果如下:

# curl joker.coolops.cn
{"data":"hello world","version":"v1"}
# curl joker.coolops.cn
{"data":"hello world","version":"v1"}
# curl joker.coolops.cn
{"data":"hello world","version":"v1"}
# curl joker.coolops.cn
{"data":"hello world","version":"v1"}
# curl joker.coolops.cn
{"data":"hello world","version":"v1"}
# curl joker.coolops.cn
{"data":"hello world","version":"v1"}
# curl joker.coolops.cn
{"data":"hello world","version":"v1"}
# curl joker.coolops.cn
{"data":"hello world","version":"v1"}
# curl joker.coolops.cn
{"data":"hello SB","version":"v2"}
# curl joker.coolops.cn
{"data":"hello world","version":"v1"}
# curl joker.coolops.cn
{"data":"hello world","version":"v1"}
# curl joker.coolops.cn
{"data":"hello world","version":"v1"}

基本保持在9:1的比例。

基于用戶請(qǐng)求的發(fā)布場(chǎng)景

(1)配置stable版本的ingress

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: app-server-stable-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: joker.coolops.cn
http:
paths:
- path:
backend:
serviceName: app-server-stable-svc
servicePort: 8080

(2)配置canary版本的ingress

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: app-server-canary-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "region"
nginx.ingress.kubernetes.io/canary-by-header-value: "sichuan"
spec:
rules:
- host: joker.coolops.cn
http:
paths:
- path:
backend:
serviceName: app-server-canary-svc
servicePort: 8080

當(dāng)我們?cè)L問(wèn)的時(shí)候不帶header,則只會(huì)訪問(wèn)stable版本應(yīng)用,如下:

# curl joker.coolops.cn
{"data":"hello world","version":"v1"}
# curl joker.coolops.cn
{"data":"hello world","version":"v1"}

如果我們?cè)谠L問(wèn)的時(shí)候帶上region: sichuan 的header,則只會(huì)訪問(wèn)到canary版本應(yīng)用,如下:

# curl joker.coolops.cn -H "region: sichuan"
{"data":"hello SB","version":"v2"}
# curl joker.coolops.cn -H "region: sichuan"
{"data":"hello SB","version":"v2"}

實(shí)現(xiàn)是不是很簡(jiǎn)單?

我們現(xiàn)在來(lái)想另外一個(gè)問(wèn)題,上面的所有操作都是手動(dòng)的,我們應(yīng)該如何進(jìn)行自動(dòng)化?應(yīng)該怎樣來(lái)設(shè)計(jì)流水線?

下面來(lái)說(shuō)說(shuō)我個(gè)人的想法。

關(guān)于灰度發(fā)布流水線設(shè)計(jì)的想法

首先來(lái)捋捋過(guò)程:

  • 發(fā)布canary版本應(yīng)用進(jìn)行測(cè)試
  • 測(cè)試完成將canary版本替換成stable版本
  • 刪除canary版本的ingress配置
  • 刪除老的stable版本

整個(gè)過(guò)程很簡(jiǎn)單,但是對(duì)于已經(jīng)部署好的deployment是不允許直接修改labels標(biāo)簽的。這時(shí)候是不是可以在canary版本測(cè)試i完成后直接更新stable版本的鏡像?當(dāng)然這種情況會(huì)存在滾動(dòng)更新的一個(gè)過(guò)程。

那我們流水線可以這樣設(shè)計(jì),如下:

這樣設(shè)計(jì)存在一個(gè)問(wèn)題,那就是無(wú)法確定等待的時(shí)間,如果等待的時(shí)間很長(zhǎng),不僅很耗資源,也可能自動(dòng)超時(shí)退出。

那我們是不是可以將其拆分為兩條流水線?流程如下:

我比較傾向第二種,這種方式流水線跑完了就退出,不會(huì)占用額外的資源。

在開(kāi)發(fā)流水線之前,我們需要先定義好命名標(biāo)準(zhǔn),這樣在操作的時(shí)候更加方便。

流水線名字格式如下:

  • -stable
  • -canary

deployment的名字格式如下:

  • -stable
  • -canary

service的名字格式如下:

  • -stable-svc
  • -canary-svc

ingress的名字格式如下:

  • -stable-ingress
  • -canary-ingress

標(biāo)準(zhǔn)定義好之后,在實(shí)現(xiàn)的時(shí)候就簡(jiǎn)單多了。

代碼位置:https://gitee.com/coolops/gary-devops.git

我定義了兩個(gè)Jenkinsfile,一個(gè)叫canary.Jenkinsfile,一個(gè)叫stable.Jenkinsfile,他們分別用來(lái)部署canary和stable版本。

然后我們會(huì)創(chuàng)建兩條流水線,如下:

其中joker-gary-devops-canary是用來(lái)部署canary版本,另外一個(gè)是用來(lái)部署stable版本。

現(xiàn)在在集群里運(yùn)行著stable版本,如下:

# curl -H "Host: joker.coolops.cn" http://192.168.100.61
{"data":"hello world!","version":"v1"}

我們修改了需求,更改了代碼,變動(dòng)如下:

package main

import (
"net/http"

"github.com/gin-gonic/gin"
)

func main() {
g := gin.Default()
g.GET("/", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"version": "v1",
"data": "hello Joker!",
})

})
_ = g.Run(":8080")
}

首先發(fā)布canary流水線,待流水線發(fā)布完成,可以在集群中看到canary版本的pod以及ingress等,如下:

# kubectl get po| grep canary
gray-devops-canary-59c88846dc-j2vlc 1/1 Running 0 55s
# kubectl get svc| grep canary
gray-devops-canary-svc ClusterIP 10.233.18.235 8080/TCP 3h14m
# kubectl get ingress| grep canary
gray-devops-canary-ingress joker.coolops.cn 192.168.100.61 80 63s

查看一下canary-ingress的內(nèi)容,看是否是我們需要的,如下:

# kubectl get ingress gray-devops-canary-ingress -o yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"
creationTimestamp: "2022-02-15T05:43:32Z"
generation: 1
name: gray-devops-canary-ingress
namespace: default
resourceVersion: "412247041"
selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/gray-devops-canary-ingress
uid: fe13b38d-1f6f-45fb-8d89-504b4b8288ea
spec:
rules:
- host: joker.coolops.cn
http:
paths:
- backend:
serviceName: gray-devops-canary-svc
servicePort: 8080
status:
loadBalancer:
ingress:
- ip: 192.168.100.61

可以發(fā)現(xiàn)跟我們預(yù)設(shè)的一樣。

訪問(wèn)測(cè)試也沒(méi)問(wèn)題,如下:

# curl -H "Host: joker.coolops.cn" http://192.168.100.61
{"data":"hello Joker!","version":"v1"}[root@master ~]# curl -H "Host: joker.coolops.cn" http://192.168.100.61
{"data":"hello world!","version":"v1"}[root@master ~]# curl -H "Host: joker.coolops.cn" http://192.168.100.61
{"data":"hello world!","version":"v1"}[root@master ~]# curl -H "Host: joker.coolops.cn" http://192.168.100.61
{"data":"hello world!","version":"v1"}[root@master ~]# curl -H "Host: joker.coolops.cn" http://192.168.100.61
{"data":"hello world!","version":"v1"}[root@master ~]# curl -H "Host: joker.coolops.cn" http://192.168.100.61
{"data":"hello world!","version":"v1"}[root@master ~]# curl -H "Host: joker.coolops.cn" http://192.168.100.61
{"data":"hello world!","version":"v1"}[root@master ~]# curl -H "Host: joker.coolops.cn" http://192.168.100.61
{"data":"hello world!","version":"v1"}[root@master ~]# curl -H "Host: joker.coolops.cn" http://192.168.100.61
{"data":"hello world!","version":"v1"}[root@master ~]# curl -H "Host: joker.coolops.cn" http://192.168.100.61
{"data":"hello world!","version":"v1"}[root@master ~]# curl -H "Host: joker.coolops.cn" http://192.168.100.61
{"data":"hello Joker!","version":"v1"}[root@master ~]# curl -H "Host: joker.coolops.cn" http://192.168.100.61
{"data":"hello world!","version":"v1"}

現(xiàn)在就可以發(fā)布stable版本了,運(yùn)行stable版本的流水線。發(fā)布完成后,集群里就只有stable版本的應(yīng)用了,如下:

# kubectl get po | grep gray
gray-devops-stable-7f977bb6cf-8jzgt 1/1 Running 0 35s
# kubectl get ingress | grep gray
gray-devops-stable-ingress joker.coolops.cn

通過(guò)域名訪問(wèn)也是符合預(yù)期的。

# curl -H "Host: joker.coolops.cn" http://192.168.100.61
{"data":"hello Joker!","version":"v1"}

到此基本實(shí)現(xiàn)了自己的想法。

說(shuō)明:Jenkinsfile中涉及的用戶名和密碼都保存在Jenkins的憑據(jù)中,插件需要安裝kubernetes deploy插件,到插件中心搜索就行。

最后

上面我們基本實(shí)現(xiàn)了灰度發(fā)布的過(guò)程,也只是僅僅將手動(dòng)的變成了自動(dòng)。但是你有沒(méi)有發(fā)現(xiàn)什么問(wèn)題?

首先需要切換流水線進(jìn)行發(fā)布,其次是發(fā)布控制方面也不是很友好,比如要增加canary版本的節(jié)點(diǎn),就需要我們手動(dòng)去做。

其實(shí)我更推薦使用argo-rollouts結(jié)合argocd進(jìn)行灰度發(fā)布,argo-rollouts自定義了一套CRD用于控制發(fā)布流程,可以省去很多手動(dòng)操作過(guò)程,argocd是基于gitops實(shí)現(xiàn)的一套軟件,便于我們進(jìn)行CD控制,也提供了UI面板進(jìn)行操作。不過(guò)要用這套就需要更改現(xiàn)有的發(fā)布方式以及應(yīng)用模板,不復(fù)雜,但是存在一定的風(fēng)險(xiǎn),需要進(jìn)行一定程度的測(cè)試。


當(dāng)前名稱(chēng):如何通過(guò) Ingress-Nginx 實(shí)現(xiàn)應(yīng)用灰度發(fā)布?
當(dāng)前網(wǎng)址:http://www.5511xx.com/article/djdhjsh.html