基于 Nginx Ingress + 云效 AppStack 实现灰度发布

作者:子丑

场景简介

灰度发布是降低生产部署风险,提升线上服务稳定性的重要手段,这在当前快速迭代的软件研发中尤为重要。相对于 K8s 默认的滚动部署或者简单的 Pod 分批,基于流量特征的灰度发布验证更精准,风险更低。

在云原生场景下,基于 Nginx Ingress 的灰度发布是被广泛使用的方案之一。该方案通过在流量入口侧进行灰度和正常流量的路由调配,将灰度流量导入到灰度的服务版本,从而可以在全量部署到生产环境前,对新版本进行验证,当验证不通过时,可以及时回退,将风险控制在较低的范围内。而整个发布和验证,能做到对终端用户服务的不间断和体验一致。

基本原理

对于常见的 web 服务,Ingress 灰度发布的基本逻辑是:将指向同一入口(HOST)的访问请求,根据特征或流量比例,将一部分流量路由到灰度服务中,通过对灰度流量的监控和验证,判断灰度服务是否符合上线标准。

按照流量的路径,我们可以画出 Ingress 流量灰度在 K8s 上的简单架构(如下图)。

图片

流量从入口的 HOST 进来后,会根据 Nginx-Ingress 的流量标识(定义在 Ingress 的 annotation 中),将符合灰度标识的请求路由到灰度环境的 service 中,进而进入背后的工作负载 Pod。对于每个环境内部的 service 和 deployment,它们并不主动感知灰度标识,也就是说,通常情况下,内部的 rpc 流量并不携带灰度标识。因此,这种架构主要解决的是外部流量灰度的问题,适合服务数量不太多,服务间调用比较简单的场景。

具体实践

接下来,我们结合云效 AppStack,来看下如何在阿里云 ACK 集群上进行应用的 Ingress 灰度发布。

我们首先导入 ACK 集群并创建应用。

图片

3.1 定义和管理灰度环境

3.1.1 定义环境

在应用中,我们分别定义灰度环境与生产环境,两个环境共享同一个 K8s 集群,我们将灰度环境命名为 grey,生产环境命名为 ack-prod。

图片

3.1.2 定义部署编排

我们打开应用设置,编排配置来定义部署编排。灰度发布生效的关键是 Ingress 中的 canary 注解,需要查看你的 nginx-ingress-controller 版本,以确定可以支持的注解。我测试的集群上 nginx-ingress-controller 的版本是 0.30,采用 header 来标识灰度流量。

图片

为了做到只在灰度环境中开启灰度的路由配置,我们使用了编排模板的条件语句,见下面的编排示例:

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: {{ .AppStack.appName }}-{{ .AppStack.envName }}namespace: {{ .Values.namespace }}
{{ if eq .AppStack.envName "grey" }}annotations:# 开启Canary。nginx.ingress.kubernetes.io/canary: "true"# 请求头为_env。nginx.ingress.kubernetes.io/canary-by-header: "_env"# 请求头_env的值为grey时,请求才会被路由到新版本服务中。nginx.ingress.kubernetes.io/canary-by-header-value: "grey"
{{ end }}
spec:rules:- host: {{ .Values.host }}http:paths:- path: /pathType: Prefixbackend:service:name: {{ .AppStack.appName }}-{{ .AppStack.envName }}port:number: 80

可以看到在 Ingress 的编排中,仅名称为 “grey” 的环境,会开启 canary 的 annotaion,并且将灰度标识设置为通过 _env: grey 的 header 标签。

同时在 Ingress 的 rules 配置中,通过变量 host 来指定路由关联的 HOST,这里 ACK 灰度环境和 ACK 生产环境分别关联灰度环境变量组和生产环境变量组,这两个变量组的 host 变量采用相同的值。

示例:

图片

#
namespace = demo-pre
#
host = go.demo.prod#
namespace = demo-prod
#
host = go.demo.prod

除了 Ingress 外,还需要配置对应的 service 和 deployment。

