ASP.NET Core on K8s学习之旅(14)Ingress灰度发布

【云原生作者/Edison Zhou

这是恰童鞋骚年的第236篇原创文章


上一篇介绍了Ingress的基本概念和Nginx Ingress的基本配置和使用,然后我还录了一个快速分享小视频介绍了一下蓝绿发布和灰度发布策略的基本概念,本篇介绍一下如何实战使用Nginx Ingress实现灰度发布(金丝雀发布)。

1一些准备工作

1.1 WebAPI项目准备

首先,我们还是准备两个版本的ASP.NET Core WebAPI项目,具体项目代码可以参考我的这篇Rolling Update的文章。

他们之间的差别在于一个接口的返回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-demonamespace: xdp-poclabels:name: canary-api-demo
spec:replicas: 2selector:matchLabels:name: canary-api-demotemplate:metadata:labels:name: canary-api-demospec:containers:- name: canary-api-demoimage: xilife/canary-api-demo:1.0ports:- containerPort: 80imagePullPolicy: IfNotPresent---kind: Service
apiVersion: v1
metadata:name: canary-api-svcnamespace: xdp-poc
spec:type: NodePortports:- port: 80targetPort: 80selector:name: canary-api-demo

(2)V1.1版本(假设为灰度版本)

apiVersion: apps/v1
kind: Deployment
metadata:name: canary-api-demo-graynamespace: xdp-poclabels:name: canary-api-demo-gray
spec:replicas: 2selector:matchLabels:name: canary-api-demo-graytemplate:metadata:labels:name: canary-api-demo-grayspec:containers:- name: canary-api-demo-grayimage: xilife/canary-api-demo:1.1ports:- containerPort: 80imagePullPolicy: IfNotPresent---kind: Service
apiVersion: v1
metadata:name: canary-api-svc-graynamespace: xdp-poc
spec:type: NodePortports:- port: 80targetPort: 80selector:name: canary-api-demo-gray

将这两个应用部署至K8s集群:

kubectl apply -f deploy-canary-api-svc.yml
kubectl apply -f deploy-canary-api-gray-svc.yml

2Ingress实现灰度发布

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-ingressnamespace: xdp-pocannotations:kubernetes.io/ingress.class: "nginx"nginx.ingress.kubernetes.io/rewrite-target: /api/$2
spec:rules:- host: portal.k8s.xi-life.cnhttp:paths:- path: /api(/|$)(.*)backend:serviceName: canary-api-svcservicePort: 80

应用至K8s集群:

kubectl apply -f ingress-nginx.yaml

再为1.1版本准备一个Ingress,让它作为灰度版本的入口逐步替换原v1版本的流量接入:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:name: nginx-ingress-graynamespace: xdp-pocannotations:kubernetes.io/ingress.class: "nginx"nginx.ingress.kubernetes.io/rewrite-target: /api/$2nginx.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.cnhttp:paths:- path: /api(/|$)(.*)backend:serviceName: canary-api-svc-grayservicePort: 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-graynamespace: xdp-pocannotations: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/$2nginx.ingress.kubernetes.io/canary: "true"nginx.ingress.kubernetes.io/canary-by-cookie: "xdp-v2-cookie"
spec:rules:- host: portal.k8s.xi-life.cnhttp:paths:- path: /api(/|$)(.*)backend:serviceName: canary-api-svc-grayservicePort: 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-graynamespace: xdp-pocannotations: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/$2nginx.ingress.kubernetes.io/canary: "true"nginx.ingress.kubernetes.io/canary-weight: "50"
spec:rules:- host: portal.k8s.xi-life.cnhttp:paths:- path: /api(/|$)(.*)backend:serviceName: canary-api-svc-grayservicePort: 80

应用至K8s集群:

kubectl apply -f ingress-nginx-gray.yaml

快速验证:这里我直接通过浏览器来测试,需要注意的是这里的50%是一个近似分布值,可能实际中不会太精确。

2.4 三种方式的优先级

Nginx Ingress提供的三种灰度发布的方式的优先级顺序为:

canary-by-header -> canary-by-cookie -> canary-weight

