查看原文
其他

VCS 集成的 Database CI/CD 工作流落地实践

cy Bytebase 2022-12-19


繁琐的数据库变更流程

你是否被繁琐的数据库变更流程所困扰?
数据库变更一直是应用发布中最为关键的步骤,要想提升应用 CI/CD 的效率,必然需要做好数据库变更管理。伴随着业务复杂度的提升与数据库实例的增加,变更管理的难度也在成倍增长。来看看以下场景是否熟悉?
  • SQL 脚本散布在不同开发者电脑中,修改、汇总过程需要反复人工确认;

  • 在割裂的多个系统中提交变更请求,繁琐又可能遗漏;

  • 脚本最终执行前 DBA 才介入审核 SQL,阻止问题 SQL 将延迟应用发布,通过则埋下长期隐患;

  • 变更请求复杂多变,设想 N 个略有不同的 SQL 脚本对应多个应用版本,如果只是把 SQL 脚本存放在普通文档上,编写者或执行者的任何疏忽都可能造成灾难性后果;

  • 变更脚本的归档与事后追踪审计更是无从谈起。
如果你只需要管理一两个数据库,这些也许都不是问题,但是当你面对少则十多个,多则上千个的实例时,相信你已经不堪忍受「折磨」。数据库变更的每个独立环节都不缺乏相应的工具,我们有代码管理平台,有五花八门的工单系统,还有多种 SQL 审核工具,但为什么这一过程体验仍然如此糟糕?
所有低效的协作都源于流程的割裂与信息的封闭,如果能将变更管理全流程打通,实现信息的高效流动,同时借此将开发与 DBA 团队的工作边界进行合理的优化,必将带来工作效率的显著提升。
Bytebase(一款聚焦数据库变更管理的工具,旨在提升数据库变更过程中的安全性与效率)与 VCS 集成的 Database CI/CD 工作流来拯救你了!
在此前的文章基于 GitHub 的数据库 CI/CD 最佳实践中,我们提出了一个完整的 Database CI/CD 流程。
在下文中,我们将从组织管理的视角切入,探讨如何设计一个真正可落地的方案。

确定组织的研发管理流程

每一个组织受到历史部门划分、技术栈、业务形态等多种因素影响,会逐渐形成适合自身的研发管理流程,并且轻易难以改变,要优化其中的 Database CI/CD 这一环节,自然先要从梳理整体流程入手研发管理流程的分类方法有很多,但我们的目标是优化变更管理,因此从应用迭代的方式,可以将其分为两种形式:

集中式迭代

将多个应用组织在一起,一个周期一次版本发布,按批次来管理。这种情况一般是由于业务应用功能耦合性较强,牵一发而动全身,因此变更时需要将上下游的关联业务进行通盘规划,常见于一些如金融等业务复杂度较高的传统行业。

分布式迭代

为了提升业务迭代效率,越来越多的组织尝试尽可能的对应用解耦,由每个团队独立负责自身应用或模块的开发与发布。一些新兴组织如互联网企业、SaaS 公司等,采用的都是这种模式,微服务就是这种模式的典型代表。

大多数组织并不会完全采用某种形式,特别是对于一些大型组织,在不同部门、新旧业务、核心与边缘业务之间,也都可能尝试不同的迭代模型,而我们需要做的就是结合不同的模型,设计最适合这类应用的 Database CI/CD 方案。

界定数据库的管理边界

在确定的应用迭代流程下,自然也就衍生出了不同的数据库管理方式。我们需要清晰的界定出数据库在不同团队间的管理边界,这一步骤非常重要,不同的管理方式决定了应以何种方式对流程进行优化。DBA 是数据库的负责人,我们的管理边界分析自然也应该围绕这一角色进行。虽然一些组织拥有较为成熟的 DBA 团队,另一些组织则可能完全没有 DBA 这一角色,但无论如何,数据库管理尤其是变更管理这一工作是无法避免的,区别仅仅是由谁来负责,常见的方式有以下三种:
  1. DBA 全面负责数据库所有工作,管理边界划在了 DBA 与开发团队之间,开发团队仅负责提交变更请求,难以触及数据库的管理工作;
  2. 开发团队完全自治管理,一般是由于组织中没有 DBA,甚至可能没有专门的基础平台团队,管理边界划在了不同开发团队之间,每个项目团队仅负责自己的数据库;
  3. DBA 全面统筹规划数据库相关工作,但开发团队较为深度的参与其中,因此部分关键工作仍整体归属于 DBA,同时有一些工作被分配给了开发团队,并且也按项目进行划分。

