对于基础设施来说,很多服务都有类似的架构、数据库交互和 UI,本文介绍了 Paypal 通过模板自动化基础设施微服务脚手架代码的实践,最大化节约了开发服务的时间并保证了服务的一致性。原文:The Art of Automating Automation[1]
简介
作为 PayPal 网站可靠性和云工程(SRCE, Site Reliability & Cloud Engineering)团队的一部分,我们一直致力于通过自动化提升效率。然而,编写能够让人凭直觉自动化完成工作的软件并不是一件简单的任务。在 PayPal 基础设施中,任何操作的自动化组件都必须提供最高级别的可靠性、安全性、效率和自助服务能力。本文我们将讨论如何在全球网络服务(GNS, Global Network Services)中实现自动化。
GNS 团队有大量的操作需要自动化,范围从需要几小时人力投入的普通任务,到需要运维团队投入很多天精力的复杂任务。对我们来说,最大的挑战是如何在不消耗大量开发周期的情况下自动化这些大大小小的操作,我们需要努力证明“ROI(投资回报)”的合理性,这点特别重要。
软件服务需求
要将任何网络功能转变为服务,需要完成以下一系列任务:
用户界面开发
- 开放给 PayPal 开发社区的所有服务都必须具有某种形式的用户界面(UI),以便用户像使用任何其他服务一样使用网络。
数据库交互和表管理
- 大多数服务需要设计数据库表以及编写数据库交互代码来操作数据。
核心业务逻辑
- 需要编写和测试特定服务的实际业务逻辑。
与自动化工具 Terraform 集成
- 我们的基础用户包括网络运营团队,他们不会使用基于 UI 的服务。相反,他们基于 GitOps 模式运作,这意味着我们开发的所有服务都需要通过开发 Terraform provider 与 Terraform 集成。
认证和授权
- 这涉及到与标准的企业身份验证(如单点登录、多因素身份验证、角色管理等)的集成。
服务帐户,API 消费者的节流和限速
- 我们决定为所有东西提供 API。因此,我们开发的所有服务都必须提供服务帐户,并确保能够节流和限速。
从上面的列表可以看出,构建一个可行的网络服务需要花费大量时间开发重要的外围组件。在理想情况下,我们能够只把时间花在编写核心业务逻辑上,而不做其他事情。通过两种方式,我们达到了编写更少代码的理想状态。
解决这个问题的第一种方法是迁移到真正的微服务组件以及构建可插拔的库架构,第二种方法是基于模板的自动代码生成,可以基于通用模板生成 UI、后端和数据库层代码。
代码生成
长期以来,数据建模一直是设计良好的软件产品的支柱。一旦确定了基本数据构建块,构建围绕数据工作的软件组件就比较容易了。如果数据是以标准格式获取的,那么围绕数据的各种软件组件就有很大的自动化空间。
这正是我们采用的方法。我们团队的所有项目都从识别数据模型开始。数据模型是用 YAML 格式定义的,这样我们的动态代码生成模块就可以为系统的各个部分生成代码。下图显示了这个过程:
GNS 软件架构
UI 代码生成
React 框架已经被包括 PayPal 在内的业界广泛采用。PayPal 应用程序团队有一个非常模块化的 React 库,用于构建面向客户的应用程序。我们以该库为基础,在任何合适的地方使用。
大多数系统程序员都不熟悉 UI 编程。为了促进快速 UI 组件开发,我们依赖于模型驱动设计。使用模型驱动设计,典型的 GNS 开发人员只需指定 UI 布局,不用编写任何 UI 代码。
GNS 代码生成引擎采用用户定义的模型,并使用 React 框架,生成一个独立的 React 代码容器,带有功能完整的 UI。这种方法允许开发人员专注于应用程序的业务逻辑。
后端代码生成
过去,开发提供 REST API 功能的微服务非常繁琐,开发人员需要为每个端点编写软件并配置 web 服务网关。然而,Flask 框架作为标准框架已经得到了 Python 开发人员的广泛认可。类似的,Golang 除了内置支持之外,还有 gorilla/mux 框架。
大多数 GNS 服务是用 Golang 或 Python 编写的。我们在上述框架的帮助下,设计了基于 Jinja 模板生成通用代码的 GNS 代码生成引擎。
基于以 YAML 格式定义的数据模型,代码生成引擎使用预定义的 Jinja 模板来生成服务的基础代码。GNS 开发人员可以在这些代码的基础上实现精确的业务逻辑,从而减少编程错误,并消除从头编写所有内容的乏味工作。
数据库层代码生成
大多数 GNS 服务需要某种形式的数据库来存储建模阶段所描述的信息。编写代码来添加、删除和修改数据库中的条目是很繁琐的,而且容易出现 bug、风格不统一等。Python 和 Golang 拥有处理对象关系映射(ORM, Object Relationship Mapper )的开源库,我们选择采用 sqlalchemy 来规范化数据库操作。
由于模型是用 YAML 格式定义的,我们的代码生成引擎除了生成后端代码外,还生成数据库处理方法。
Terraform Provider 代码生成
Terraform 已经成为自动化基础设施的最常用工具。作为 GNS 服务提供商,我们已经决定所有自动化服务都将有针对 Terraform 的接口,从而能够适配正被不断采用的持续部署流水线。
Terraform 体系架构灵活且方便扩展,能够为我们喜欢的任何自动化添加 Provider。请参阅 terrform 文档了解更多细节。
Terraform Provider 架构
由于 Terraform Provider 是一个构造良好的库,我们的代码生成引擎可以基于 Jinja 模板生成基于 golang 的 Provider 程序,然后将这些代码构建到一个可插拔模块中,该模块可以安装到正在运行的 terraform 实例中。一旦完成,用户就可以在 GNS 服务上进行标准的 terraform 操作,就像任何其他服务一样。
结论
自动化任何网络服务所需的大部分任务已经由我们的代码生成引擎生成,从而允许我们只专注于服务的核心逻辑。转向微服务体系架构以及采用基于模板的代码生成和模型驱动的体系架构使我们能够以更快的速度生产服务。在撰写本文时,我们可以在一天之内完成任何服务的工作框架,从而帮助团队可以专注于核心逻辑,并在更短的时间内产生更多的服务。
References:
[1] The Art of Automating Automation: https://medium.com/paypal-tech/the-art-of-automating-automation-17b32594a41f