学习笔记三十六:通过Ingress-nginx实现灰度发布

通过Ingress-nginx实现灰度发布

  • 灰度发布原理
    • 将新版本灰度给部分用户
    • 切一定比例的流量给新版本
  • 部署两个版本的服务
    • 以 nginx 为例,先部署一个 v1 版本:
    • 部署一个 v2 版本
    • 再创建一个 Ingress,对外暴露服务,指向 v1 版本的服务:
    • 访问验证
  • 基于 Header 的流量切分:
    • 测试访问
  • 基于 Cookie 的流量切分:
    • 测试访问:
  • 基于服务权重的流量切分
    • 测试访问:

灰度发布原理

将新版本灰度给部分用户

  • 假设线上运行了一套对外提供 7 层服务的 Service A 服务,后来开发了个新版本 Service A’ 想要上线,但又不想直接替换掉原来的 Service A,希望先灰度一小部分用户,等运行一段时间足够稳定了再逐渐全量上线新版本,最后平滑下线旧版本。这个时候就可以利用 Nginx Ingress 基于 Header 或 Cookie 进行流量切分的策略来发布,业务使用 Header 或 Cookie 来标识不同类型的用户,我们通过配置 Ingress 来实现让带有指定 Header 或 Cookie 的请求被转发到新版本,其它的仍然转发到旧版本,从而实现将新版本灰度给部分用户:
    在这里插入图片描述

切一定比例的流量给新版本

  • 假设线上运行了一套对外提供 7 层服务的 Service B 服务,后来修复了一些问题,需要灰度上线一个新版本 Service B’,但又不想直接替换掉原来的 Service B,而是让先切 10% 的流量到新版本,等观察一段时间稳定后再逐渐加大新版本的流量比例直至完全替换旧版本,最后再滑下线旧版本,从而实现切一定比例的流量给新版本:
    在这里插入图片描述

部署两个版本的服务

Ingress-Nginx是一个K8S ingress工具,支持配置Ingress Annotations来实现不同场景下的灰度发布和测试。 Nginx Annotations 支持以下几种Canary规则:

  • 假设我们现在部署了两个版本的服务,老版本和canary版本
  • nginx.ingress.kubernetes.io/canary-by-header:基于Request Header的流量切分,适用于灰度发布以及 A/B 测试。当Request Header 设置为 always时,请求将会被一直发送到 Canary 版本;当 Request Header 设置为 never时,请求不会被发送到 Canary 入口。
  • nginx.ingress.kubernetes.io/canary-by-header-value:要匹配的 Request Header 的值,用于通知 Ingress 将请求路由到 Canary Ingress 中指定的服务。当 Request Header 设置为此值时,它将被路由到 Canary 入口。
  • nginx.ingress.kubernetes.io/canary-weight:基于服务权重的流量切分,适用于蓝绿部署,权重范围 0 - 100 按百分比将请求路由到 Canary Ingress 中指定的服务。权重为 0 意味着该金丝雀规则不会向 Canary 入口的服务发送任何请求。权重为60意味着60%流量转到canary。权重为 100 意味着所有请求都将被发送到 Canary 入口。
  • nginx.ingress.kubernetes.io/canary-by-cookie:基于 Cookie 的流量切分,适用于灰度发布与 A/B 测试。用于通知 Ingress 将请求路由到 Canary Ingress 中指定的服务的cookie。当 cookie 值设置为 always时,它将被路由到 Canary 入口;当 cookie 值设置为 never时,请求不会被发送到 Canary 入口。

以 nginx 为例,先部署一个 v1 版本:

上传openresty.tar.gz至node节点
链接:https://pan.baidu.com/s/10BU9qNqiAjfQfb9ZyVh1cQ?pwd=6uaq
提取码:6uaq

ctr -n=k8s.io images import openresty.tar.gz
docker load -i  openresty.tar.gz

在master执行

vim v1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-v1
spec:replicas: 1selector:matchLabels:app: nginxversion: v1template:metadata:labels:app: nginxversion: v1spec:containers:- name: nginximage: "openresty/openresty:centos"imagePullPolicy: IfNotPresentports:- name: httpprotocol: TCPcontainerPort: 80volumeMounts:- mountPath: /usr/local/openresty/nginx/conf/nginx.confname: configsubPath: nginx.confvolumes:- name: configconfigMap:name: nginx-v1
---
apiVersion: v1
kind: ConfigMap
metadata:labels:app: nginxversion: v1name: 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: ClusterIPports:- port: 80protocol: TCPname: httpselector:app: nginxversion: v1
kubectl apply -f v1.yaml

部署一个 v2 版本

