致景科技成立于2013年12月,是领先的纺织产业互联网企业,国家高新技术企业。旗下拥有“百布”、“全布”、“天工”、“致景金条”、“致景纺织智造园”、“致景智慧仓物流园”等业务板块,致力于通过大数据、云计算、物联网等新一代信息技术,全面打通纺织服装行业的信息流、物流和资金流,帮助行业实现协同化、柔性化、智能化的升级,构建纺织服装纵向一体化的数智化综合服务平台。
方案背景
问题描述
项目测试环境被抢占
开发联调环境不稳定
开发环境自由发布,经常性导致联调中断,开发转而寻求端到端的线下联调,在个人机器上部署上下游应用,这种模式在微服务化推广之后面对众多的微服务应用基本上寸步难行。如何解决开发阶段代码调试?
线上灰度环境的缺乏
问题综述
线下缺乏隔离的多套环境来支持多项目的开发和测试,线上缺乏灵活的流量路由策略支持灰度。
方案调研
我们的目标是开发团队不依赖运维团队(DEV=OPS),可以一键拉起逻辑隔离的开发/项目环境,可以支持预发环境隔离,生产环境规则流量+自然流量的全链路灰度验证。
自研ribbon实现
物理隔离(蓝绿发布)
这种方案需要为要灰度的服务搭建一套网络隔离、资源独立的环境,在其中部署服务的灰度版本。由于与基础环境隔离,基础环境中的其他服务无法访问到需要灰度的服务,所以需要在灰度环境中冗余部署这些服务,以便整个调用链路正常进行流量转发。此外,注册中心等一些其他依赖的中间件组件也需要冗余部署在灰度环境中,保证微服务之间的可⻅性问题,确保获取的节点IP地址只属于当前的网络环境。这个方案需要为这些业务场景采用堆机器的方式来维护多套灰度环境,会造成运维、机器成本过大,成本和代价远超收益;如果应用数目很小,就两三个应用,这个方式还是很方便的,可以接受的。
MSE标签路由+ APPSTACK应用编排(我们的选择)
- 云效应用交付平台 AppStackhttps://help.aliyun.com/document_detail/321856.html
- 阿里云微服务引擎MSE 标签路由https://help.aliyun.com/document_detail/170454.html
我们假定通过上面的两篇文章,读者已经对这两个产品已经有了简单的了解:APPSTACK负责应用的环境管理和流水线发布,MSE负责流量全链路灰度。
MSE标签路由的重要概念
对照下面的MSE标签路由的图,我们重点介绍下MSE标签路由的几个重要概念如应用的打标、流量染色/自动染色、标识链路传递等,同时下图也是我们采用方案的核心原理,使用域名来标识不同的逻辑隔离环境。
应用(服务)打标
对照核心示意图,我们发现每个应用都有个(base/gray)的tag,有了这个tag,我们才可以根据tag定义流量规则;
我们创建MSE 应用的时候是通过特定annotation(alicloud.service.tag=dev1)和环境变量spring.cloud.nacos.discovery.metadata.version给MSE 应用打标的,比如通过annotation打标之后我们就可以在MSE的标签路由中进行流量规则定义;
同时我们也可以看到Nacos里面的服务有了一个标签相关的元数据(_micro.service.env_);
MSE 流量规则配置
Nacos 里面元数据信息
容器中增加 gray 相关的环境变量
MSE 流量规则配置出现 gray 节点
Nacos 里面有gray环境的元数据信息
MSE 云原生网关可以选择 gray 版本
流量染色/自动染色
我们的解决方案也是特别地利用了这一点,对照核心示意图,我们在域名名字中添加了流量标识,然后在Ingress-Nginx中将流量标识解析出来然后通过x-mse-tag:xxx的方式一路传递下去,这样就实现了在整个链路上优先选择xxx标识的服务,使用没有标识的base服务进行兜底。
标识链路传递
阿里云效应用交付APPSTACK简述
把云效APPSTACK引入进来,主要目的是方便开发同学通过白屏的管理方式自助完成MSE所需要的配置工作,同时在微服务架构下,我们希望应用进行拆分之后,每个应用都有自己的owner。
在这里我们不展开讲述APPSTACK的核心功能,我们这里主要的就是借助应用编排,让每个应用的每个环境部署的时候,可以设置好MSE标签路由所需要的各种环境变量和annotation。
应用的多套环境部署
每个环境都会按照 MSE 标签路由的要求打上不同的标识
我们的解决方案
环境定义
多套开发环境,目标是支持多个项目的在开发阶段的开发联调,核心要求是各项目动态隔离并且支持端云互联,项目动态隔离是每个项目都有自己的开发联调环境且只需部署有变动应用,端云互联是开发可以将自己本地跑的应用注册到这个MSE这个体系里面来,实现可以本地调试的目的,两个研发可以点对点地进行本地debug来跟踪问题。开发基础环境是负责兜底服务调用的,每个应用生产部署之后都需要同步更新开发基础环境,保障基础环境是最新的生产版本。
多套项目环境,目标是支持耗时较长的大型项目,比如重大技改,重大业务项目,需要长时间占用测试环境跟内外部关联方进行稳定测试的。核心要求是各个项目动态隔离。关于项目动态隔离的定义同上
测试环境,目标是支持短平快的项目测试和集成测试,比如日常的缺陷修复,或者多个小项目需要集成到一起发布,同时也是我们日常自动化测试的环境。项目环境中的特性分支也需要经过测试环境的自动化测试才可以上线。
预发环境,目标是支持产品经理在真实环境中验证产品功能,进行验收,预发环境使用的基础建设如数据库等同生产环境是一致的,当然这里对系统设计也会提出更高的要求,比如需要保持向前兼容,就像数据库,只能增列不能减列,不能在sql中使用select * 等等,这些我们通过DMS进行数据库结构变更的约束和通过代码检查保障,此处不赘述。
生产环境,目标是支持规则流量+自然流量的全链路灰度,这里的规则流量指的是带有明显特征的流量,通过MSE的流量规则能够清晰定义的请求,比如请求头,参数,cookie,body中数据符合规则的。自然流量则相反,我们不指定任何特征,比如全部流量的1%导入到灰度环境,这个我们就理解成自然流量。
综合来看,目前的环境体系里,开发环境和项目环境涉及到动态隔离,所以需要部署基础环境来完成服务兜底的能力,这个基础环境也就是MSE标签路由中无标签(base)应用的提供者。
1. 拉取特性分支进入开发环境进行本地开发和前后端联调,然后提测到项目环境
2. 项目环境由测试团队完成功能测试之后,将应用部署到(集成)测试环境
3. 在(集成)测试环境同其他特性分支一起完成集成,并通过自动化测试和简单验证,既可部署至预发环境
4. 产品经理在预发环境进行功能验收测试,通过之后可以发布到生产环境进行灰度验证
5. 在生产环境可以按照规则流量+自然流量进行灰度验证,通过之后就可以导入全部流量
6. 最后将特性分支合并至主干后用最新的生产版本更新开发/项目基础环境。
主要场景实施
场景一:项目隔离的动态多环境
1. 通APPSTACK部署好有标签的应用(项目环境)和没标签的应用(基础环境),下列截图仅做示范
1. 在ingress-nginx中解析域名中的tag属性转换成x-mse-tag请求头链路传递
通过注解nginx.ingress.kubernetes.io/configuration-snippet实现,具体如下:
nginx.ingress.kubernetes.io/configuration-snippet: proxy_set_header x-mse-tag dev1
场景二:规则流量全链路灰度的生产环境
1、通过APPSTACK在生产环境部署好有灰度标识的应用,略图。
2、定义流量路由规则,在MSE控制台为本次灰度链路中的入口应用设置流量路由规则,比如本次发布更新了A-B-C三个应用,A就是入口应用。
通过这种方式定义之后,我们可以设置符合某些特征的流量进入到A应用的gray版本,并且向后层层传递过去,不用每个应用重复设置路由规则。这就会满足了规则流量的全链路灰度的要求。
场景三:自然流量全链路灰度的生产环境
1. 通APPSTACK在生产环境部署好有灰度标识的应用,略图。这里至少需要为本次项目的入口应用A(也可以是全部应用)增加一个自动染色的变量profiler.micro.service.tag.trace.enable=true,这个变量会把经过这个入口应用A的流量自动染色,往后传递的时候自动增加x-mse-tag的请求头,从而实现全链路灰度
2. 定义流量规则,即自然流量的多少比例进入gray环境
原理概要介绍
MSE + APPSTACK的解决方案,核心的地方在于流量规则的定义以及流量标识的传递,其核心的解决方案在于流量中标识的解析和传递,我们再看一次这个标识传递的图
怎么样才能实现这里面最核心的解析Extract和注入Inject的功能呢?
答案是探针,为每个MSE管理的应用运行时候增加一个java agent的探针,完成一个类似JVM AOP的能力,在ACK(k8s)的容器中,MSE通过如下的方式自动为应用安装java agent;
1. 配置 Webhook,然后根据 Pod 或者 Namespac中的 Labels,来判断是否要挂载 Java Agent。如果需要挂载,则就对 Pod 的声明⽂件做出后续修改
2. 获取并添加环境变量 JAVA_TOOL_OPTIONS,⽤于加载 Java Agent。
3. 给业务容器添加 Volume,⽤于存储 Java Agent 的⽂件内容。
4. 给 Pod 添加 Init container,⽤于在业务容器启动前下载 Java Agent