亚马逊AWS官方博客

使用开源工具 Liquibase 和 Jenkins 部署、跟踪和回滚 RDS 数据库代码更改

各行各业的客户都需要处理关系数据库代码部署。在大多数情况下,开发人员依靠数据库管理员 (DBA) 执行数据库代码部署。当数据库数量和数据库代码更改量不大时,这非常适用。但是,如果是公司规模,那么他们需要处理不同的数据库引擎,包括 Oracle、SQL Server、PostgreSQL 和 MySQL,以及成百甚至上千个数据库。当开发人员需要部署、跟踪或是回滚数据库更改时,这会对 DBA 造成巨大的负担。而且,在敏捷的环境中等待 DBA 为开发人员进行更改会产生瓶颈。

在本博文中,我将会详细介绍一个在 AWS 中使用开源工具 LiquibaseJenkins 构建具有成本效益、独立于数据库的解决方案示例,以解决这些数据库问题。我不会深入介绍 Liquibase 或 Jenkins 的工作原理;相反,我会重点介绍如何在 Amazon Elastic Compute Cloud (Amazon EC2)、AWS CodeCommitAWS Secrets Manager 和 Amazon Simple Email Service (Amazon SES) 等 AWS 服务上部署这些开源工具,以实现所需目标。

概览

Liquibase 是一个独立于数据库的库,用于跟踪、管理和应用数据库架构更改,使用户能够更轻松地跟踪数据库更改。您可以轻松以 SQL、XML、JSON 或 YAML 格式定义更改。

Jenkins 是一个开源自动化服务器,支持开发人员可靠地构建、部署和回滚代码更改。Jenkins 可以安装在任何已安装 Java Runtime Environment (JRE) 的计算机上。

先决条件

出于本演练的目的,您需要具备以下条件:

  • AWS 账户
  • Amazon Aurora RDS 数据库 (PostgreSQL)
  • 可连接到 Amazon Aurora RDS 数据库和创建/删除表的数据库用户
  • 已在其中安装 Git 客户端并且已将该客户端配置为连接到 CodeCommit 存储库和发布数据库代码的本地计算机

 

架构

演练

让我们来详细介绍一个示例,在该示例中,我将使用在 Amazon Linux AMI 上运行的 Amazon EC2 实例构建此解决方案,在 Amazon Aurora PostgreSQL RDS 数据库上部署数据库架构更改。

步骤 1:将数据库凭证存储于 AWS Secrets Manager

在先决条件部分,我提到了需要数据库用户才能部署数据库更改。此数据库用户用于在数据库中来回部署和回滚架构更改。我将使用 Secrets Manager 来存储这些数据库用户凭证。需要时,使用 AWS 命令行界面 (AWS CLI) 配置 Jenkins 作业,以检索这些凭证。

在下面的示例中,我将存储名为 dbdevopsaurora 的 RDS Aurora 数据库的凭证。

1.在 AWS 控制台中,导航至 AWS Secrets Manager存储新密钥

2.选择 RDS 数据库凭证作为密钥类型,然后输入数据库用户名和密码。

屏幕截图:选择“RDS 数据库凭证”作为密钥类型,然后输入数据库用户名和密码。

3.选择下一步,然后填写密钥 名称描述字段。

4.依次选择下一步启用自动旋转(可选,但推荐选中)。

5.依次选择下一步保存

步骤 2:设置 CodeCommit 存储库

要创建 CodeCommit 存储库:

1.打开 CodeCommit 控制台

2.在区域选择器中,选择想要在其中创建存储库的 AWS 区域Us-east-1.

3.在存储库页面上,选择创建存储库

4.在创建存储库页面上,输入存储库名称DBDevopsDemoRepo.

5.在描述中,输入存储库描述:此存储库用于 DB 部署自动化演示

6.可选步骤:选择添加标签向您的存储库添加一个或多个存储库标签(自定义属性标签,用于帮助您组织和管理您的 AWS 资源)。

7.创建

步骤 3:启动 EC2 实例以托管 Jenkins 和 Liquibase

在此构建环境中,我将启用在 Amazon Linux AMI 上运行的 Amazon EC2 实例,以托管 Liquibase、Jenkins 以及此解决方案所需的其他程序包。

安装和配置 Jenkins、Java、Nginx、jq、Git

使用专用密钥连接到您的实例,然后切换至根用户。首先,让我们更新存储库并安装 Jenkins、Nginx、Git、Java 和 jq。

