Rainbond 这款产品一向致力于打通企业运用交给的全流程,这个流程中不可或缺的一环是企业运用的不断晋级、迭代。Rainbond 特有的才能,是能够将包含多个服务组件的企业运用体系进行打包,并履行一键装置、晋级以及回滚的操作。上述的内容只是处理了运用程序自身的版别操控问题。企业运用的晋级迭代流程想要彻底实现主动化,还需求能够主动处理数据库表结构(Schema)的版别操控。经过不断的探究,Rainbond 首先在源码构建范畴借助业界领先的 Liquibase 集成了云原生时代的数据库 Schema 版别办理的才能。

Schema版别办理难题

数据库表结构(Schema)界说了数据表(Table)的姓名,以及每一个数据表中所包含的数据列(Column)的姓名、特点等信息。它描绘了一个数据库所具有的结构,记录在数据库中的数据都需求遵循 Schema 里的界说。

区别于运用程序自身的晋级,Schema 版别办理问题,本质上是一种耐久化数据的晋级,这一特征伴随着两个疑问:

  • 耐久化数据怎么晋级:云原生时代的交给,现已无法跳脱出容器化、渠道化的特征。各大云原生渠道在进行软件交给过程中,都不会容易将耐久化数据归入版别操控体系中去。原因很简单,每个交给环境中的数据都是不同的,晋级过程中很难挑选耐久化数据的一致版别办理计划。

  • 哪些耐久化数据需求晋级:既然难以挑选耐久化数据的一致版别办理计划,那么退而求其次,是否能够优先挑选必要的耐久化数据进行版别办理。缩小规模之后,就突出了数据库表结构这一特殊耐久化数据类型。其版别办理的必要性是显而易见的,运用程序自身从V1版别晋级到了V2版别,那么对应的数据库表结构也需求增加必要的新表、新列。

这两个疑问引出了本文的宗旨:在企业级软件交给范畴,怎么合理的在每次晋级的过程中处理数据库表结构(Schema)的版别操控?

传统软件交给范畴,在 Schema 版别办理方面有两种干流的处理计划:

  • 人工处理:这是最根底的 Schema 版别办理方法。现场交给人员不只需求处理运用程序的晋级流程,也直接操作数据库,完结 Schema 的晋级。这种方法最直接,可是无法主动化处理的流程都具有一些通病:低效、易错。

  • 代码处理:这是一种进阶的方法。经过在运用程序内部引进第三方库,来进行 Schema 的版别办理。这一操作现已能够革除交给现场的人工处理流程,交给人员只需求将运用程序进行更新,程序自身会衔接到数据库,对 Schema 作出主动化的改变。这种方法的主动化程度现已能够满足要求,可是也具有引进第三方库的通病:技术本钱提升、侵入性、与言语或结构绑定。

云原生时代的处理思路

云原生时代,运用程序的运用者、交给者都期望经过所选用的渠道来赋能自己的运用程序。在本文讨论的范畴中,这种等待能够详细的描绘为:借助渠道才能,以无侵入的方法,将 Schema 版别办理才能赋予运用,使得运用在进行一键晋级时, Schema 也主动完结晋级。

Rainbond 作为一款云原生运用办理渠道,也在不断探究为运用赋能之道。在 Schema 版别办理范畴,实现了在源码构建过程中集成 Schema 版别办理的才能。运用自身不需求改动任何代码,只是需求将两种类型的文件放进代码根目录下的指定目录下即可。这两种文件别离是:界说了数据库实例衔接地址的配置文件,晋级 Schema 所运用的 Sql 脚本文件。

关于源码构建

源码构建功用,自身就是一种 Rainbond 对运用的赋能。云原生时代,运用都在向容器化的方向跨进。容器化的过程中看似无法革除 Dockerfile 的编写,实则不然。源码构建功用能够直接对接源代码,将其编译成为可运转的容器镜像。整个过程不需求开发人员的介入,供给代码库房地址即可,极大的降低了开发人员的技术担负。

