1 - 概述
背景介绍
在实际的开发过程中,一个微服务架构系统下的不同微服务可能是由多个团队进行开发与维护的,每个团队只需关注所属的一个或多个微服务,而各个团队维护的微服务之间可能存在相互调用关系。如果一个团队在开发其所属的微服务,调试的时候需要验证完整的微服务调用链路。此时需要依赖其他团队的微服务,如何部署开发联调环境就会遇到以下问题:
- 如果所有团队都使用同一套开发联调环境,那么一个团队的测试微服务实例无法正常运行时,会影响其他依赖该微服务的应用也无法正常运行。
- 如果每个团队有单独的一套开发联调环境,那么每个团队不仅需要维护自己环境的微服务应用,还需要维护其他团队环境的自身所属微服务应用,效率大大降低。同时,每个团队都需要部署完整的一套微服务架构应用,成本也随着团队数的增加而大大上升。
此时可以使用测试环境路由的架构来帮助部署一套运维简单且成本较低开发联调环境。
什么是测试环境路由
测试环境路由是一种基于服务路由的环境治理策略,核心是维护一个稳定的基线环境作为基础环境,测试环境仅需要部署需要变更的微服务以构成特性环境。部署完成多测试环境后,开发者可以通过一定的路由规则方式,将测试请求打到不同的测试环境,如果测试环境没有相应的微服务处理链路上的请求,那么会降级到基线环境处理。因此,开发者需要将开发新测试的微服务部署到对应的测试环境,而不需要更新或不属于开发者管理的微服务则复用基线环境的服务,完成对应测试环境的测试。
由此可见,多测试环境有两个基础概念,即基线环境和特性环境。
基础概念
基线环境
基线环境(Baseline Environment)是完整稳定的基础环境,是作为同类型下其他环境流量通路的一个兜底可用环境,用户应该尽量保证基线环境的完整性、稳定性。
测试环境
测试环境(Feature Environment)是一种临时环境,仅可能为开发/测试环境类型,测试环境不需要部署全链路完整的服务,而是仅部署本次有变更的服务,其他服务通过服务路由的方式复用基线环境服务资源。
实现原理
方案总览
测试环境路由的样例实现以下图为例,一共有两个测试环境以及一个基线环境。流量从端到端会依次经过以下组件:App -> 网关 -> 用户中心 -> 积分中心 -> 活动中心。
为了达到测试环境路由的能力,开发工作需要做三件事情:
- 服务实例染色(标识实例属于哪个测试环境)
- 流量染色(标识请求应该被转发到哪个测试环境)
- 服务路由 a. 网关根据请求的目标测试环境标签转发到对应的目标测试环境的用户中心. b. 服务调用时,优先转发到同测试环境下的目标服务实例,如果同测试环境下没有服务实例则转发到基线环境.
以下三小节,将会详细介绍这三部分的原理。
服务实例染色
在多测试环境的场景中,需要对每个测试环境部署的实例进行区分,因此需要在实例上打类似于“featureenv=测试环境名”的标签,例如以下几种实践场景:
- 应用实例的配置文件中表明其环境信息。
- 把实例标签放到机器上的某一个配置文件里,例如 /etc/metadata。
- 应用启动时,调用公司的 CMDB 接口获取元信息。
流量染色
流量染色即为每个请求打上目标测试环境标签,路由转发时根据请求标签匹配请求。而流量染色可以分为以下几种方式:
- 静态染色
静态染色所有经过当前实例的请求都带上当前实例的标签信息。例如经过 env=f1 的实例的请求都携带 env=f1 的标签信息。
- 动态染色
静态染色是把服务实例的某些标签作为请求标签,服务实例标签相对静态,应用启动后初始化一次之后就不再变更。但是在实际的应用场景下,不同的请求往往需要设置不同的标签信息。此时则需要通过动态染色的能力。因此需要按照一定的规则或逻辑,为每个请求动态生成标签信息。
元数据路由
北极星提供了非常完善的服务治理能力,上层的服务框架基于北极星原生 SDK 就能快速实现强大的服务治理能力。在多测试环境场景下主要用到了元数据路由插件,此插件核心能力是根据请求的标签完全匹配服务实例的标签。
操作指引
具体操作指引按照染色的方式,分为以下三种,可以跳转到对应的文档详细查看:
2 - 客户端染色
流程简介
如概述所言,测试环境路由的开发工作分为三个阶段:
- 阶段一:实例打标。在多测试环境的场景中,需要对每个测试环境部署的实例进行区分,因此需要在实例上打类似标识实例测试环境类别的标签。
- 阶段二:部署应用。
- 阶段三:流量染色。流量染色即为每个请求打上目标测试环境标签,路由转发时根据请求标签匹配请求。
如下图所示,开发者给每个环境的应用实例进行打标(如 featureenv=f1
),标明其所在的环境类型。阶段二部署业务应用。阶段三中,开发者在请求头添加相应的流量标签,即可完成测试环境路由。
操作指引
阶段一
微服务框架服务注册场景
Spring Cloud Tencent 框架接入
Spring Cloud Tencent 中的 spring-cloud-tencent-featureenv-plugin
模块闭环了测试环境路由全部能力,所有服务只需要添加该依赖即可引入测试环境路由能力。spring-cloud-tencent-featureenv-plugin
默认以 featureenv
标签作为匹配标签,用户也可以通过系统内置的 system-feature-env-router-label=custom_feature_env_key
标签来指定测试环境路由使用的标签键。以下三种方式以默认的 featureenv
作为示例。设置方式详情参考Spring Cloud Tencent 元数据使用说明。
- 方式一:配置文件
在服务实例的配置文件中添加配置,如在 bootstrap.yml
添加如下所示即可:
spring:
cloud:
tencent:
metadata:
content:
featureenv: f1 # f1 替换为测试环境名称
- 方式二:环境变量
在服务实例所在的操作系统中添加环境变量也可进行打标,例如:SCT_METADATA_CONTENT_featureenv=f1
。
- 方式三:SPI 方式
自定义实现
InstanceMetadataProvider#getMetadata()
方法的返回值里里包含featureenv
即可。
注意:基线环境部署的服务实例不需要设置 featureenv
标签,表明其不属于任何测试环境,才可在请求没有匹配到对应测试环境的时候,匹配到基线环境。
kubernetes服务注册场景
北极星提供了polaris-controller,支持直接将pod labels同步为北极星上面的实例标签。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
做完上面2步后,polaris-controller默认会对集群中的服务数据进行全量同步,而pod中的labels也会同步为北极星的实例标签。
阶段二
在 VM 或者容器中部署业务应用,需要保证业务应用与北极星服务治理中心的网络连通性。
阶段三
开发者在客户端发出的 HTTP 请求里,新增 X-Polaris-Metadata-Transitive-featureenv=f1
请求头即可实现流量染色。
请求头
X-Polaris-Metadata-Transitive-featureenv=f1
是按照北极星定义的请求头格式设置的,其中X-Polaris-Metadata-Transitive-
是北极星需要读取请求头的前缀,例子中的featureenv
为实际的键值对的key,f1
为实际的键值对的value。
原理解析
-
标签筛选:用户传入的env=f1,spring cloud tencent会基于从北极星发现的实例数据,筛选出匹配env=f1的实例,并进行服务调用。
-
标签透传:在微服务的调用链路中,spring cloud tencent框架会将用户的请求标签逐级往下透传,使得每一层调用都可以优先调度都env=f1的实例上。
3 - 网关动态染色
流程简介
如概述所言,测试环境路由的开发工作分为三个阶段:
- 阶段一:实例打标。在多测试环境的场景中,需要对每个测试环境部署的实例进行区分,因此需要在实例上打类似标识实例测试环境类别的标签。
- 阶段二:部署应用。
- 阶段三:流量染色。流量染色即为每个请求打上目标测试环境标签,路由转发时根据请求标签匹配请求。
如下图所示,开发者给每个环境的应用实例进行打标(如 featureenv=f1
),标明其所在的环境类型。阶段二部署业务应用。阶段三中,开发者在网关添加动态流量染色规则来给每个请求添加相应的流量标签,即可完成测试环境路由。
操作指引
阶段一
微服务框架服务注册场景
Spring Cloud Tencent 框架接入
Spring Cloud Tencent 中的 spring-cloud-tencent-featureenv-plugin
模块闭环了测试环境路由全部能力,所有服务只需要添加该依赖即可引入测试环境路由能力。spring-cloud-tencent-featureenv-plugin
默认以 featureenv
标签作为匹配标签,用户也可以通过系统内置的 system-feature-env-router-label=custom_feature_env_key
标签来指定测试环境路由使用的标签键。以下三种方式以默认的 featureenv
作为示例。设置方式详情参考Spring Cloud Tencent 元数据使用说明。
- 方式一:配置文件
在服务实例的配置文件中添加配置,如在 bootstrap.yml
添加如下所示即可:
spring:
cloud:
tencent:
metadata:
content:
featureenv: f1 # f1 替换为测试环境名称
- 方式二:环境变量
在服务实例所在的操作系统中添加环境变量也可进行打标,例如:SCT_METADATA_CONTENT_featureenv=f1
。
- 方式三:SPI 方式
自定义实现
InstanceMetadataProvider#getMetadata()
方法的返回值里里包含featureenv
即可。
注意:基线环境部署的服务实例不需要设置 featureenv
标签,表明其不属于任何测试环境,才可在请求没有匹配到对应测试环境的时候,匹配到基线环境。
kubernetes服务注册场景
北极星提供了polaris-controller,支持直接将pod labels同步为北极星上面的实例标签。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
做完上面2步后,polaris-controller默认会对集群中的服务数据进行全量同步,而pod中的labels也会同步为北极星的实例标签。
阶段二
在 VM 或者容器中部署业务应用,需要保证业务应用与北极星服务治理中心的网络连通性。
阶段三
网关动态染色是开发者配置一定的染色规则,让流量经过网关时自动染色。例如上图红框内所示,把 uid=1
用户的请求都转发到 f1
环境,把 uid=0
用户的请求都转发到 f2
环境。具体的流程是开发者在北极星的页面上添加类似如下图所示的染色规则,然后网关根据染色规则在 HTTP 请求里,新增 X-Polaris-Metadata-Transitive-featureenv=f1
请求头即可实现流量染色。
请求头
X-Polaris-Metadata-Transitive-featureenv=f1
是按照北极星定义的请求头格式设置的,其中X-Polaris-Metadata-Transitive-
是北极星需要读取请求头的前缀,例子中的featureenv
为实际的键值对的key,f1
为实际的键值对的value。
操作步骤:
- 创建配置文件
rule/staining.json
。
- 编辑
rule/staining.json
并应用SCG染色模板(SCG染色模版将在1.11.0版本提供,目前仅支持自定义编写)。
- 保存并发布,该规则配置将下发到对应的SCG应用,后续 HTTP 请求将按照规则进行染色,并根据染色标签路由到不同的测试环境,以实现测试环境路由。
模版里的样例配置的含义是,在 HTTP 请求的参数中拿到 uid
字段,如果等于(EQUAL
) 10001
,那么就在经过的 HTTP 请求的头部自动打上 X-Polaris-Metadata-Transitive-featureenv=feature1
的数据标签。更加详细的规则配置说明如下所示:
配置项 | 配置项说明 | 类型 | 备注 |
---|---|---|---|
rules | 动态染色规则列表 | list | |
conditions | 规则匹配条件列表 | list | |
conditions内项 | 规则匹配条件 | map | |
conditions内项.key | 规则匹配条件原始值 | string | ${http.query.xxx} ${http.header.xxx} ${http.cookie.xxx} ${http.method} ${http.uri} |
conditions内项.values | 规则匹配条件目标值列表 | list | |
conditions内项.operation | 规则匹配条件操作符 | string | EQUALS NOT_EQUALS IN NOT_IN REGEX BLANK NOT_BLANK |
labels | 染色标签列表 | list | |
labels内项 | 染色标签 | map | |
labels内项.key | 染色标签key | string | |
labels内项.value | 染色标签value | list |
Spring Cloud Tencent 实现方式
Spring Cloud Tencent 通过实现 Spring Cloud Gateway 的 GlobalFilter
来实现流量染色插件,开发者只需要添加 spring-cloud-tencent-gateway-plugin
依赖,并在配置文件打开如下所示的染色插件开关即可引入流量染色能力。spring-cloud-tencent-gateway-plugin
插件会默认读取北极星配置中心内的 rule/staining.json
配置作为动态染色规则。
spring-cloud-tencent-gateway-plugin
配置列表:
配置项Key | 默认值 | 是否必填 | 配置项说明 |
---|---|---|---|
spring.cloud.tencent.plugin.scg.enabled | true | 否 | 是否开启网关插件 |
spring.cloud.tencent.plugin.scg.staining | false | 否 | 是否开启网关染色 |
spring.cloud.tencent.plugin.scg.staining.rule-staining.enabled | true | 否 | 是否开启网关动态规则染色 |
spring.cloud.tencent.plugin.scg.staining.rule-staining.namespace | ${spring.cloud.tencent.namespace:default} | 否 | 网关动态规则命名空间 |
spring.cloud.tencent.plugin.scg.staining.rule-staining.group | ${spring.application.name:spring-cloud-gateway} | 否 | 网关动态规则配置分组 |
spring.cloud.tencent.plugin.scg.staining.rule-staining.fileName | rule/staining.json | 否 | 网关动态规则文件名 |
4 - 网关静态染色
流程简介
如概述所言,测试环境路由的开发工作分为三个阶段:
- 阶段一:实例打标。在多测试环境的场景中,需要对每个测试环境部署的实例进行区分,因此需要在实例上打类似标识实例测试环境类别的标签。
- 阶段二:部署应用。
- 阶段三:流量染色。流量染色即为每个请求打上目标测试环境标签,路由转发时根据请求标签匹配请求。
如下图所示,开发者给每个环境的应用实例进行打标(如 featureenv=f1
),标明其所在的环境类型。阶段二部署业务应用。阶段三中,开发者在各个环境的网关添加向请求头插入流量标签的插件,即可完成测试环境路由。
操作指引
阶段一
微服务框架服务注册场景
Spring Cloud Tencent 框架接入
Spring Cloud Tencent 中的 spring-cloud-tencent-featureenv-plugin
模块闭环了测试环境路由全部能力,所有服务只需要添加该依赖即可引入测试环境路由能力。spring-cloud-tencent-featureenv-plugin
默认以 featureenv
标签作为匹配标签,用户也可以通过系统内置的 system-feature-env-router-label=custom_feature_env_key
标签来指定测试环境路由使用的标签键。以下三种方式以默认的 featureenv
作为示例。设置方式详情参考Spring Cloud Tencent 元数据使用说明。
- 方式一:配置文件
在服务实例的配置文件中添加配置,如在 bootstrap.yml
添加如下所示即可:
spring:
cloud:
tencent:
metadata:
content:
featureenv: f1 # f1 替换为测试环境名称
- 方式二:环境变量
在服务实例所在的操作系统中添加环境变量也可进行打标,例如:SCT_METADATA_CONTENT_featureenv=f1
。
- 方式三:SPI 方式
自定义实现
InstanceMetadataProvider#getMetadata()
方法的返回值里里包含featureenv
即可。
注意:基线环境部署的服务实例不需要设置 featureenv
标签,表明其不属于任何测试环境,才可在请求没有匹配到对应测试环境的时候,匹配到基线环境。
kubernetes服务注册场景
北极星提供了polaris-controller,支持直接将pod labels同步为北极星上面的实例标签。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
做完上面2步后,polaris-controller默认会对集群中的服务数据进行全量同步,而pod中的labels也会同步为北极星的实例标签。
阶段二
在 VM 或者容器中部署业务应用,需要保证业务应用与北极星服务治理中心的网络连通性。
阶段三
往请求中加入固定的 Header 是网关最常见的插件,如上图所示。可以在每个环境部署一个网关,所有经过网关的请求都增加 X-Polaris-Metadata-Transitive-featureenv=f1
请求头(其中,f1
替换为对应的测试环境标签)即可。
请求头
X-Polaris-Metadata-Transitive-featureenv=f1
是按照北极星定义的请求头格式设置的,其中X-Polaris-Metadata-Transitive-
是北极星需要读取请求头的前缀,例子中的featureenv
为实际的键值对的key,f1
为实际的键值对的value。
Spring Cloud Tencent 静态染色
在 Spring Cloud 项目中,可以利用 Spring Cloud Gateway 提供的一些方式来帮助实现流量的静态染色,如下所示。所有经过该网关的流量,都在经过的 HTTP 请求的头部自动打上 X-Polaris-Metadata-Transitive-featureenv=f1
的数据标签。
- 配置文件方式添加 HTTP 请求头部
开发者可以在配置文件中,为每一个需要进行流量染色的服务,添加 Spring Cloud Gateway 提供的内置 filter 规则来实现流量染色的 HTTP 请求头部的添加。
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: lb://NAME_OF_SERVICE
filters:
- AddRequestHeader=X-Polaris-Metadata-Transitive-featureenv, f1
具体文档参考:The AddRequestHeader GatewayFilter Factory。
- 代码方式添加 HTTP 请求头部
开发者也可以实现 Spring Cloud Gateway 提供的 GlobalFilter 接口,直接为所有经过网关应用的请求添加流量染色的 HTTP 请求头部。
@Component
public class CustomGlobalFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// get request builder
ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
try {
builder.header("X-Polaris-Metadata-Transitive-featureenv", URLEncoder.encode("f1", UTF_8));
}
catch (UnsupportedEncodingException e) {
builder.header("X-Polaris-Metadata-Transitive-featureenv", "f1");
}
return chain.filter(exchange.mutate().request(builder.build()).build());
}
}