在以 Database DevOps 为目标的组织中,应该鼓励开发团队更深入的参与到数据库变更工作中,而 DBA 应该基于自身的专业深度,站在更高的视角协同基础平台、SRE 等团队制定数据库管理框架,包括管理工具选型、审核策略制定、自动化 CI/CD 流程落地等,通过赋能开发团队来提升整体效率,而非以一己之力去应对大量的琐碎基础工作,毕竟在很多组织中一名 DBA 往往面对的是上百名开发者。基于这一目标,我们强烈建议采用第三种模式,即 DBA(或基础平台部门)与开发团队协同构建数据库管理框架,并允许开发团队在受控状态下接触数据库。
当然,不同的组织可以结合自身研发流程与业务特点,更具体的决定将哪些工作交给开发团队自治:
  • 采用集中式迭代的组织,由于业务的复杂度更高,DBA 需要深度管控每一批次具体的变更工作,但并不妨碍在测试、预集成等早期阶段展开与开发团队的变更协作,这将大大提升最终生产环境的发布效率。
  • 采用分布式迭代的组织,大量的工作甚至包括生产环境的变更审核权都被交给了开发团队,少量 DBA(甚至没有) 只参与部分最关键的环节,或是解决一些较为复杂的问题。


Database CI/CD 落地实践

在明确了自身组织的研发管理特点后,可以展开具体的集成了 VCS 的 Database CI/CD 的落地工作了。

引入 VCS 进行变更脚本的管理

第一件要做的事,是让混乱的 SQL 脚本进行有序的管理。SQL 也是代码的一种,使用诸如 GitLab, GitHub 这样的版本控制系统(VCS)对其进行管理是明智的选择。为了确保可管理性,我们需要对 SQL 脚本在 VCS 的存放目录结构进行合理的设计。
按应用项目进行脚本的分类存储
对于分布式迭代的组织,大多数时候每一个数据库都归属于一个或一类特定的应用,并以此作为管理边界。Bytebase 延用了这种管理模式,即按照应用项目来组织数据库的管理,这也符合大多数组织的管理习惯,因此建议将变更脚本以应用项目名作为根目录进行分类。这些脚本可以被存放在各自应用的代码仓库,也可以统一存放于一个代码仓库,取决于组织的管理习惯。
按变更批次进行脚本的分类存储
对于集中式迭代的组织,由于每一批次的变更可能涉及多个应用,并且这些脚本是相互关联和影响的,因此更倾向于在 VCS 中将变更脚本按批次进行分类存储,而非按应用进行分类,这就意味着在每一个批次目录下包含了多个应用数据库的变更脚本,为了方便管理,建议在批次目录下采用环境名或数据库名进行脚本的分类。而在 Bytebase 中,为了管理数据库的审核权限,仍然建议按照应用项目进行分组管理。

让开发者进行 SQL 自助预审核

为了避免应用将要发布时才发现糟糕的 SQL,应该在开发者的工作界面(VCS)就引入预审核机制,帮助开发者在脚本编写阶段就发现违反规范的语句。常见的检查项分类如下:
  • 语法正确性:基础的标准 SQL 语法检查。

  • 语句可执行性:语句关联的对象是否存在,例如创建索引时目标表应该存在,这种检查既包括对脚本上下文的检查,也包括对库内已有 Schema 的检查。

  • 命名风格检查:表名、索引名、字段名等应该富有含义且易于管理,例如索引名应该包含对应的表与字段,而表名不建议采用特殊字符。

  • 建表规则检查:如必须有主键、必须有字段注释等。

  • 建索引规则检查:如限制索引类型、限制索引字段数量、限制索引字段类型等。

  • 字段规则检查:如限制字段的类型、长度、默认值等。

  • 查询限制:如查询必须带有过滤条件等。