在源码构建的流程中,以无侵入的方法集成了许多才能。比方经过归入 Pinpoint-agent 的方法集成 APM 才能。再比方经过归入 jmx-exporter 的方法集成自界说事务监控才能。今天要点描绘的,是经过归入 Liquibase 的方法,集成 Schema 版别操控才能。

关于Liquibase

Liquibase 是一款专门用于数据库表结构版别操控的 CI/CD 工具。从 2006 年开端,Liquibase 团队一向致力于让数据库改变办理更简单,尤其是在敏捷软件开发范畴。这一工具依据 Apache 2.0 协议开源。

经过长时间的迭代,Liquibase 现已十分老练可靠,经过 sql、yaml、xml、json 在内的多种文件格局,开发人员能够快速的界说出契合 Liquibase 风格的数据库表结构改变文件,这种文件被称之为 changelog。依据 changelog 中的界说,Liquibase 能够十分便利的在多个改变操作版别之间晋级与回滚。

Liquibase 供给多种方法供开发人员交互,包含一种通用的指令行操作模式,源码构建经过指令行形式集成 Liquibase 的 Schema 版别办理才能。

代码界说的Schema版别操控才能

Rainbond 源码构建推崇代码界说各种才能。关于 Schema 版别操控才能而言,也是经过代码库房中的指定文件来界说的,咱们能够扼要的称之为 Schema As Code,这种代码界说才能的实践,要求每一次 CI 作业都由一个代码库房地址开端,比方 Git。关于每一个数据库实例来说,经过指定目录下的配置文件和 changelog 来界说数据库表结构版别。默许情况下,是指代码根目录下的 Schema目录。

下面是一个代码结构示例,Rainbond 官方一起供给了一份完整的代码示例 java-maven-demo :

.
├──Procfile
├──README.md
├──Schema
│├──changelog.sql#界说数据库表结构
│└──mysql.properties#界说数据库实例衔接信息
├──pom.xml
└──src

Schema 目录下的 mysql.propertieschanglog.sql文件界说了怎么进行 Schema 版别操控。

mysql.properties 界说了数据库实例的衔接方法,以及所引用的 changelog 文件地址。

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT}/${MYSQL_DATABASE}?createDatabaseIfNotExist=true&characterEncoding=utf8
username=${MYSQL_USER}
password=${MYSQL_PASSWORD}
changeLogFile=changelog.sql

最简化界说项包含:

  • driver:指定运用的 jdbc 驱动,源码构建中集成的驱动支撑mysql、mariadb、mssql、mongo、postgresql、sqlite等常见类型数据库。

  • url:界说数据库衔接地址,能够经过 jdbc 的规范写法来预创数据库实例。

  • username&password:界说数据库实例的登录凭证。

  • changeLogFile:界说该数据库实例表结构改变文件的途径。

源码构建过程中,会遍历识别 Schema 目录下的所有 properties 文件,并在发动时处理每一个数据库实例的 Schema 版别操控流程。经过配置文件的组合,在以下各种常见场景中都能够很好的作业。

  • 单个数据库实例

  • 多个相同类型数据库实例,比方运用一起衔接了多个 mysql

  • 多个不同类型数据库实例,比方运用一起衔接了mysql、mongo

  • 同个数据库中的多个数据库实例,比方运用一起运用同个 mysql 中的多个库实例

changlog 的最佳实践

changelog 文件,是办理 Schema 的关键所在。以下是一个示例:

--liquibaseformattedsql
--changesetguox.goodrain:1
createtableperson(
idintprimarykey,
namevarchar(50)notnull,
address1varchar(50),
address2varchar(50),
cityvarchar(30)
);
--rollbackdroptableperson;
--changesetguox.goodrain:2
createtablecompany(
idintprimarykey,
namevarchar(50)notnull,
address1varchar(50),
address2varchar(50),
cityvarchar(30)
);
--rollbackdroptablecompany;

引荐运用 sql 类型的 changelog 文件来界说 Schema 版别,由于这最契合开发人员的习气。