---
apiVersion: v1
kind: Service
metadata:name: {{ .AppStack.appName }}-{{ .AppStack.envName }}namespace: {{ .Values.namespace }}
spec:selector:run: {{ .AppStack.appName }}-{{ .AppStack.envName }}ports:- protocol: TCPport: 80targetPort: 8080---
apiVersion: apps/v1
kind: Deployment
metadata:name: {{ .AppStack.appName }}-{{ .AppStack.envName }}labels:run: {{ .AppStack.appName }}-{{ .AppStack.envName }}namespace: {{ .Values.namespace }}
spec:replicas: {{ .Values.replicas }}selector:matchLabels:run: {{ .AppStack.appName }}-{{ .AppStack.envName }}template:metadata:labels:run: {{ .AppStack.appName }}-{{ .AppStack.envName }}spec:containers:- name: mainimage: {{ .AppStack.image.backend }}ports:- containerPort: 8080resources:limits:cpu: {{ .Values.cpuLimit }}memory: {{ .Values.memoryLimit }}requests:cpu: {{ .Values.cpuRequest }}memory: {{ .Values.memoryRequest }}

3.2 准备示例代码并关联到应用中

可从 atomgit 上下载实例代码,路径为:https://atomgit.com/feiyuw/demo-go-echo.git

将代码导入到云效代码管理 Codeup,然后关联到应用中。

图片

3.3 定义灰度发布的流程

接下来,我们通过云效 AppStack 的研发流程,定义灰度发布的整个过程,见下图:

图片

在该流程中,每次执行,我们都会从 master 分支拉取代码进行镜像构建,构建完成后会转交运维进行审批,审批通过后即开始部署过程。

部署过程包含灰度部署、灰度验证、生产部署和灰度清理四个步骤。

  • 灰度部署步骤会将前面构建出来的镜像更新到 ACK 灰度环境,此时通过在请求中携带 _env:grey 的 header 就可进行灰度验证。
  • 灰度验证是一个人工卡点,用于对灰度环境的观测和验证,如果验证通过即自动进行生产环境的部署,如果验证失败,则跳过生产部署,执行灰度清理
  • 生产部署步骤会将镜像更新到 ACK 生产环境,此时新的服务版本将对普通用户可见。注意,这里为了降低风险,生产部署的策略被设置为了分批,且首批暂停的模式,保证线上仍然是逐步放量的,且有机会快速回退。
  • 灰度清理步骤主要是清理灰度环境的资源,一方面节约资源,另一方面避免灰度验证不通过时对线上的影响。

在云效 AppStack 上相关应用的设置中,进行研发流程设置(如果仅是体验灰度发布,可仅配置生产阶段)。

图片

上述流程可以参考下面的流水线 yaml 来定义,请注意将其中的 acr_docker_build_step 步骤的镜像地址和服务连接修改为正确的值,并把 grey_validate 和 ops_validate 包含的 userId 替换为自己的阿里云的账号 ID。