对于Nginx Ingress的使用目前已知限制:

(1)Ingress-Nginx是在0.21.0版本中才引入的Canary功能,因此建议确保版本在0.22.0及之后(据说0.21.0版本的基于Cookie方式有点问题);

(2)目前每个Ingress规则中最多只能应用一个canary入口

3小结
本文介绍了Nginx Ingress提供的三种灰度发布(canary)的方式,然后介绍了如何使用Nginx Ingress并进行配置实现ASP.NET Core WebAPI应用服务的灰度发布实践,最后对比三种方式的优先级及限制,希望对你有所帮助。

4参考资料

JadePeng,《K8s基于Nginx Ingress实现灰度发布》

我的小碗汤,《Nginx Ingress实现灰度和金丝雀发布》

梁宽,《再也不采坑的K8s实战指南》

WangT,《K8s基于Nginx Ingress进行蓝绿部署/金丝雀发布》

linus.lin,《一文明白蓝绿部署、滚动部署、灰度发布、金丝雀发布》

往期精彩回顾

.NET Core on K8s学习系列文章目录

骚年快享:K8s下发布策略基本概念一览

基于Jenkins的开发测试全流程持续集成实践

基于Jenkins的ASP.NET Core持续集成实践


如果本文对你有用,

不妨点个“在看”/转发朋友圈

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/309639.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[汇编语言]实验:应用更灵活的寻址方式来定位内存地址

实验内容: &#xff08;1&#xff09;将datasg段中每个单词的头一个字母改成大写字母。 datasg段中的数据为: &#xff08;2&#xff09; 将datasg段中每个单词的字母改成大写字母。 datasg段中的数据为: ibm dec dos vax …

Redundant Paths POJ - 3177(tarjan+边双连通分量)

题意&#xff1a; 有n个牧场&#xff0c;要求从一个牧场到另一个牧场&#xff0c;要求至少要有2条独立的路可以走。现已有m条路&#xff0c;求至少要新建多少条路&#xff0c;使得任何两个牧场之间至少有两条独立的路。两条独立的路是指&#xff1a;没有公共边的路&#xff0c…

Slice的本质

Slice的本质 我们先看下面的代码&#xff0c;看看它的输出是什么&#xff1a; package mainimport "fmt"type Slice []intfunc (A Slice) Append(value int) {A append(A, value) } func main() {mSlice : make(Slice, 10, 20)mSlice.Append(5)fmt.Println(mSlice…

你需要了解操作系统发展历程

本文我们大概回顾计算机操作系统发展历程&#xff0c;这里不会记录关于操作系统的完整历史记录&#xff0c;只是记录那些里程碑事件&#xff0c;看看各位接触计算机时&#xff0c;操作系统发展正处于哪个年代起初没有操作系统&#xff0c;没有编程语言或编译器&#xff0c;甚至…

[汇编语言]实验:更灵活的寻址方式 -应用si和di

实验内容: &#xff08;1&#xff09; 用寄存器SI和DI实现将字符串‘welcome to masm!’ 复制到它后面的数据区中。 &#xff08;2&#xff09; 用[bx(si或di)idata]的方式&#xff0c;来使程序变得简洁。 &#xff08;1&#xff09; 代码如下: assume ds:datasg,cs:code…

http.ListenAndServe()到底做了什么?

参考&#xff1a;https://studygolang.com/articles/25849?frsidebar ​ http://blog.csdn.net/gophers 实现一个最简短的hello world服务器 package mainimport "net/http"func main() {http.HandleFunc("/", func(w http.ResponseWriter, r *http.Reque…

Strongly connected HDU - 4635(tarjan+强连通分量)

题意&#xff1a; 给一个简单有向图&#xff0c;让你加最多的边&#xff0c;使他还是一个简单有向图。 题目&#xff1a; Give a simple directed graph with N nodes and M edges. Please tell me the maximum number of the edges you can add that the graph is still a …

C++编程基础题训练

1.编写一个c风格的程序&#xff0c;用动态分配空间的方法计算Fibonacci数列的前20项并存储到动态分配的空间中 1.代码如下 #include <iostream> using namespace std;int main() {int *a new int[25];a[0] 0;a[1] 1;for (int i 2; i < 20; i){a[i] a[i - 1] a…