changlog 文件经过注释来界说一些行为。常见如下:

#界说changelog文件的格局,这是每一个changelog文件的开头项
--liquibaseformattedsql
#界说改变集,后面跟随的,是开发人员姓名,以及改变集的序号,这个序号很重要,主张运用有序数字来界说
--changesetguox.goodrain:1
#界说回滚操作,每一个改变集都应该界说与之对应的回滚操作,这使得在改变出现问题时,快速回滚到指定版别的改变集
--rollbackdroptablestaff;

Liquibase 官方提出了一系列的最佳实践,有一些最佳实践应该作为开发人员的默许行为。

  • 每个改变集仅包含一个改变,经过细化数据库表结构的改变版别,这能够防止失利的主动提交语句使数据库处于意外状况。

  • changeset 的 ID,挑选有序且绝无仅有的数列,或者对开发者友好的姓名。

  • 让版别永远可回滚,为每一个 changeset 设置合理的回滚操作。

有关于 mysql.propertieschanglog.sql 文件的写法,更多的特性请参考 liquibase 文档 ,这些特性都能够被源码构建所继承。

Schema生命周期流程

1. 构建流程

履行正常的源码构建流程时,会主动识别代码根目录下的 Schema 目录,预备 Schema 版别办理所需求的根底环境,包含 jre 和 Liquibase 工具包。

构建日志会有以下提示:

在Rainbond中实现数据库结构自动化升级

2. 发动流程

完结构建流程后,服务组件会主动进入发动过程中, Rainbond 渠道会依据代码中界说好的配置文件,针对每一个数据库实例,进行主动晋级处理。

处理过程中,在服务组件的日志中的头部位置,会打印相关的记录:

在Rainbond中实现数据库结构自动化升级

上图中演示了针对同一个 mysql 数据库中的多个库实例进行表结构的晋级操作。关于空的库实例而言,这也相当于一次初始化的操作。

在示例中,Rainbond 别离向运用所衔接的同个 mysql 数据库中的两个库实例(别离名为 Initialize anotherdb)进行了表结构初始化操作,别离创建了表companyperson 以及 another_companyanother_person。在数据库组件的 Web终端登录后,能够验证:

在Rainbond中实现数据库结构自动化升级

3. 发布到组件库

Rainbond 特有的发布机制,能够将事务组件和数据库组件一致发布为一个运用模版。便利在不同的环境中一键装置交给。经过运用模版交给的运用,仍然具有 Schema 版别操控的才能。全新装置的运用模版,其数据库也会被初始化为上述状况。在这里,咱们称发布的运用为源运用,由运用模版装置而来的运用为已交给运用。

在Rainbond中实现数据库结构自动化升级

4. 代码更新

当开发人员继续迭代事务体系的时分,Schema 也随之改动,假定新版别的事务体系,要求 Initialize 新增表 staff,并为已有的 person 表增加一个新的列 country。那么开发人员应该为对应的 changelog.sql 文件新增以下内容,并和新的事务代码一起提交,确保事务代码和 Schema 保持一致。

--changesetother.goodrain:3
altertablepersonaddcolumncountryvarchar(2);
createtablestaff(
idintprimarykey,
namevarchar(50)notnull,
address1varchar(50),
address2varchar(50),
cityvarchar(30)
);
--rollbackdroptablestaff;
--rollbackaltertablepersondropcolumncountry;

在源运用处点击构建,Rainbond 会拉取最新的代码,更新事务运用的一起,为 Schema 进行晋级。

构建过程中没有任何改变,可是在发动过程中,针对更新的 Initialize 和保持原状的 anotherdb 库实例,Rainbond 给出两种不同的处理:

在Rainbond中实现数据库结构自动化升级

5. 依据运用模版的晋级

源运用有了新的版别,已交给运用也应随之有改变。首先,运用模版需求有一个更新的版别,重复发布流程,界说更高的版别号即可。已交给运用能够依据 Rainbond 的提示,一键晋级到更新后的版别。