vim v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-v2
spec:replicas: 1selector:matchLabels:app: nginxversion: v2template:metadata:labels:app: nginxversion: v2spec:containers:- name: nginximage: "openresty/openresty:centos"imagePullPolicy: IfNotPresentports:- name: httpprotocol: TCPcontainerPort: 80volumeMounts:- mountPath: /usr/local/openresty/nginx/conf/nginx.confname: configsubPath: nginx.confvolumes:- name: configconfigMap:name: nginx-v2
---
apiVersion: v1
kind: ConfigMap
metadata:labels:app: nginxversion: v2name: 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: ClusterIPports:- port: 80protocol: TCPname: httpselector:app: nginxversion: v2
kubectl apply -f v2.yaml

再创建一个 Ingress,对外暴露服务,指向 v1 版本的服务:

vim v1-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: nginxannotations:kubernetes.io/ingress.class: nginx
spec:rules:- host: canary.example.comhttp:paths:- path: /  #配置访问路径,如果通过url进行转发,需要修改;空默认为访问的路径为"/"pathType:  Prefixbackend:  #配置后端服务service:name: nginx-v1port:number: 80
kubectl apply -f v1-ingress.yaml

访问验证

#curl -H "Host: canary.example.com" http://EXTERNAL-IP # EXTERNAL-IP 替换为 Nginx Ingress 自身对外暴露的 IP
curl -H "Host: canary.example.com" http://192.168.40.12

在这里插入图片描述

基于 Header 的流量切分:

创建 Canary Ingress,指定 v2 版本的后端服务,且加上一些 annotation,实现仅将带有名为 Region 且值为 cd 或 sz 的请求头的请求转发给当前 Canary Ingress,模拟灰度新版本给成都和深圳地域的用户:

vim v2-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:annotations:kubernetes.io/ingress.class: nginxnginx.ingress.kubernetes.io/canary: "true"nginx.ingress.kubernetes.io/canary-by-header: "Region"nginx.ingress.kubernetes.io/canary-by-header-pattern: "cd|sz"name: nginx-canary
spec:rules:- host: canary.example.comhttp:paths:- path: /  #配置访问路径,如果通过url进行转发,需要修改;空默认为访问的路径为"/"pathType:  Prefixbackend:  #配置后端服务service:name: nginx-v2port:number: 80
kubectl apply -f v2-ingress.yaml

测试访问

#curl -H "Host: canary.example.com" -H "Region: cd" http://EXTERNAL-IP # EXTERNAL-IP 替换为 Nginx Ingress 自身对外暴露的 IP
curl -H "Host: canary.example.com" -H "Region: cd" http://192.168.40.12
curl -H "Host: canary.example.com" -H "Region: bj" http://192.168.40.12
curl -H "Host: canary.example.com" -H "Region: cd" http://192.168.40.12

在这里插入图片描述

可以看到,只有 header Region 为 cd 或 sz 的请求才由 v2 版本服务响应。

基于 Cookie 的流量切分:

与前面 Header 类似,不过使用 Cookie 就无法自定义 value 了,这里以模拟灰度成都地域用户为例,仅将带有名为 user_from_cd 的 cookie 的请求转发给当前 Canary Ingress 。先删除前面基于 Header 的流量切分的 Canary Ingress,然后创建下面新的 Canary Ingress:

kubectl delete -f v2-ingress.yaml
vim v1-cookie.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:annotations:kubernetes.io/ingress.class: nginxnginx.ingress.kubernetes.io/canary: "true"nginx.ingress.kubernetes.io/canary-by-cookie: "user_from_cd"name: nginx-canary
spec:rules:- host: canary.example.comhttp:paths:- path: /  #配置访问路径,如果通过url进行转发,需要修改;空默认为访问的路径为"/"pathType:  Prefixbackend:  #配置后端服务service:name: nginx-v2port:number: 80
kubectl apply -f v1-cookie.yaml

测试访问:

#curl -s -H "Host: canary.example.com" --cookie "user_from_cd=always" http://EXTERNAL-IP # EXTERNAL-IP 替换为 Nginx Ingress 自身对外暴露的 IP
curl -s -H "Host: canary.example.com" --cookie "user_from_cd=always" http://192.168.40.12
curl -s -H "Host: canary.example.com" --cookie "user_from_bj=always" http://192.168.40.12
curl -s -H "Host: canary.example.com" http://192.168.40.12

在这里插入图片描述

可以看到,只有 cookie user_from_cd 为 always 的请求才由 v2 版本的服务响应。

基于服务权重的流量切分

基于服务权重的 Canary Ingress 就简单了,直接定义需要导入的流量比例,这里以导入 10% 流量到 v2 版本为例 (如果有,先删除之前的 Canary Ingress):