基于 abp vNext 和 .NET Core 开发博客项目 - 使用Redis缓存数据

上一篇文章完成了项目的全局异常处理和日志记录。在日志记录中使用的静态方法有人指出写法不是很优雅&#xff0c;遂优化一下上一篇中日志记录的方法&#xff0c;具体操作如下&#xff1a;在.ToolKits层中新建扩展方法Log4NetExtensions.cs。//Log4NetExtensions.cs using log4…

G - 水陆距离 HihoCoder - 1478(广搜+队列先进先出性质)

题目&#xff1a; 给定一个N x M的01矩阵&#xff0c;其中1表示陆地&#xff0c;0表示水域。对于每一个位置&#xff0c;求出它距离最近的水域的距离是多少。 矩阵中每个位置与它上下左右相邻的格子距离为1。 Input 第一行包含两个整数&#xff0c;N和M。 以下N行每行M个0…

第一讲 工作区和GOPATH

此为 《极客时间&Go语言核心36讲》 个人笔记&#xff0c;具体课程详见极客时间官网。 Table of Contents generated with DocToc 第一讲 工作区和GOPATH 1. 环境变量配置2. 配置GOPATH的意义 2.1 Go语言源码的组织方式2.2 源码安装后的结果&#xff08;归档文件、可执行文…

C++重载运算符小结与注意点

重载运算符需注意: 1.重载运算符时容易忘记写返回值。 2.重载赋值运算符时&#xff0c;记得加const&#xff0c;因为赋值操作必须是固定的右值。 3重载时&#xff0c;写在类中的只能有一个参数(实际有两个参数&#xff0c;另外一个是this指针&#xff0c;我们看不见而已)&am…

开发大会上,前微软CEO放出的狠话!.NET开发随时起飞,你准备好了吗?

“开发者&#xff0c;开发者&#xff0c;开发者&#xff0c;开发者”&#xff0c;微软前任CEO史蒂夫鲍尔默(Steve Ballmer)用这种略带疯狂、又唱又跳的方式表达他对开发者的热爱。不夸张的说&#xff0c;相比二十年前那个如日中天的巨无霸微软&#xff0c;现在的微软比以往任何…

Balanced Lineup POJ - 3264(线段树模板+查询比大小+建树)

题意&#xff1a; 给你n个数&#xff0c;然后问一段区间的最大的差值是多少。 题目&#xff1a; For the daily milking, Farmer John’s N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer John decides to organize a game of Ultimate Frisbe…

第二讲 命令源码文件

此为 《极客时间&Go语言核心36讲》 个人笔记&#xff0c;具体课程详见极客时间官网。 Table of Contents generated with DocToc 第二讲 命令源码文件 1. 什么是命令源码文件&#xff1f;2. 命令参数的接收和解析 2.1 命令源码文件怎么接收参数?2.2 怎样在运行源代码文件…

程序员过关斩将--为微服务撸一个简约而不简单的配置中心

点击上方蓝字 关注我们毫不犹豫的说&#xff0c;现代高速发展的互联网造就了一批又一批的网络红人&#xff0c;这一批批网红又极大的催生了特定平台的一大波流量&#xff0c;但是留给了程序员却是一地鸡毛&#xff0c;无论是运维还是开发&#xff0c;每天都会担心服务器崩溃&a…

Just a Hook HDU - 1698(查询区间求和+最基础模板)

题意&#xff1a; 给你一个1~n的区间&#xff0c;起始区间内均为1&#xff0c;然后对子区间进行值更新&#xff0c;最后求区间和。 题目&#xff1a; In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of the heroes. The hook is ma…

DDIA笔记——数据复制

Table of Contents generated with DocToc 此篇为《数据密集型应用系统设计》&#xff08;DDIA&#xff09;读书笔记&#xff0c;笔记可能存在遗漏&#xff0c;建议直接阅读原书。 第五章 数据复制 主从复制 复制滞后复制滞后带来的问题 多主节点复制 适用场景处理写冲突拓扑结…