使用 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 规则可以总体划分为以下两类:

  1. 基于权重的 Canary 规则:

  1. 基于用户请求的 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 版本的 deploymentservice (为方便快速演示,仅需将 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 赋值 neveralways,当 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

Kubernetes 使用 Ingress 实现灰度发布功能的更多相关文章

  1. 基于 Istio 与 Kubernetes 对应用进行灰度发布与 Tracing

    灰度发布,是指在黑与白之间,能够平滑过渡的一种发布方式.通俗来说,即让产品的迭代能够按照不同的灰度策略对新版本进行线上环境的测试,灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以对新版本进行测试 ...

  2. Spring cloud架构中利用zuul网关实现灰度发布功能

    蓝绿发布.金丝雀发布(灰度发布).AB测试 首先,了解下这几种发布方式的基础概念. 目前常见的发布策略有蓝绿发布.金丝雀发布(灰度发布).AB测试这几种,在国内的开发者中,对这几个概念有独立的理解.蓝 ...

  3. Ingress-nginx灰度发布功能详解

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

    本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章. 之前一篇介绍了Ingress的基本概念和Nginx Ingress的基本配置和 ...

  5. 《前端运维》五、k8s--3灰度发布、滚动更新与探针

    一.灰度发布 灰度发布是一种发布方式,也叫金丝雀发布,起源是矿工在下井之前会先放一只金丝雀到井里,如果金丝雀不叫了,就代表瓦斯浓度高.原因是金丝雀对瓦斯气体很敏感.灰度发布的做法是:会在现存旧应用的基 ...

  6. 如何用istio实现应用的灰度发布

    Istio为用户提供基于微服务的流量治理能力.Istio允许用户按照标准制定一套流量分发规则,并且无侵入的下发到实例中,平滑稳定的实现灰度发布功能. 基于华为云的Istio服务网格技术,使得灰度发布全 ...

  7. idou老师教你学Istio 18 : 如何用istio实现应用的灰度发布

    Istio为用户提供基于微服务的流量治理能力.Istio允许用户按照标准制定一套流量分发规则,并且无侵入的下发到实例中,平滑稳定的实现灰度发布功能. 基于华为云的Istio服务网格技术,使得灰度发布全 ...

  8. 干货分享|使用 Istio 实现灰度发布

    Kubernetes 作为基础平台,提供了强大的容器编排能力.但是在其上部署业务和服务治理上,仍然会面对一些复杂性和局限性.在服务治理上,已经有许多成熟的 ServiceMesh 框架用于扩充其能力, ...

  9. 【大话云原生】kubernetes灰度发布篇-从步行到坐缆车的自动化服务升级

    此文系[大话云原生]系列第四篇,该系列文章期望用最通俗.简单的语言说明白云原生生态系统内的组成.架构以及应用关系.从这篇开始我们要开始针对Kubernetes进行介绍了,本文内容如下: 一.Kuber ...

随机推荐

  1. 记一次springboot(2.1.6)+springcloud(Greenwich.SR2) 配置中心搭建,支持在线刷新

    1.配置eureka注册中心 EureKaSpringApplication: package com.crow.eureka; import org.springframework.boot.Spr ...

  2. 与Bat脚本的故事

    因为工作时需要将定时处理的业务抽出来,废弃通过监听定时调用的这种方法,改为通过第三方软件定时执行bat脚本来实现,所以学习了一下bat脚本,整理出一些学习中的基础点和重点. 基础点: (1)bat脚本 ...

  3. GitBook 3.2.3入门

    简介 GitBook 是一个基于 Node.js 的命令行工具,可使用 GitHub / Git.Markdown.AsciiDoc来制作精美的电子书.GitBook 可以将文档作为静态网站或电子书( ...

  4. 给select赋值的一种方法

    做毕设遇到的问题,在update数据的时候,要先把原来的数据传递给前台,赋值给input等标签,但是啊,select标签没有value属性啊,所以在这里研究了一下,总结一个给select赋值的方法吧 ...

  5. 【题解】CF1324F

    Question 题目大意:每个点不是黑点就是白点,求以每一个点为根时,选择出一个联通块,使得白点数与黑点数之差最大(白减黑). \(Solution\) 考虑先跑一遍\(dp\). 可以写出一个比较 ...

  6. BeetleX之webapi自定义响应内容

    输出内容多样性在webapi服务中比较普遍的,有的情况使用json,xml,图片和二进制流下载等等:为了适应用不同情况的需要,组件支持自定义内容输出.接下来的主要描述组件在webapi如何定义各种内容 ...

  7. 抓包工具Charles使用

    设置Reason:最近接触一个APP后台项目,但是不知道APP各个操作访问对应的是后台的哪个接口,迫切需要使用一个抓包工具one by one Charles  Free  简单上手快,首选 下载:h ...

  8. go 数组指针 指针数组

    package main import "fmt" func test() { var p *int // 定义指针 var a = 10 p = &a // 将a的地址赋 ...

  9. php长时间的脚本,报502

    php-fpm超时时间设置request_terminate_timeout分析原创loophome 最后发布于2017-11-22 16:17:59 阅读数 21201 收藏展开今天发现了一个很神奇 ...

  10. selenium-绕过登录

    第一种方式:chrome-debug 1.现在终端输入一下命令,启动Chrome-debug模式 #windows a.首先将chrome的环境添加到PATH中 b.进入cmd 命令栏,输入:chro ...