---
stages:build:name: "构建"jobs:go_build:name: "Go 镜像构建"steps:golang_build_step:name: "Golang 构建"step: "GolangBuild"with:goVersion: "1.20.x"run: |export GOPROXY=https://goproxy.cnmake buildupload_step:step: "ArtifactUpload"name: "构建物上传"with:serviceConnection: "wtdbdh89rrfdsod6"repo: "flow_generic_repo"artifact: "demo-go-echo"version: "prod-${CI_COMMIT_ID}.${DATETIME}"filePath:- "demo-go-echo"- "deploy.sh"acr_docker_build_step:name: "镜像构建并推送至阿里云镜像仓库个人版"step: "ACRDockerBuild"with:artifact: "image"dockerfilePath: "Dockerfile"dockerRegistry: "registry.cn-zhangjiakou.aliyuncs.com/docker007/demo-go-echo"dockerTag: "prod-${CI_COMMIT_ID}.${DATETIME}"region: "cn-zhangjiakou"serviceConnection: "<connectionId>"approve:name: "部署审核"jobs:ops_validate:name: "运维审批"component: "ManualValidate"with:validatorType: "users"validators:- <userId>grey:name: "灰度验证"jobs:grey_deploy_job:name: "ACK灰度部署"component: "AppStackFlowDeploy"with:application: "demo-go-echo"environment: "grey"artifacts:- label: "backend"value: "$[stages.build.go_build.acr_docker_build_step.artifacts.image.dockerUrl]"autoDeploy: truegrey_validate:name: "灰度验证"component: "ManualValidate"needs:- "grey_deploy_job"with:validatorType: "users"validators:- <userId>deploy:name: "部署"jobs:ack_deploy_job:name: "ACK生产部署"component: "AppStackFlowDeploy"condition: |succeed('grey.grey_validate')with:application: "demo-go-echo"environment: "ack-prod"artifacts:- label: "backend"value: "$[stages.build.go_build.acr_docker_build_step.artifacts.image.dockerUrl]"autoDeploy: truecleanup:name: "清理环境"jobs:cleanup_grey_env_job:name: "清理灰度环境"component: "AppStackCleanEnv"needs:- "grey.grey_validate"- "deploy.ack_deploy_job"condition: |failed('grey.grey_validate') || succeed('deploy.ack_deploy_job')with:application: "demo-go-echo"environment: "grey"deleteEnv: "cleanEnv"

3.4 验证灰度发布流程

我们假设研发流程仅包含生产阶段,先运行一次生产阶段,将应用部署到灰度和生产环境中,注意:环境第一次部署可能需要手动创建部署单。

修改代码,将 routes.go 里面的版本号修改为新的值,再次执行生产阶段,直到灰度验证步骤,此时生产环境与灰度环境运行不同的版本。

通过 kubectl get ing -A 获取 ingress 的出口 IP,在本地 /etc/hosts 中将其绑定到 go.demo.prod 中,如:

127.0.0.1 go.demo.prod  # 将127.0.0.1修改为正确的出口IP

打开终端,通过 httpie 或者 curl 请求/version 接口,以 httpie 为例,请求命令为:

http -v http://go.demo.prod/version # 请求正式环境
http -v http://go.demo.prod/version _env:grey    # 请求灰度环境

常见问题

4.1 有了灰度环境,生产环境部署的时候还需要分批吗?

建议在生产环境部署的时候仍然开启分批,因为灰度环境虽然验证通过了,但受到数据量等影响,生产仍然不建议全量一起上,通过分批,可以把风险控制在小范围内,避免大的故障的发生。

4.2 如何在研发流程上整合配置变更和数据变更?

可以将配置变更和数据变更作为研发阶段的步骤,编排到研发流程的流水线 yaml 中,通常建议在应用部署前执行数据变更,部署后执行配置变更。同时,对应于 K8s 上的灰度环境,如果采用了类似 Nacos 这样的配置中心,也应当由对应的灰度 namespace,从而避免直接修改生产配置。

4.3 灰度环境包含多个应用,如何保证其内部服务间调用也是走的灰度环境?

完整的方案建议参考 MSE 等产品。

如果应用数量比较少,链路比较简单,且接受基于 K8s 的简单方案,可以为每个应用都定义一个灰度环境,共享同一个集群和 namespace,应用间通过 service 进行调用。此时,由于 namespace 的隔离,灰度环境内的应用互相调用只会调用同 namespace 下的其它应用的灰度版本。

这种方案需要保证各应用灰度环境的长期可用,因此研发流程最后的清理环境步骤需要被移除。

4.4 如何在流程中关联其它类型的发布如函数计算?

可以在函数计算的相关步骤编排到研发流程的流水线 yaml 中,从而实现双方的联动。

点击此处,手把手带你体验云效应用交付 AppStack,还可抽取漫步者蓝牙耳机、护眼台灯等丰厚礼品。

参考文档:

[1] 如何通过 Nginx Ingress Controller 实现应用服务的灰度发布_容器服务 Kubernetes 版 ACK(ACK)

https://help.aliyun.com/zh/ack/ack-managed-and-ack-dedicated/user-guide/implement-gray-scale-and-blue-green-publishing-through-nginx-ingress#38348104fea19

[2] Canary Deployments - Ingress-Nginx Controller

https://kubernetes.github.io/ingress-nginx/examples/canary/

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

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

相关文章

从 Acme.Sh V3.0 说说 ZeroSSL

熟悉明月的都知道&#xff0c;明月一直都在使用 acme.sh 作为服务器端申请、部署、续期免费 SSL 证书的主要工具&#xff0c;今天在帮一个站长申请 SSL 证书的时候发现 acme.sh v3.0 开始默认的免费 SSL 证书变更为&#xff1a;ZeroSSL 了&#xff0c;这个 ZeroSSL 其实跟明月一…

在 C++ 中使用不同平台的时间函数及比较

在 C 编程中&#xff0c;时间函数的选择对于性能测量、任务调度和时间戳记录至关重要。不同的操作系统提供了不同的时间函数&#xff0c;同时在同一个平台上&#xff0c;也可能有多种不同的时间函数可供选择。本文将介绍在 C 中常用的时间函数&#xff0c;并比较它们在不同平台…

通俗范畴论2 有向图与准范畴

退一步海阔天空&#xff0c;在正式进入范畴论之前&#xff0c;我们可以重新审视一下我们是如何认识世界的&#xff0c;有了这个对人类认识世界过程的底层理解&#xff0c;可以帮助我们更好地理解范畴论。 对于人类认识世界&#xff0c;最神奇的一点就是这个世界居然是可以认识…

Elasticsearch 认证模拟题 - 22

一、题目 索引 task 索引中文档的 fielda 字段内容包括了 hello & world&#xff0c;索引后&#xff0c;要求使用 match_phrase query 查询 hello & world 或者 hello and world 都能匹配该文档 1.1 考点 分词器 1.2 答案 # 创建符合条件的 task 索引&#xff0c;…

算法人生(22):从“生成对抗网络”看“逆商提升”

​ 在图像生成与编辑、音频合成、视频生成领域里&#xff0c;有一个非常重要的深度学习方法——生成对抗网络&#xff08;简称GANs&#xff09;&#xff0c;它是由两个神经网络组成的模型&#xff0c;分别为生成器&#xff08;Generator&#xff09;和判别器&#xff08;Discr…

采煤vr事故灾害应急模拟救援训练降低生命财产损失

在化工工地&#xff0c;设备繁多、环境复杂&#xff0c;潜藏着众多安全隐患&#xff0c;稍有不慎便可能引发安全事故。为了保障工地的安全&#xff0c;我们急需一套全面、高效的安全管理解决方案。web3d开发公司深圳华锐视点研发的工地安全3D模拟仿真隐患排查系统&#xff0c;正…

可以用来制作硬模空心耳机壳的胶粘剂有哪些种类?

可以用来制作硬模空心耳机壳的胶粘剂有哪些种类&#xff1f; 制作耳机壳的胶粘剂有很多种类&#xff0c;常见的有环氧树脂胶水、UV树脂胶、快干胶、热熔胶等。 这些胶粘剂都有不同的特点和适用场景&#xff0c;可以根据自己的需求选择合适的类型。 例如&#xff1a; 环氧树脂…

pdf转图片,pdf转图片在线转

pdf转图片的方法&#xff0c;对于许多人来说可能是一个稍显陌生的操作。然而&#xff0c;在日常生活和工作中&#xff0c;我们有时确实需要将pdf文件转换为图片格式&#xff0c;以便于在特定的场合或平台上进行分享、展示或编辑。以下&#xff0c;我们将详细介绍一个pdf转成图片…

用宝塔部署vue+springboot上线公网详细步骤

