cover_image

收钱吧多泳道环境的演进

刘宁 SQB Blog
2022年04月19日 08:00
图片

我们知道,在研发过程中往往需要多套环境以满足不同的阶段的研发需求,如开发、测试、预发布环境。好的环境方案可以提高开发调试、项目测试的效率,也可以降低上线的风险,从而缩短整个需求的交付周期,提高生产效率。

为应对业务快速发展的需求,收钱吧在多环境的治理上经历了数个版本的迭代。本文主要介绍这几代测试环境的发展与技术实现。

早期测试环境

2018年之前,收钱吧的测试环境是两套物理隔离的环境:

  • 给予独立的硬件资源
  • 每个服务为每个环境准备独立的配置文件

使用Jenkins[1]+Docker[2]部署,两套环境之间互不影响。这套部署方案,技术上相对成熟,操作上简单直观,但存在以下的问题:

  • 测试环境新增服务需要运维介入,创建Jenkins任务、配置Jenkins脚本、配置域名解析等,流程繁琐
  • 需要切换服务分支时,Jenkins需要checkout源码、编译源码、构建Docker镜像、部署服务,整个流程耗时较久
  • 同一个服务只能有两个需求并行开发测试,无法满足快速增长的需求
  • 每个服务的配置文件是工程师手动维护,如果配置出错,有可能造成两套环境的交叉调用
  • 很难拓展出第三、四套环境,需要大量的硬件资源以及需要为每个服务新增配置文件
图片

以上问题也对应着我们的各种诉求:

  • 我们想要研发同学不需要太多的运维知识就能快速部署新服务
  • 我们想要服务分支的切换更加快捷容易
  • 我们不想要跟其他人抢环境,不想测试到一半被人切了分支
  • 我们想要减少一些重复的工作
  • ...

多泳道环境 1.0

2018年,收钱吧决定将服务迁往Kubernetes[3]集群,原来的CI构建也从Jenkins迁移到Gitlab CI[4]。Gitlab CI的使用,使得从checkout源码到构建Docker镜像的整个流程透明化,而依托于Kubernetes的能力,服务部署、升级等操作流程也不再繁琐,更容易与内部系统集成,实现自动化。

虽然将服务迁移到Kubernetes集群解决了测试环境中的很多问题,但在业务需求快速迭代的场景下,测试环境最核心的诉求:同一个服务在环境中能够多版本共存,并没有得到有效解决。

在Kubernetes原生网络中,让请求访问同一个服务的两个不同版本,我们只有两种选择:

  1. 多个版本的Pod配置相同label,Service中配置对应selector。这种情况下,流量在不同版本的Pod之间随机路由,显然无法在这样的场景下做测试。
  2. 不同版本配置不同的Service。这种情况相当于把服务的不同版本当成不同的服务处理。想要让下游服务访问特定版本,需要下游服务修改配置文件,这也不是可行的方案。流量的路由应该由用户决定,而不是由链路中的某个节点决定。

多泳道环境的构思

显然Kubernetes原生网络无法提供足够的支持,我们需要能够精确控制流量路由到哪个版本。在此背景下,受到阿里特性环境[5]的启发,我们提出了多泳道环境的构想。蓝图如下,同时引入了环境泳道的概念。

图片

环境泳道是逻辑而非物理上的概念,同一泳道的服务之间可以直接访问,跨泳道的访问需要携带对应标识,访问的服务在泳道内不存在,请求也不携带标识,则默认路由到基础泳道。

若干个环境泳道,组成了多泳道环境:

  • 同一服务不同版本,使用同一个域名,服务发现由底层设施负责
  • 环境泳道可以任意创建和释放
  • 入口请求的流量需要带上特殊标识,来标识流量所属泳道
  • 每个服务透传请求携带的标识

这样的设计之下,我们认为传统的物理上的多环境将转变成逻辑上的多环境,从而可以大量节省硬件资源,处于开发、测试阶段的项目不会再因为环境数量限制而导致排队等待了,另外通过底层设施来控制路由,也不会再出现不同环境交叉使用的乱象。

依托于Istio的实现

以上构想,正是当时Service Mesh[6]着力解决的问题。不管是RedHat,还是Nginx[7],给出的Service Mesh方案都是使用Control Plane + Sidecar[8] Proxy的模式。所以工程效率团队调研了当时相对成熟的解决方案Istio[9]

我们从Istio的Bookinfo[10]这个样例上可以了解到,Istio流量管理的核心功能是通过两份CRD[11]--VirtualServiceDestinationRule的配置来完成。

其中VirtualService用于配置路由规则,它可以作用于L4、L7,对于常见的HTTP流量还可以对header、uri、queryParams等进行匹配路由,如:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews-route
spec:
  hosts:
  - reviews.prod.svc.cluster.local
  http:
  - name: "reviews-v2-routes"
    match:
    - uri:
        prefix: "/wpcatalog"
    route:
    - destination:
        host: reviews.prod.svc.cluster.local
        subset: v2
  - name: "reviews-v1-route"
    route:
    - destination:
        host: reviews.prod.svc.cluster.local
        subset: v1