若要在 Amazon Linux 上安装 Jenkins,我们需要从以下位置添加 Jenkins 存储库和安装 Jenkins:

wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key
yum install -y jenkins
yum install -y java
yum install -y nginx1
yum install -y jq
yum install -y git-all

Jenkins 通常使用端口 TCP/8080,因此,我们将 Nginx 配置为代理。编辑 Nginx 配置文件 (/etc/nginx/nginx.conf) 并更改服务器配置,与以下类似:

server {
    listen       80;
    server_name  _;

    location / {
            proxy_pass http://127.0.0.1:8080;
    }
} 

Jenkins 通常使用端口 TCP/8080,并在安全组中将该端口向需要访问的计算机开放。

启动 Jenkins 和 Nginx 服务,并确保已将其配置为即便在重启后仍运行:

service jenkins start
service nginx start
chkconfig jenkins on
chkconfig nginx on

配置 EC2 实例上的 Git

确保您使用自己的电子邮件地址:

sudo -u jenkins git config --global credential.helper '!aws codecommit credential-helper $@‘
sudo -u jenkins git config --global credential.useHttpPath true
sudo -u jenkins git config --global user.email "email@domain.com"
sudo -u jenkins git config --global user.name (http://user.name/) "MyJenkinsServer"

解锁 Jenkins

将浏览器指向 EC2 实例的公开 DNS 名称(例如,http://ec2-54-221-39-132.compute-1.amazonaws.com/),此时您应该能够看到 Jenkins 主页和解锁说明:

自定义 Jenkins 页面上,选择安装建议的插件

等待一段时间,直到 Jenkins 安装所有建议的插件。此过程完成之后,已安装插件旁边将会显示复选标记。

创建第一个管理员用户页面上,输入 Jenkins 用户的用户名、密码、全名和电子邮件地址。

选择保存并继续保存并完成以及开始使用 Jenkins

下载 Liquibase 并将其安装到 EC2 实例上

Liquibase Community 版本下载为 .zip 文件夹。使用 Putty 或任何其他 SSH 工具登录到 EC2 实例,然后移至 Jenkins 安装目录 cd /var/lib/Jenkins

创建一个名为 liquibase 的文件夹,然后将 Liquibase .zip 文件夹的内容复制到此文件夹。目录应与以下所示类似:

下载 JDBC 驱动程序并将其安装到 EC2 实例上

安装 JDBC 驱动程序,以便 Liquibase 连接到 RDS 数据库。在本示例中,我们使用的是 Aurora PostgreSQL,因此,需要的是 PostgreSQL JDBC 驱动程序

下载 JDBC JAR 文件并将其置于 Liquibase 文件夹中。目录应与以下所示类似:

创建用于部署和回滚的 Bash shell 脚本

Jenkins 将在后台调用这些脚本。这些 Bash shell 脚本将通过分配至 EC2 实例的 IAM 角色调用 Secrets Manager,以提取数据库凭证、运行 Liquibase 实用程序以及部署和回滚更改。

1.创建用于部署的脚本。请注意,此脚本为 PostgreSQL 专用。针对不同的数据库相应地更改驱动程序和 classpath。使用 vi 之类的编辑器创建此文件。

cd /var/lib/jenkins
vi  callLiquibaseDemoDeployment.sh
export lquser=`aws secretsmanager get-secret-value --secret-id dbdevopsAuroraCreds --region us-east-1   | jq --raw-output .SecretString | jq -r ."username"`
export lqpassword=`aws secretsmanager get-secret-value --secret-id dbdevopsAuroraCreds --region us-east-1   | jq --raw-output .SecretString | jq -r ."password"`
export hostname=`aws secretsmanager get-secret-value --secret-id dbdevopsAuroraCreds --region us-east-1   | jq --raw-output .SecretString | jq -r ."host"`
export portnumber=`aws secretsmanager get-secret-value --secret-id dbdevopsAuroraCreds --region us-east-1   | jq --raw-output .SecretString | jq -r ."port"`

bash $JENKINS_HOME/liquibase/liquibase --changeLogFile=$1 --url=jdbc:postgresql://$hostname:$portnumber/devopsdb --username=$lquser --password=$lqpassword --driver=org.postgresql.Driver --classpath=$JENKINS_HOME/liquibase/postgresql-42.2.8.jar update

然后保存此脚本并退出编辑器。

2.创建使用 Count 进行回滚的脚本。请注意,此脚本为 PostgreSQL 专用。针对不同的数据库相应地更改驱动程序和 classpath。

cd /var/lib/jenkins
vi callLiquibaseDemoRollback.sh
export JENKINS_HOME=/var/lib/jenkins/
export lquser=`aws secretsmanager get-secret-value --secret-id dbdevopsAuroraCreds --region us-east-1   | jq --raw-output .SecretString | jq -r ."username"`
export lqpassword=`aws secretsmanager get-secret-value --secret-id dbdevopsAuroraCreds --region us-east-1   | jq --raw-output .SecretString | jq -r ."password"`
export hostname=`aws secretsmanager get-secret-value --secret-id dbdevopsAuroraCreds --region us-east-1   | jq --raw-output .SecretString | jq -r ."host"`
export portnumber=`aws secretsmanager get-secret-value --secret-id dbdevopsAuroraCreds --region us-east-1   | jq --raw-output .SecretString | jq -r ."port"`

bash $JENKINS_HOME/liquibase/liquibase --changeLogFile=$1 --url=jdbc:postgresql://$hostname:$portnumber/devopsdb --username=$lquser --password=$lqpassword --driver=org.postgresql.Driver --classpath=$JENKINS_HOME/liquibase/postgresql-42.2.8.jar rollbackCount $2

然后保存此脚本并退出编辑器。

步骤 3:为 EC2 实例创建 IAM 角色

为 EC2 实例创建一个 IAM 角色,以访问 CodeCommit 存储库和 Secrets Manager。

1.创建角色 JenkinsEC2DevopsRole

2.将 AWS 策略 AWSCodeCommitPowerUser 附加到该角色。

3.创建自定义策略 SecretsManagerRead,以读取 Secrets Manager 中的密钥并将其附加到角色。此自定义策略的 JSON 与以下类似:

{
"Version": "2012-10-17",
"Statement": [
        {
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"secretsmanager:GetRandomPassword",
"secretsmanager:GetResourcePolicy",
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret",
"secretsmanager:ListSecretVersionIds"
            ],
"Resource": "*"
        }
    ]
}

将角色 JenkinsEC2DevopsRole 附加到运行 Jenkins 的 EC2 实例。

步骤 4:使用 SES 为 Jenkins 设置 SMTP 服务器

1.登录到 SES 的 AWS 控制台,并将区域选择为 us-east-1

2.导航至 SMTP 设置并单击创建我的 SMTP 凭证。此操作会将凭证下载到本地计算机;下一步骤需要使用此文件的内容。

3.通过浏览器登录到 Jenkins 并导航至管理 Jenkins配置系统

4.在系统管理员电子邮件地址中输入您选择的电子邮件地址,该地址用于发送 Jenkins 通知。此电子邮件地址应为经过 SES 验证的电子邮件地址。请参阅有关如何在 SES 中验证电子邮件地址的文档。

5.在电子邮件通知下输入 SMTP 服务器名称(例如,步骤 4.2 中的 email-smtp.us-east-1.amazonaws.com)。

6.单击高级按钮,然后再单击使用 SMTP 身份验证选项旁边的复选框。然后设置以下字段:

  • 用户名:已下载的 SMTP 凭证中的用户名(步骤 4.2)
  • 密码:已下载的 SMTP 凭证中的密码(步骤 4.2)
  • 使用 SSL:取消选中此复选框
  • SMTP 端口:587

6.单击通过向收件人发送测试电子邮件测试配置选项旁边的复选框,以检查电子邮件通知功能。输入有效的电子邮件 ID 并单击测试配置按钮,以查看是否会在配置的邮箱中收到一封测试邮件。请注意,收件人电子邮件地址应经过 SES 验证才会收到测试邮件。请参阅有关如何在 SES 中验证电子邮件地址的文档。

7.保存

步骤 5:将数据库代码推送至 CodeCommit 存储库

在先决条件中,我提到了可通过 Git 客户端连接到 CodeCommit 存储库的本地计算机。在这里,我将不再详细介绍该主题,许多其他博文中均有介绍。请参阅 CodeCommit 文档,了解如何将文件推送至 CodeCommit 存储库

对于 Liquibase,可以 SQL、XML 和 JSON 格式指定更改。在本示例中,我将演示 SQL 格式。以下屏幕截图所示为推送到存储库 DBDevopsDemoRepo 的主分支的 Liquibase 格式化 SQL 文件。文件名为 changeset.sql。此文件用于保留代码,以便部署到数据库。

如何针对 Liquibase 设置此文件的格式

Liquibase 格式化 SQL 文件使用注释为 Liquibase 提供元数据。每个 SQL 文件均必须以下面的注释开头:

--liquibase formatted sql

格式化 SQL 文件中的每个更改集必须以下面的注释开头:

--changeset author:id 

changeset.sql 中,您可以看到作者为公共并且使用任意 ID 3 来指定更改集编号。此 ID 是唯一的。这些值有助于跟踪数据库中的更改。

然后是要部署的 DDL:

create table test3 ( 
id int primary key,
name varchar(255)
);

最后,您可以指定一个使用回滚注释的回滚命令。以下是通过删除表 test3 进行回滚的示例:

--rollback drop table test3;

步骤 6:创建一个用于部署和回滚的 Jenkins 项目

创建部署项目

现在,让我们创建一个 Jenkins 项目,以便将 DDL 更改部署到 RDS 数据库。

1.使用现有凭证通过浏览器登录到 Jenkins。

2.单击新建项目并选择任意风格项目

3.将项目名称输入为 LiquibaseDeploymentDemo,然后选择确定

4.在项目中,创建一个用于指定要部署的文件名的参数。

在常规部分,选中复选框此项目已参数化。在下拉菜单中,选择添加参数字符串参数。按如下所示填充字段:

单击下拉菜单、“添加参数”并选择“字符串参数”。按此屏幕截图所示填充字段:文件名、changeset.sql 和描述

5.指定 Jenkins 可从其中提取文件的 CodeCommit 存储库。在源代码管理部分中,选择选项 Git。使用存储库详细信息填充字段存储库 URL分支指定器。对于其他行为,请选择签出到子目录,并按如下所示输入 JENKINS_HOME/Code

在“源代码管理”部分中,选中选项“Git”。使用存储库详细信息填充字段“存储库 URL”和“分支指定器”。在“其他行为”中,选择下拉菜单“签出到子目录”,并按此屏幕截图所示输入“JENKINS_HOME/Code”

6.要设置构建对象,请从下拉菜单中选择执行 Shell,然后输入要构建的命令,如下所示:

bash $JENKINS_HOME/callLiquibaseDemoDeployment.sh $JENKINS_HOME/Code/$filename

先前创建的脚本 callLiquibaseDemoDeployment.sh 将与此 Jenkins 项目的文件名参数一起引用。

先前创建的脚本“callLiquibaseDemoDeployment.sh”将与此 Jenkins 项目的文件名参数一起引用。

7.设置构建后操作,以发送与构建失败相关的邮件。从下拉列表中选择电子邮件通知,输入要向其发送通知的电子邮件地址,然后选中复选框为每一个不稳定构建发送电子邮件,如下所示:

从下拉列表中选择“电子邮件通知”,输入要向其发送通知的电子邮件地址,然后选择复选框“为每一个不稳定构建发送电子邮件”,如此屏幕截图所示

8.保存,您的部署项目已设置完毕。

创建回滚项目

让我们创建一个用于在需要时回滚 RDS 数据库的 DDL 更改的 Jenkins 项目。可以通过不同的方式使用标签、更改数等进行回滚。在本示例中,我将使用 Liquibase 中的回滚计数功能。

1.使用现有凭证通过浏览器登录到 Jenkins。

2.单击新建项目并选择任意风格项目

3.将项目名称输入为 LiquibaseRollbackDemo,然后按确定

4.创建一个用于指定要回滚的文件名的参数。在常规部分,选中复选框此项目已参数化。单击下拉列表中的添加参数并选择字符串参数。按如下所示填充字段:

单击下拉菜单、“添加参数”并选择“字符串参数”。按此屏幕截图所示填充字段:文件名、changeset.sql 和描述

5.创建一个用于指定要回滚的更改集数量的参数。在常规部分,选中复选框此项目已参数化。单击下拉列表中的添加参数并选择字符串参数。按如下所示填充字段:

6.指定 Jenkins 可从其中提取文件的 CodeCommit 存储库。

源代码管理部分中,选择选项 Git。使用存储库详细信息填充字段存储库 URL分支指定器。对于其他行为,请选择下拉菜单签出到子目录,如下所示:

在“源代码管理”部分中,选中选项“Git”。使用存储库详细信息填充字段“存储库 URL”和“分支指定器”。在“其他行为”中,选择下拉菜单“签出到子目录”,并按此屏幕截图所示输入“JENKINS_HOME/Code”

7.要设置构建对象,请从下拉菜单中选择执行 Shell,然后输入详细信息。构建的命令如下所示:

bash $JENKINS_HOME/callLiquibaseDemoRollback.sh $JENKINS_HOME/Code/$filename $JENKINS_HOME/Code/$rollbackcount

先前创建的脚本 callLiquibaseDemoRollback 将与 Jenkins 项目的文件名参数一起引用。

先前创建的脚本“callLiquibaseDemoDeployment.sh”将与此 Jenkins 项目的文件名参数一起应用。屏幕截图

8.设置构建后操作,以发送与构建失败相关的邮件。

从下拉列表中选择电子邮件通知,输入要向其发送通知的电子邮件地址,然后选中复选框为每一个不稳定构建发送电子邮件,如下所示:

从下拉列表中选择“电子邮件通知”,输入要向其发送通知的电子邮件地址,然后选择复选框“为每一个不稳定构建发送电子邮件”,如此屏幕截图所示

9.保存,您的回滚作业已设置完毕。

部署更改

现在,基础设施和部署作业已设置完毕,让我们来完成部署。

1.将浏览器指向 EC2 实例的公开 DNS 名称,然后使用先前创建的凭证登录。

2.单击项目 LiquibaseDeploymentDemo

3.通过单击使用参数构建来构建项目。

4.在下面的屏幕中,输入您想要部署的 CodeCommit 存储库中存储的 SQL 文件的名称。在本示例中,我们在步骤 5 中创建了 SQL 文件。我们将部署文件 changeset.sql

5.选择构建部署数据库更改。

6.在构建历史记录中 ,您将能够看到已创建作业的唯一编号。单击作业编号和控制台输出,以查看作业详细信息。

7.我们已将 Jenkins 配置为在失败时发送通知,因此,如果构建失败,则我们将会收到一封包含详细信息的电子邮件。

跟踪和验证更改

Liquibase 使用 databasechangelog 跟踪所有数据库更改。它会将跟踪数据保留在与时间、作者、更改集和更多详细信息一起部署的文件上。DBA 或开发人员可以通过查询 databasechangelog 文件来跟踪数据库中应用的所有更改。

在本示例中,我将使用 PostgreSQL 客户端登录数据库。请参阅下面的屏幕截图,以了解与所部署的更改集相关的查询和详细信息。更改通过此表中的行表示:

回滚更改

开发人员偶尔会因我们无法控制的原因而必须回滚更改。由于我们使用的是 Liquibase,因此回滚更改更加简单。

1.将浏览器指向 EC2 实例的公开 DNS 名称,然后使用先前创建的凭证登录。

2.单击项目 LiquibaseRollbackDemo

3.现在,通过单击使用参数构建来构建项目。

4.在下面的屏幕中,输入用于部署存储在 CodeCommit 存储库中的更改的 SQL 文件名称。在本示例中,我们将回滚文件 changeset.sql 中的单个更改。现在,我们已按 LIFO 顺序(即,首先回滚部署的最后一个更改集)部署更改。

5.选择构建按钮,此时将会回滚数据库中的更改。

6.在构建历史记录中,您将能够看到已创建作业的唯一编号。依次单击作业编号和控制台输出,以查看作业详细信息。

7.我们已将 Jenkins 配置为在失败时发送通知,因此,如果构建失败,则我们将会收到一封包含详细信息的电子邮件。

跟踪和验证回滚

Liquibase 使用 databasechangelog 跟踪所有数据库更改。完成回滚之后,它会在部署之后删除先前创建的行。我们可以登录数据库以查看这些详细信息。

我将再次使用 PostgreSQL 客户端登录数据库。查看下面的查询屏幕截图。您可以看到一个空表,这意味着表示更改的行已在 Liquibase 回滚之后从此表中删除。

结论

在本博文中,我介绍了如何使用 AWS 服务(如 EC2、SES、Secrets Manager 和 CodeCommit 等)以及开源工具 Jenkins 和 Liquibase 部署、跟踪和回滚 RDS Aurora PostgreSQL 数据库的数据库架构更改。此解决方案具有成本效益,并且可以在 EC2 Spot 实例上运行,从而可以进一步降低成本。

安装相应的 JDBC 驱动程序并对脚本进行少许修改之后,您就可以轻松修改此解决方案,以适用于其他 RDS 数据库,如 SQL Server、MySQL 和 Oracle 等。通过对解决方案进行少许修改,您也可以修改Jenkins 项目,以便以特定间隔轮询存储库,或者在开发人员提交代码时构建部署作业。

希望本博文为您提供了丰富而有用的信息,并且此解决方案对您有所帮助,同时,欢迎大家提供反馈和评论。