首先自己在腾讯云中按照教程安装好宝塔。这是宝塔面板&#xff0c;获取登录宝塔的网址和账号密码。 1.在navicat新建数据库 如果出现权限问题&#xff0c;可以在宝塔数据库面板phpMyAdmin中进行权限设置 navicat可以修改用户权限 2.在宝塔面板新建数据库 3.将前端打包的dist文件…

linux 部署瑞数6实战(维普,药监局)第一部分

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx 本文章未经许可禁止转载&…

【星海随笔】云解决方案学习日志篇(二) kafka、Zookeeper、Fielbeat

Elastic 中国社区官方博客 https://blog.csdn.net/ubuntutouch/category_9209092.html Kafka kafka的源代码是基于Scala语言编写的&#xff0c;运行在Java虚拟机&#xff08;即:JVM&#xff09;上。因此&#xff0c;在安装kafka之前需要先安装JDK Kafka 为什么依赖 Zookeepe…

52. QT插件开发--插件程序(带ui文件)的创建与编译

1. 说明 一般情况下,针对代码量比较小的QT程序不需要进行插件集成化开发,但是针对大型程序来说,代码结构比较复杂,使用插件开发的方式可以提高代码开发和维护效率,团队之间的分工合作也会更加的明确。所谓插件式开发,实际上就是把程序的一部分功能封装起来,编译成一个单…

认识Redis 主从同步、事务和Memcached的区别

08- 什么是 Redis 主从同步&#xff1f; Redis 的主从同步(replication)机制&#xff0c;允许 Slave 从 Master 那里&#xff0c;通过网络传输拷贝到完整的数据备份&#xff0c;从而达到主从机制。 主数据库可以进行读写操作&#xff0c;当发生写操作的时候自动将数据同步到从…

AES加密、DES加密和RC4加密的区别

AES加密、DES加密和RC4加密在多个方面存在显著区别。以下是这些加密算法的详细对比&#xff1a; AES加密 算法原理&#xff1a; AES&#xff08;Advanced Encryption Standard&#xff09;采用对称密钥加密&#xff0c;利用分组密码的原理&#xff0c;将明文分成多个128位的组…

【C语言】解决C语言报错:Use of Uninitialized Variable

文章目录 简介什么是Use of Uninitialized VariableUse of Uninitialized Variable的常见原因如何检测和调试Use of Uninitialized Variable解决Use of Uninitialized Variable的最佳实践详细实例解析示例1&#xff1a;局部变量未初始化示例2&#xff1a;数组未初始化示例3&…

分布式物联网平台特点

随着物联网&#xff08;IoT&#xff09;技术的飞速发展&#xff0c;我们正步入一个万物互联的新时代。在这个时代&#xff0c;设备、数据和服务的无缝集成是实现智能化的关键。分布式物联网平台作为这一进程的核心&#xff0c;正在成为构建智能世界的基石。 一、分布式物联网平…

C++ 47 之 函数调用运算符重载

#include <iostream> #include <string> using namespace std;class MyPrint{ public:// 重载小括号() 重载谁operator后就紧跟谁的符号void operator()(string txt){cout << txt << endl;} };class MyAdd{ public:int operator()(int a, int b){retur…

【Pandas驯化-04】Pandas中drop_duplicates、describe、翻转操作

【Pandas驯化-04】Pandas中drop_duplicates、describe、翻转操作 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &#x1f387; 相关内容文档获取 微信公…

CleanMyMac X软件下载附加详细安装教程

​首先要介绍的是CleanMyMac X&#xff0c;这是一款极受欢迎的苹果电脑清理软件&#xff0c;它能够全面扫描你的电脑系统&#xff0c;清理无用的文件和垃圾&#xff0c;以释放硬盘空间&#xff0c;除了清理功能之外&#xff0c;CleanMyMac X 还可协助管理应用程序、优化性能、修…

[2024-06]-[大模型]-[Ollama]- WebUI

主要涉及要部署的前端webui是来源于:https://github.com/open-webui/open-webui 正常就使用: docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-web…