DestinationRule定义了服务的不同版本,如:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: bookinfo-ratings
spec:
  host: ratings.prod.svc.cluster.local
  subsets:
  - name: testversion
    labels:
      version: v3
    trafficPolicy:
      loadBalancer:
        simple: ROUND_ROBIN

这样来,对于多泳道环境的构思,依托于Istio的能力,可以被简化成以下逻辑:

if headers.x-env-flag == v2:
    route(subset_v2)
else if request.sourceLabels.version == v2:
    request.headers.x-env-flag = v2
    route(subset_v2)
else:
    route(subset_v1)

利用基础设施层进行流量的路由的实现还有个显而易见的好处:对当前服务的改造成本极小。当时第一批接入的后端服务,只需要升级RPC库的版本即可。

另外,我们也配套开发了多泳道环境管理平台——Volac。它的作用便是创建环境泳道,并根据环境泳道配置对应的VirtualService和DestinationRule。

改造后测试环境的控制逻辑如下图:

图片
  1. Volac创建VirtualServiceDestinationRule,并部署服务
  2. Istio给服务注入Envoy容器作为sidecar,同时Istio控制面监听VirtualServiceDestinationRule的变化,动态地给Envoy下发路由配置。

改造后的业务流量如下图:

图片
  1. 带特定标识的请求,会路由到特定的环境
  2. 环境泳道中没有对应服务,请求会路由到基础泳道

多泳道环境 2.0

经过上述改造,基本解决了早期测试环境中的问题,但是却带来了新的问题。

公司内部服务部署系统涉及很多业务方面的需求,例如:

  • 用户、权限管理
  • 应用管理
  • 发布窗口管理
  • 发布审核
  • ...

也涉及很多技术方面的细节,如:

  • 调用Kubernetes接口部署服务
  • 使用Istio API创建资源
  • ...

综合以上,在多泳道环境管理平台Volac的实现过程中,还存在一些问题:

  • 业务和技术的过度耦合
  • 过度依赖第三方的实现实现,即Istio,Service Mesh解决方案可能存在更好的实现
  • 服务配置状态存储在数据库,无法迅速完成多集群迁移和扩展

基于以上原因,我们将Volac的业务逻辑与技术细节拆解:

  • 业务逻辑演变为Next平台:收钱吧内部集应用发布、项目管理、研发效能报表等于一体的平台
  • 技术细节实现演变为elastic-env-operator[12]Kubernetes的方式[13]

最终,测试环境的控制逻辑如下:

图片

至此,依托于Kubernetes的CRD扩展和operator,测试环境实现了:

  • 不依赖于业务,可以独立存在
  • 更好的扩展性,如支持监控系统的VictoriaMetrics
  • 不与第三方实现紧耦合,可在业务无感知的情况下替换实现
  • 可以迅速将环境扩展或迁移到多个集群

写在最后

多泳道环境1.0在2019年上线,最终带来了很多直接和间接收益。

直接收益:

  • 去掉了一套固定环境,节省了将近一半云服务器资源。随着服务数量的不断增长,这项收益也在不断变大
  • 项目不再需要维护两份测试配置,节省了人力,减少了出错成本
  • 环境按需伸缩(现在运行着近600套环境),需求交付不再需要排队等待测试环境,提高了交付效率。随着业务发展,这项收益也越发明显

间接收益:

  • 环境实现自动化,更容易与CI/CD集成,减少人工维护,节省成本
  • 环境更易迁移与扩展,为异云部署打下基础

关于作者

刘宁,来自技术平台部



参考资料

[1]

Jenkins: https://www.jenkins.io/

[2]

Docker: https://www.docker.com/

[3]

Kubernetes: https://kubernetes.io/

[4]

Gitlab CI: https://docs.gitlab.com/ee/ci/

[5]

在阿里,我们如何管理测试环境: https://developer.aliyun.com/article/688852

[6]

What's a service mesh?: https://www.redhat.com/en/topics/microservices/what-is-a-service-mesh

[7]

What Is a Service Mesh?: https://www.nginx.com/blog/what-is-a-service-mesh/

[8]

Microsoft: Sidecar Pattern: https://docs.microsoft.com/en-us/azure/architecture/patterns/sidecar

[9]

Istio: https://istio.io/latest/

[10]

Bookinfo Application: https://istio.io/latest/docs/examples/bookinfo/

[11]

Extend the Kubernetes API with CustomResourceDefinitions: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/

[12]

Wosai/elastic-env-operator: https://github.com/WoSai/elastic-env-operator

[13]

Extending Kubernetes: Operator Pattern: https://kubernetes.io/docs/concepts/extend-kubernetes/operator/

图片

图片


继续滑动看下一个
SQB Blog
向上滑动看下一个