实现基于 Azure DevOps 的数据库 CI/CD 最佳实践
数据库变更一直是整个应用发布过程中效率最低、流程最复杂、风险最高的环节,也是 DevOps 流程中最难以攻克的阵地。那我们是否能在具体的 CI/CD 流程中,像处理代码那样处理数据库变更呢?

DORA 调研报告
DORA(DevOps Research & Assessment)是一家专注于 DevOps 的研究机构, 在该领域以专业与客观著称。自 2014 年以来,DevOps 调研了全球范围内超过 32,000 名专业人员,并以年度报告的形式对外发布研究成果。DORA 明确指出,将数据库变更纳入应用发布流程将显著提升整体发布效率。

这一结论并不令人意外。问题是,该怎么做?
一个完整的基于 Azure DevOps 的数据库 CI/CD 工作流

通过 Bytebase,我们将实现一个完整的基于 Azure DevOps 的数据库 CI/CD 工作流:
- 开发者将变更 SQL 脚本提交到代码分支;
- 触发 Bytebase 提供的 SQL 审核 CI 进行自动化 SQL 审核,并给出修改建议;
- 修改完成后的 SQL 脚本合并入主分支;
- 自动触发发布流程,脚本将被推送到 Bytebase 中;
- Bytebase 内置的自动审核将对变更语句进行二次确认,根据变更风险等级自动匹配审批流,根据审批流进行审批;
- 审批后的语句可手动或自动触发在目标库中执行;
- 变更完成后的数据库最新 schema 结构将被自动回写入代码仓库;
- 确认变更完成后,触发下一阶段的应用发布流程。
通过 Bytebase 社区版实现
让我们一步一步看看这个过程怎样实现的。
第一步 通过 Docker 启动 Bytebase,并配置外部 URL
ngrok 是一个反向代理工具,我们需要它的公网地址,以便从 GitHub 接收 webhooks。这里使用 ngrok 是出于测试目的;对于生产使用,我们建议使用 Caddy。

- 登录 ngrok Dashboard,并按照 Getting Started 步骤进行安装和配置。
- 在 Docker 中运行 Bytebase:
docker run --init \--name bytebase \--restart always \--publish 5678:8080 \--health-cmd "curl --fail http://localhost:5678/healthz || exit 1" \--health-interval 5m \--health-timeout 60s \--volume ~/.bytebase/data:/var/opt/bytebase \bytebase/bytebase:2.10.0 \--data /var/opt/bytebase \--port 8080
- Bytebase 在 Docker 中成功启动,你可以通过
localhost:5678来访问。注册一个管理员账号。 - 在命令行运行
ngrok http 5678,并获得公共 URL。

- 登录 Bytebase,点击右上角的齿轮,将公共 URL 填入到网络部分的外部 URL,点击更新。
第二步 在 Bytebase 种添加 Azure DevOps Service 作为 Git Provider
- 通过公共 URL 来访问 Bytebase,点击右上角的齿轮 > 集成 > GitOps,选择 Azure DevOps Service,点击下一步。你会进入到第二步,拷贝 Redirect URI。点击 直达链接 访问你的 Azure DevOps 账号。

- 在 Azure DevOps 的应用注册页面,填写表格如下并保存:
- Company name: 可以任取一个名字,比如
bb - Homepage URL:
https://bytebase.com - Authorization callback URL: 从 Bytebase 步骤 2 复制的 Redirect URI
- Authorizied scopes: 找到 Code (full), Identity (read), Project and team (read), Build (read and execute)

- 点击 show,复制 Application ID 和 Client Secret,然后粘贴到 Bytebase 的 GitOps 配置页面步骤 2 里。

第三步 在 Bytebase 中配置一个 GitOps 工作流
- 访问 Azure DevOps,并建立一个新项目 bytebase-gitops。
- 访问 Bytebase,进入项目 Sample Project。点击 GitOps 标签,选择 GitOps 工作流。点击 配置 GitOps。
- 选择 Azure DevOps(就是你在上一步配置的),然后选择 bytebase-gitops 这个项目。你会来到步骤三,保持其它参数不变,滑动到页面底部,勾选 基于 Azure DevOps Pipeline 开启 SQL 审核。点击完成。