在Rainbond中实现数据库结构自动化升级

6. 验证

登录已交给运用的数据库组件中,能够检查对应的 Schema 改变。

在Rainbond中实现数据库结构自动化升级

7. 回滚

数据库表结构的回滚操作是一个很严肃的问题。本着数据库表结构只增不减的原则,现已生效的 Schema 不会随着已交给运用的一键回滚而有任何变动。假如一定要进行回滚,则需求运维人员登录事务组件的 Web终端手动操作。

需求注意的是回滚的次序:数据库表结构应该先于运用程序回滚。这是由于一旦运用程序回滚完结, changlog 文件自身也回滚到了上个版别,无法再进行数据库表结构的回滚。

履行以下指令,能够依据指定的配置文件,对数据库表结构进行回滚操作,回滚起伏以 1 个 changeset 为单位。

cdSchema/
liquibaserollbackCount1--defaults-file=mysql.properties

鉴于回滚后的事务组件一旦重启或更新,就会比对 changelog 文件后重新晋级 Schema,所以在履行回滚操作后,必须增加环境变量 ALLOW_SCHEMA_UPDATE=false 来禁用 Schema 版别办理操控功用,直到新版别运用模版的晋级。

常见问题

  1. 怎么在 *.properties 配置文件中合理的界说所有数据库实例的衔接地址和凭证?

运用环境变量来替代 *.properties 配置文件中的数据路实例衔接地址和凭证信息,界说方法详见文中的示例。Rainbond 源码构建过程中,会拾取运转环境中的所有环境变量,对目标配置文件进行渲染,所以关于环境变量的命名并不重要,只需求确保界说的环境变量会在终究交给环境中生成即可。无论环境变量来自于自界说的环境配置仍是 Rainbond 独有的衔接信息机制。

  1. 履行回滚操作失利?

回滚怎么操作,界说在 changlog 文件中。必须确保每一个 changeset 都有对应的回滚战略,方可确保每次回滚都得到正确的成果。

  1. 履行 Schema 晋级的过程中报错:!! Failed to check the database status. Check /app/Schema/xxx.properties.log

每一次履行 Schema 改变的过程中,都会先进行检查,包含数据库实例地址的连通性、changelog 文件的可履行性。假如检查不经过,则不会对数据库作出任何操作,可是检查的成果会记录在日志文件中,能够登录 Web 终端,检查提示中的日志文件内容。

  1. 老用户怎么获取 Schema 版别操控功用?

这一功用和 Rainbond 的版别脱离,所以老用户能够经过更新源码构建相关组件来获取这一才能。履行以下一组指令即可:

#以下指令在 Rainbond 集群内任意节点履行;假如你运用 dind-allinone 版别,则应该在 rainbond-allinone 容器中履行
hubpassword=$(kubectlgetrainbondcluster-oyaml-nrbd-system|greppassword|awk'{print$2}')
dockerlogin--username=admin--password=${hubpassword}goodrain.me
images=(builderrunner)
forimagein${images[@]}
do
dockerpullregistry.cn-hangzhou.aliyuncs.com/goodrain/${image}:v5.5.0-release
dockertagregistry.cn-hangzhou.aliyuncs.com/goodrain/${image}:v5.5.0-releasegoodrain.me/${image}
dockerpushgoodrain.me/${image}
done

References Link

Liquibase www.liquibase.com
java-maven-demo gitee.com/rainbond/ja…

关于Rainbond

Rainbond 是一个开源的云原生运用办理渠道,运用简单,不需求懂容器和Kubernetes,支撑办理多个Kubernetes集群,供给企业级运用的全生命周期办理,功用包含运用开发环境、运用商场、微服务架构、运用继续交给、运用运维、运用级多云办理等。

Github:github.com/goodrain/ra…
官网:www.rainbond.com
微信群:重视 Rainbond 大众号参加技术交流群
钉钉群:请搜索钉钉群号 31096419

本文运用 文章同步助手 同步