对于微服务的开发者而言,拥有一套干净、独占的完整测试环境无疑能够提高软件研发过程中的功能调试和异常排查效率。

然而在中大型团队里,为每位开发者维护一整套专用测试服务集群,从经济成本和管理成本上考虑都并不现实。为此阿里巴巴的研发团队采用了基于路由隔离的”虚拟环境”方法。

“虚拟环境”的本质是基于服务实例(即Kubernetes的Pod实例)上的“环境标”(在Kubernetes表现为Label)属性,结合约定的路由复用规则,形成一个个开发者视角的专属测试环境。这些虚拟的专属环境从集群管理者的视角来看,称为“隔离域”,它具有如下特点:

  • “隔离域”是由路由规则形成的虚拟边界
  • 每个“环境标”都会形成一个独立的“隔离域”
  • “隔离域”之间可以存在部分或完全重合
  • “隔离域”的成员会随集群中服务实例所带“环境标”动态变化

路由规则

虚拟环境的路由规则很简单:如果请求是来自一个带有环境标的服务实例,
它会优先寻找跟它具有相同环境标的实例,如果没有,则会寻找它上一级的环境标,直至到达顶级的默认服务实例

假设A、B、C、D四个微服务组成了一个完整的测试环境。

此时若为集群中的服务实例全部赋予环境标dev,就形成了一个隔离域,如下图蓝色部分所示。结合虚拟环境的实践,我们称这个隔离域为“公共基础环境”(也称默认环境)。

KT-env目标及功能 - 图1

当进行特定项目开发的时候,开发者不需要重新部署整套微服务系统,而是单独部署需要修改的部分服务(如服务C和服务D),为它们赋予一个子级环境标,比如dev.proj,然后加入到测试环境中。

根据路由规则,当请求来自带有dev.proj环境标的实例C,需要调用服务B,但是发现没有带环境标dev.proj的服务B实例,于是会寻找带有上一级环境标dev的服务B实例。同理当链路到达服务C时,会由dev环境标的实例响应,而由于服务D存在dev.proj环境标的实例,所以这部分实例会接管到达服务D的请求。

因此dev.proj环境标所形成的隔离域边界下图红色区域所示,这便是dev.proj虚拟环境的服务实例集合。

KT-env目标及功能 - 图2

不难看出,dev.proj虚拟环境复用了部分公共基础环境的资源(服务A和服务B)。这样做的好处是,第一不会占用大量的计算资源;第二,不会影响公共基础环境的稳定性。

开发者还可以将本地开发机加入虚拟环境。比如小明在本地启动了一个服务C的实例,他给这个服务实例打上环境标dev.proj.local,基于前面介绍的路由规则,带环境标的服务发出的请求会优先寻找带相同环境标的服务实例,如果找不到则会逐级寻找带有上一级环境标的实例。于是环境标为dev.proj.local的服务C、环境标为dev.proj服务D和公共基础环境dev中的服务A、服务B就组成了一个新的的虚拟环境,如下图红色部分所示。

KT-env目标及功能 - 图3

这时小明的同事在本地启动了一个服务A,如果他没有对这个服务打环境标,则他的所有调用请求会默认使用“公共基础环境”进行测试。因此小明在自己的虚拟环境中的任何调试都不会影响到他的同事,反之亦然。如下图所示。

KT-env目标及功能 - 图4

若小明的同事加入了小明所在的项目,他们之间需要进行“联调”。这时,他只需将本地的服务打上一个和小明相同的环境标即可,如下图红色部分所示。

KT-env目标及功能 - 图5

总结而言,虚拟环境是通过在服务实例(以及从这些实例发出的请求)上携带约定标签,将个别需要调试或测试的特定版本服务实例与其他公共服务实例组成临时虚拟集群的一种环境管理实践。