- 系统会自动在 Azure DevOps 中建立实现 CI 的 PR,点击 Complete 手动合并。回到目录,可以看到 pipeline 自动生成。

- 回到 Bytebase,你会见到 GitOps 工作流已设置成功。
第四步 建立一个 PR(合并请求)去触发 SQL 审核 CI
- 点击界面顶端环境,你可以看到在 Prod 最下方有了一个 SQL 审核策略,点击编辑,你会看到有 3 条开启的规则。它们将通过 CI 应用。我们将非空的等级调为错误。

- 为了测试 SQL 审核 CI,我们将创建一个合并请求来更改 Prod 数据库 schema。不过,我们会让它先违反下 SQL 审核策略。Azure DevOps 上的 bytebase-gitops-az。单击新建分支,命名为 add-nickname-table-employee,点击创建分支。
- 在新分支上创建子目录 bytebase,并创建子子目录 prod。在 prod 目录中创建文件 employee##202310201700##ddl##add_nickname_table_employee.sql。将以下 SQL 脚本复制到文件中,并提交更改。
ALTER TABLE "public"."employee" ADD COLUMN "nick_name" text;
- 创建包含上述提交的合并请求。SQL 审核 CI 将自动运行并显示失败消息。点击 Tests 可以看到具体的违反规则。

- 更新 SQL 脚本并提交到当前分支。SQL 审核 CI 将再次运行并显示通过信息。单击 Complete。
ALTER TABLE "public"."employee" ADD COLUMN "nick_name" text NOT NULL DEFAULT '';

- 返回 Bytebase 中的 Sample Project,你会看到推送事件开启了一个工单。

- 到问题详情页面。因为没有配置审批流或手动发布,此工单会自动发布。你可以点击查看变更来查看差异。

通过 Bytebase 企业版解锁更多功能
你可以升级到企业版,解锁更多功能。点击页面左下角的开始免费试用并升级到企业版,点击顶部实例,为现有的两个实例分配证书。
手动发布
在环境 > 2.Prod,找到发布策略,然后选择 人工发布 > 需要 DBA 或者 Bytebase 实例所有者发布。

自定义审批
- 访问设置 > 安全性 & 策略 > 自定义审批。将项目 Project Owner -> DBA 设置为DDL > 高风险的审批流。

- 访问设置 > 安全性 & 策略 > 风险中心。点击添加规则,然后点击加载第一个模板,点击添加。

最新 schema 写回
Schema 变更完成后,Bytebase 会将最新 schema 写回 Git 代码库。这样,团队在 Git 中就始终有一个数据库 schema 的标准真实源。
- 返回 Azure DevOps,新建一个分支 add-country-table-employee。在 bytebase/prod 目录下创建文件
employee##202310201700##ddl##add_country_table_employee.sql。将以下 SQL 脚本复制到文件中并提交更改。ALTER TABLE "public"."employee" ADD COLUMN "country" text NOT NULL DEFAULT ''; - 返回 Bytebase,转到新创建的工单,它符合 Project Owner -> DBA 的审批流程。

- 按照审批流程点击批准后,横幅将显示等待发布。然后,负责人就可以点击发布了。
- 回到 GitLab,你会发现在
bytebase/prod/下有一个新的文件.employee##LATEST.sql,包含了 Bytebase 写回的最新 schema。(这里需要开启推送到 main 的权限)

Schema 漂移
Bytebase 内置了 schema 漂移检测功能,可以检测到意外的 schema 变更。让我们使用 SQL 编辑器管理员模式来模拟一下。
点击右上角的终端图标(SQL 编辑器)。你将跳转到 SQL 编辑器。点击管理员模式。在此模式下所做的一切与直接连接服务器相同,Bytebase 不会记录。
选择左侧的 (Prod) Employee,粘贴并运行以下脚本:
ALTER TABLE "public"."employee" ADD COLUMN "city" text NOT NULL DEFAULT '';
- 返回 Bytebase 主页,点击顶部的数据库, 选择 Prod 下的 employee。点击现在同步。看到成功消息后,刷新页面。你将看到 schema 漂移。你可以在实例详情页配置自动扫描,以避免手动同步。