kubectl delete -f v1-cookie.yaml
vim v1-weight.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:annotations:kubernetes.io/ingress.class: nginxnginx.ingress.kubernetes.io/canary: "true"nginx.ingress.kubernetes.io/canary-weight: "10"name: nginx-canary
spec:rules:- host: canary.example.comhttp:paths:- path: /  #配置访问路径,如果通过url进行转发,需要修改;空默认为访问的路径为"/"pathType:  Prefixbackend:  #配置后端服务service:name: nginx-v2port:number: 80
kubectl apply -f v1-weight.yaml

测试访问:

#for i in {1..10}; do curl -H "Host: canary.example.com" http://EXTERNAL-IP; done;
for i in {1..10}; do curl -H "Host: canary.example.com" http://192.168.40.12; done;

在这里插入图片描述

可以看到,大概只有十分之一的几率由 v2 版本的服务响应,符合 10% 服务权重的设置

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

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

相关文章

【idea】设置鼠标滚轮控制缩放大小

1、点击file 选择Setting 2、点击Editor 下面的 General 3、勾选 Mouse Control 下面的 Change font size with CtrlMouse Wheel in 4、点级apply 5、按 ctrl键 鼠标滚轮缩放字体的大小

异常 Exception 01

《 异常 Exception 》 异常的概念 异常体系图(!!) 常见的异常 异常处理概念 异常处理分类 自定义异常 throw和throws的对比 异常 Exception 01 一、引入二、介绍基本概念执行过程中所发生的异常事件可分为两类 三、异常体系图四、常见的运行时异常1、NullPointerException空指针…

大模型的RPA应用 | 代理流程自动化(APA),开启智能自动化新纪元

随着技术创新的持续推进,自动化技术已经变得至关重要,成为驱动企业和社会向前发展的核心动力。在自动化的里程碑中,机器人流程自动化(RPA)已经有效地将简单、重复且规则性的任务自动化。可是随着对处理更为复杂、多变且…

flutter开发实战-readmore长文本展开和收缩控件

flutter开发实战-readmore长文本展开和收缩控件 当长文本展开和收缩控件,我们需要使用readmore来处理长文本展开和收缩,方便阅读 一、引入readmore 在工程的pubspec.yaml中引入插件 readmore: ^2.1.0ReadMoreText的属性如下 const ReadMoreText(this.…

【Axure教程】用中继器制作多选树

“多选树”可能指的是一种用户界面元素,用于展示层级结构并允许用户选择多个节点。这在软件应用程序中常用于设置、文件浏览器等场景。 Axure里面虽然自带了一个树元件,但是并没有多选的功能,所以今天就教大家如何用中继器制作一个多选树的基…

Git——工作区管理

如何管理工作目录,以便用户可以更高效地新建提交。如何在处理工作区和暂存区文件的过程中修复错误,以及如何修复最近一次提交记录中的问题;同时还会了解到如何安全地使用暂存机制和多个工作目录处理工作流中的中断问题。 主要内容有以下几点…

DC电源模块的基本工作原理和应用

BOSHIDA DC电源模块的基本工作原理和应用 DC电源模块是一种能够将交流电转化为直流电的电子装置。它的基本工作原理是利用变压器、整流桥、电容滤波、电压稳定器等电路组成,将输入的交流电转换为稳定的直流电输出。这种直流电源模块通常可以提供不同的电压和电流输…

算法通关村第十三关-白银挑战数字与数学高频问题

大家好我是苏麟 , 今天带来数字与数学的高频问题 . 加一 描述 : 给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 你可以假设除了整数 0 之外,这个…

分布式技术(二)注册中心

💌 所属专栏:【微服务】😀 作 者:长安不及十里💻 工作:目前从事电力行业开发🌈 目标:全栈开发🚀 个人简介:一个正在努力学技术的Java工程师,专注基…

Python条件判断:解读逻辑演绎,优化编程思维

更多资料获取 📚 个人网站:ipengtao.com 条件判断是编程中的重要概念,Python语言提供了多种方式来进行条件判断,例如if、else、elif等。本文将深入探讨Python中条件判断的灵活应用,结合丰富的示例代码展示其全面性。 …

ant design vue3 处理 ant-card-head ant-tabs靠左边对齐之has选择器不生效

火狐浏览器是不支持has的。 解决方法:通过position来解决。

CCF CSP认证 历年题目自练Day50

题目 试题编号: 201809-3 试题名称: 元素选择器 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 题目分析(个人理解) 还是先理解题意,关于html的部分,可以按照样例画出…