「Jenkins Pipeline」- 连接 MySQL 数据库

  CREATED BY JENKINSBOT

问题描述

在 Jenkins Pipeline 中,我们需要连接 MySQL 数据库,以存储某些状态数据,用于在多个 Job 之间共享。这些数据不属于制品,通过制品管理的方式进行传递是件繁琐的事情,而且存在问题。然而,通过数据库进行传递是最好的方式。因此,我们需要解决在 Jenkins Pipline 中连接数据库的问题。

但是,事情往往没有看起来那样简单。我们难以像 Groovy 连接数据库 那样使用 mysql-connector-java 类库,原因在于 JDBC 驱动的加载方式以及 Jenkins Pipeline 类加载器的设计,这两点导致我们无法直接使用。但是,我们终究是找到解决方案。

该笔记将记录:在 Jenkins Pipeline 中,如何连接 MySQL 数据库,以及常见问题处理。

解决方法

方案一、通过系统类加载器(废弃)

但是,好在还有其他的方法:我们下载 mysql-connector-java 类库,将其保存在 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-1.el7_6.x86_64/jre/lib/ext/mysql-connector-java.jar(我们使用 CentOS 7.x 发行版,而 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-1.el7_6.x86_64/ 是 YUM 安装 OpenJDK 的目录)。此时 mysql-connector-java 将由系统类加载器进行加载。

访问数据库的代码如下(这与 Groovy 连接数据库 基本类似,但无需 Grab 引入驱动):

import java.sql.*;
import groovy.sql.Sql

def connectionString = "jdbc:mysql://<ip-address>:<port-number>/<database>"
def username = "<username>"
def password = "<password>"
def driver = "com.mysql.jdbc.Driver"
def sqlInstance = Sql.newInstance(connectionString, username, password, driver)

// 查询第一条数据
def firstRow = sqlInstance.firstRow("select * from <database>.<table>")
print firstRow

如果采用该方法,(1)建议不再使用 YUM 提供的 OpenJDK 包,(2)而应该到 OpenJDK 官网下载,然后放入自定义的 Jar 包,并单独维护。

方案二、使用 database 插件(推荐)

# 09/24/2020 官方提供 Database / MySQL API Plugin / MySQL Database Plugin 扩展,但是没有演示程序,文档也少的可怜(近乎没有),所以我们也没有办法使用官方插件(经过反复的实验,并没有成功,也许是我们的操作方式不对)。

# 03/24/2021 但是,我们现在找到相关的文档说明,并通过测试。该部分将记录这些内容,介绍连接 MySQL 数据库的方法。

第一步、安装 databaseMySQL Database Plugin 插件:
其中,Database 插件是抽象层,对“底层驱动”进行封装。而这里的“底层驱动”便是“MySQL Database Plugin”插件。除了连接 MySQL 数据库的插件,还有 PostgreSQL Database plugin、H2 Database plugin 等等(这里不再赘述插件的安装方法)。

第二步、添加 MySQL 数据库配置:
在 Manage Jenkins / Configure System / Global Database 中,填写数据库信息:选择 MySQL 数据库;填写 Username、Password 等等信息;填写 Validation Query 字段,例如 select version(); 语句;最后,点击按钮 Test Connection 测试连接。

第三步、在 Jenkins Pipeline 中,连接数据库:

pipeline {
    agent any
    stages {
        stage('# 构建开始') {
            steps {
                script{
                    getDatabaseConnection(type: 'GLOBAL') {
                        def result = sql(sql: "show databases;")
                        println "Class of result: ${result.getClass().toString()}"
                        println "Value of result: ${result}"
                    }
                }
            }
        }
    }
}

下面是执行的输出结果(省略无关内容),正如我们所见,返回 ArrayList 对象:

...
Class of result: class java.util.ArrayList
Value of result: [[SCHEMA_NAME:information_schema], [SCHEMA_NAME:test_db]]
...

关于连接数据库的相关参数,参考 Pipeline Steps Reference/database 文档。

补充说明

对于大多数构建任务,没有必要使用 Jenkins Pipeline 访问数据库,这也许是种小众需求。如果在设计中出现这种需求,也许应该重新考虑。我们之所以需要连接数据库,是因为我们要用 Jenkins 做些复杂的事情。

参考文献

How to add a JDBC driver to Jenkins’s jobs & load the parameter values from SQL Database
mysql – How to add a JDBC driver to a Jenkins pipeline? – Stack Overflow
database | Jenkins plugin / database-h2 | Jenkins plugin / MySQL Database | Jenkins plugin
jenkinsci/pipeline-authoring-sig – Gitter