- 访问异常中心,也会看到 schema 漂移。
总结
有了 Bytebase,你就有了一套完整的 Azure DevOps 数据库 CI/CD 工作流程。你可以将此工作流程应用到自己的项目中,并根据自己的需要进行定制。 Bytebase 也支持 GitLab,GitHub,以及 Bitbucket。具体的配置步骤可以查看 Bytebase 官网文档。
💡 更多资讯,请关注 Bytebase 公号:Bytebase
相关文章:
实现基于 Azure DevOps 的数据库 CI/CD 最佳实践
数据库变更一直是整个应用发布过程中效率最低、流程最复杂、风险最高的环节,也是 DevOps 流程中最难以攻克的阵地。那我们是否能在具体的 CI/CD 流程中,像处理代码那样处理数据库变更呢? DORA 调研报告 DORA(DevOps Research &am…...
上海实习小记
8月3日入职10月27日离职,原本还想做满3个月再走,可惜公司提早要迁到成都,就只好 离职了回学校了。在博客随便写写记录一下这几个月的生活吧,想到哪里写到哪里 实习的公司是一个小公司,开发一款类似于咸鱼之王的游戏&am…...
uniapp实现路线规划
UniApp是一个基于Vue.js框架开发的跨平台应用开发框架,可以同时构建iOS、Android、H5等多个平台的应用。它使用了基于前端技术栈的Web开发方式,通过编写一套代码,即可在不同平台上运行和发布应用。 UniApp具有以下特点: 跨平台开…...
飞利浦双串口51单片机485网关
主要功能将PC端的数据接收下来,分发到不同的设备,也是轮询设备数据读取回来,打包回传到PC端,数据包包头包尾识别,数据校验,接收超时处理,将协议结构化处理,协议的改动不需要改动程序…...
生态扩展:Flink Doris Connector
生态扩展:Flink Doris Connector 官网地址: https://doris.apache.org/zh-CN/docs/dev/ecosystem/flink-doris-connector flink的安装: tar -zxvf flink-1.16.0-bin-scala_2.12.tgz mv flink-1.16.0-bin-scala_2.12.tgz /opt/flinkflink环境…...
HarmonyOS(二)—— 初识ArkTS开发语言(上)之TypeScript入门
前言 Mozilla创造了JS,Microsoft创建了TS,而Huawei进一步推出了ArkTS。因此在学习使用ArkTS前,需要掌握基本的TS开发技能。 ArkTS介绍 ArkTS是HarmonyOS优选的主力应用开发语言。它在TypeScript(简称TS)的基础上&am…...
从零开始实现神经网络(一)_NN神经网络
参考文章:神经网络介绍 一、神经元 这一神经网络的基本单元,神经元接受输入,对它们进行一些数学运算,并产生一个输出。 这里有三步。 首先,将每个输入(X1)乘以一个权重: 接下来&…...
C语言 每日一题 Day10
1.使用函数判断完全平方数 本题要求实现一个判断整数是否为完全平方数的简单函数。 函数接口定义: int IsSquare(int n); 其中n是用户传入的参数,在长整型范围内。如果n是完全平方数,则函数IsSquare必须返回1,否则返回0。 代码实…...
C++继承——矩形和长方体
Rectangle矩形类 /*矩形类*/ class Rectangle { private:double L 0;double W 0; public:Rectangle() default;Rectangle(double a, double b);double GetArea(); /*矩形面积*/double GetGirth(); /*矩形周长*/ }; /*构造函数*/ Rectangle::Rectangle(double a, double b) …...
代码随想录打卡第五十八天|● 583. 两个字符串的删除操作 ● 72. 编辑距离
583. 两个字符串的删除操作 题目: 给定两个单词 word1 和 word2 ,返回使得 word1 和 word2 相同所需的最小步数。 每步 可以删除任意一个字符串中的一个字符。 题目链接: 583. 两个字符串的删除操作 解题思路: dp数组的含义&am…...
面试流程之——程序员如何写项目经验
在简历中介绍IT项目经验,你可以遵循以下步骤: 明确项目目标:首先,清晰地阐述项目的目标。这可以是提升某个软件的性能,改进某个系统的用户界面,或者增加某款产品的功能。让读者了解你的工作与项目的整体目…...
框架安全-CVE 漏洞复现DjangoFlaskNode.jsJQuery框架漏洞复现
目录 服务攻防-框架安全&CVE复现&Django&Flask&Node.JS&JQuery漏洞复现中间件列表介绍常见语言开发框架Python开发框架安全-Django&Flask漏洞复现Django开发框架漏洞复现CVE-2019-14234(Django JSONField/HStoreField SQL注入漏洞ÿ…...
基于SSM的理发店管理系统
基于SSM的理发店管理系统的设计与实现~ 开发语言:Java数据库:MySQL技术:SpringSpringMVCMyBatis工具:IDEA/Ecilpse、Navicat、Maven 系统展示 主页 公告信息 管理员界面 用户界面 摘要 基于SSM(Spring、Spring MVC、…...
2.Spark的工作与架构原理
概述 目标: spark的工作原理spark数据处理通用流程rdd 什么是rddrdd 的特点 spark架构 spark架构相关进程spark架构原理 spark的工作原理 spark 的工作原理,如下图 图中中间部分是spark集群,也可以是基于 yarn 的,图上可以…...
qt-C++笔记之带有倒计数显示的按钮,计时期间按钮锁定
qt-C笔记之带有倒计数显示的按钮,计时期间按钮锁定 code review! 文章目录 qt-C笔记之带有倒计数显示的按钮,计时期间按钮锁定1.运行2.main.cc3.main.pro 1.运行 2.main.cc 代码 #include <QApplication> #include <QPushButton> #includ…...
HTML全局属性(global attribute)有哪些?
HTML全局属性是指在HTML元素上可用的基本属性,它们适用于所有HTML元素。以下是一些常见的HTML全局属性: 1:class:为元素指定一个或多个类名,用于与CSS样式表关联。 2:id::为元素指定唯一的标识…...
MyBatis-Plus返回getOne返回null疑惑
getOne返回null 问题描述分析过程总结 问题描述 在数据库建了一张表主要包括两个字段master_id和slave_id;主要的额外字段max_lots 默认值是null; 当调用getOne进行查询结果是null,但实际情况是数据库时应该返回值的; AotfxMasterSlave ex…...
Physics2DPlugin3加载后会跳转gsap官网解决
因工作需要使用Physics2DPlugin3库,目标效果 加载他里面的在线js,使用效果正常,但是几秒会跳转官网,我们app内部、浏览器都会这样。 于是研究js代码,发现里面有setTimeout跳转。 删掉就好了 分享我改好的文件&#x…...
【AI视野·今日Sound 声学论文速览 第三十二期】Tue, 24 Oct 2023
AI视野今日CS.Sound 声学论文速览 Tue, 24 Oct 2023 Totally 20 papers 👉上期速览✈更多精彩请移步主页 Interesting: 📚nvas3d, 基于任意录音和室内3D信息合成重建不同听角(位置)处的新的声音。(from apple cmu) website: htt…...
在Linux上编译gdal3.1.2指南
作者:朱金灿 来源:clever101的专栏 为什么大多数人学不会人工智能编程?>>> 以Ubuntu 18编译gdal3.1.2为例,编译gdal3.1.2需要先编译proj库和geos库(可选)。我选择的proj库版本为proj-7.1.0,编译proj-7.1.0需要先编译tiff库和sqlite3。我选择的sqlite3的版本为…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...