Bytebase 内置了近百条较为常见和通用的开发规范,并且支持结合企业自身业务特点的自定义规范。每条配置为生效的规范都可以设置 Error(禁止通过)与 Warnning(可强制通过)两个告警等级,同时可以选择禁用该规范。为了确保开发规范可落地,强烈建议 DBA 与开发团队共同商定 SQL 开发规范与告警等级,并决定在不同阶段应该启用哪些规范。
生产实践中,一个应用常常包括开发、测试、预上线、生产等多个环境,为了平衡开发效率与安全性,在不同阶段应该采用不同的审核策略,但建议至少从测试环境开始,就应该将 SQL 脚本纳入VCS 管理。下图给出了一个粗略的分阶段策略(细粒度的规范设置应结合自身业务特点确定):
  • 在脚本的创建阶段,通过 Bytebase 提供的与 VCS 集成的审核能力(开启 SQL Review Actions | Database CI/CD with GitHub 教程 ①)即可对 SQL 语句进行各项约束的预检查,帮助开发者识别违反规范的语句,为了兼顾开发效率,可以考虑对违规 SQL 仅做告警提示。
  • 在 SQL 的执行阶段,Bytebase 将启动二次检查,越接近生产环境,执行阶段的审核应该越趋于严格。

定义自动化的部署工作流

我们的目的不仅是变更脚本的分类保存,更重要的目标是将整个变更发布流程完全打通,实现脚本提交即发布。Bytebae 提供了这样的能力,通过识别指定代码仓库下的脚本路径,每一个脚本都可以被关联到指定的数据库,进而实现全自动的变更发布。先来看一例 Bytebase 的路径匹配模板:
Base_DIR/{{ENV_NAME}}/**/{{DB_NAME}}__{{VERSION}}__{{TYPE}}__{{DESCRIPTION}}.sql
在这个目录结构中:
  • Base_DIR 为指定的任意根目录(可多级);

  • {{ENV_NAME}} 为占位符,映射为 Bytebase 中的环境属性;

  • ** 为通配符,匹配任意一级或多级目录;

  • {{DB_NAME}} 为占位符,映射为需要变更的数据库名;

  • {{VERSION}} 为占位符,映射为本次变更的版本号;

  • {{TYPE}} 为占位符,映射为变更类型是 DDL 还是 DML;

  • {{DESCRIPTION}} 为占位符,映射为脚本简述;
通过将「占位符」与「通配符」搭配,可以在任意目录结构下精准的匹配到 Bytebase 所管理的目标数据库。
应用项目进行脚本的分类存储模式下,VCS 中的脚本分类结构与 Bytebase 中的数据库分类结构是一一对应的,Bytebase 中的每一个 Project 都只监控与自己对应目录下的脚本变化。
变更批次进行脚本的分类存储模式下,VCS 中每一个批次下的变更脚本与Bytebase 中的数据库分类结构是一对多的关系,但通过占位符的合理设置,每一个变更脚本仍然能精准匹配到指定的数据库。

在 Bytebase UI 界面完成最终的配置

最后我们要做的就是按照上述的规划,在 Bytebase 中将其逐一落地。
这一过程可以被具体分为三项主要工作:
1. 创建 Project
按照确定的数据库管理边界将组织内部的数据库分为若干组,并分配给不同的 project,开发团队的管理边界将通过 project 来界定,而 DBA/运维/Platform 等团队可以在全局拥有权限。
2. 配置 SQL 审核策略
结合与开发团队商定的审核规范以及告警等级,在不同的环境激活相应的规范。
3. 激活 GitOps 工作流
结合 VCS 中的目录结构设计,在指定 project 中配置对应的监控模板,实现对 VCS 中提交文件的监控,并自动生成工单流程。
更详细的配置实现请参考此前发布的文章:实现数据库 GitOps|Database CI/CD with GitHub 教程

产品体验官|基于 GitHub 的数据库 CI/CD

DevJoy 游园会:一起来摆摊!

还有一些 TiDB 没有配上 Bytebase|PingCAP 用户峰会

叮!福利:SaaS 工具分享群


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存