升级到GoCD 20.5.0及以上版本
GoCD20.5.0
引入了其数据库实现的若干更改,以构建一个更灵活的模型,允许与多个数据库集成。作为这些更改的一部分,GoCD改变了用于自动数据库迁移的技术(从无人维护的DBDeploy改为Liquibase)。这些更改需要一次性迁移GoCD数据库<=20.4.0
到符合GoCD的数据库20.5.0
及更高版本。
GoCD20.5.0
,虽然继续默认支持H2,但提供了使用PostgreSQL和MySQL的能力。作为这次一次性数据库迁移的一部分,用户还可以选择迁移到他们选择的数据库。可能的迁移包括:
- H2=>PostgreSQL [推荐]
- PostgreSQL=>PostgreSQL
- H2=>H2
- H2=>MySQL [警告!请参见下方注释]
选择您的迁移策略
GoCD捆绑了基于Java磁盘的H2数据库。如果你从未配置过数据库,那么你正在使用的就是这个。
- PostgreSQL的历史支持是通过Thoughtworks提供的商业附加组件提供的。这一功能被整合到核心GoCD中,并且自那时起免费提供。
20.5.0
. - 由于这一历史,GoCD所有的功能性回归测试都在H2和PostgreSQL数据库上运行。
- 虽然在
20.5.0
中增加了对MySQL的支持,只完成了一轮基本的迁移测试,而且功能测试套件并没有定期在构建流水线中针对MySQL运行。如果考虑迁移到MySQL,请注意这一点。 as a part of the build pipeline. This is something to be aware of if considering moving to MySQL. - 在GoCD中使用的H2版本
20.5.0
移到了使用MVStore作为默认存储子系统。根据截至2022年10月的H2文档,MVStore的当前状态仍被标记为实验性。尽管使用默认的H2适合起步或实验,我们建议在生产环境下的GoCD实例中使用PostgreSQL。
选择目标GoCD版本
如果你在考虑升级到一个比更高的版本 20.5.0
,请记住关于与旧版代理兼容性的通常注意事项,这在升级GoCD中有所提及。鉴于在20.5.0
和22.3.0
之间没有重大的数据库相关更改,因此没有特别的数据库相关考量,不过你应该查看发行说明,以了解你的设置中可能存在破坏性变化。
选择PostgreSQL或MySQL版本
如果你在考虑在本次升级期间从H2迁移到PostgreSQL或MySQL,你应该认真考虑你的目标数据库版本。理想情况下,你应该选择一个重叠版本基于以下因素:
- 你最终目标GoCD版本的支持的数据库版本.
- 的数据库迁移工具验证过的支持的数据库版本
20.5.0
发布时支持的版本。这些版本为:- PostgreSQL (
v9.6
–v12
)。截至2022年,更新的版本将可能正确工作,但是应该被视为未经过验证,所以在特定环境中仔细检查你的数据。 - MySQL (
v8.0
)
- PostgreSQL (
以前的商业PostgreSQL插件用户
以前的商业PostgreSQL附加组件使用已被GoCD中的开源/免费PostgreSQL支持取代20.5.0
。不再需要、使用或支持插件/扩展。然而,为了继续使用PostgreSQL,你的现有数据库仍然需要一次手动迁移来使其与GoCD20.5.0
和更高版本兼容。
以前的商业业务连续性插件用户
由于安全问题,在后期版本的GoCD中删除了业务连续性功能20.5.0
+。你应该停止备用实例,并仅升级主实例。
迁移步骤
按照以下说明将现有的GoCD <=20.4.0
数据库迁移到GoCD20.5.0
(及更高版本)兼容的数据库。此迁移所需的时间取决于你的数据库大小。在测试过程中我们观察到迁移时间从几分钟到一个多小时以上不等,具体取决于数据库大小。请在GoCD服务器的备份上进行测试,以了解你的特定数据库所需的迁移时间。
强烈建议:: 在生产实例上尝试迁移之前,先在非生产实例或GoCD的备份上尝试迁移。
第1步:升级到GoCD20.4.0
一般来说,你应该能够直接从任何较旧版本的GoCD迁移到20.5.0
或更高的版本。然而,在20.5.0
几个发布之前的版本中,GoCD围绕安装程序和代理通信进行了多次更改,这可能涉及必要的设置更改。
因此,为了确保你一次解决一个问题,建议先正常升级到GoCD20.4.0
并验证你的GoCD设置20.4.0
在然后再升级到GoCD20.5.0
或更高版本。
第2步:备份
备份你的GoCD服务器。参考备份GoCD服务器文档获取指示。
第3步:停止GoCD服务器
如果GoCD服务器正在运行,请停止它。
第4步:数据库迁移
-
从GitHub发布部分下载最新稳定版本的迁移工具GoCD数据库迁移工具的仓库.
-
解压缩并放入目录中。
cd
获取使用说明。 -
在该目录下手动运行
./bin/gocd-database-migrator --help
for usage instructions.
先决条件:确保在运行迁移的机器上安装了Java 8+。
4.1 从H2到H2的数据迁移
-
The
gocd-database-migrator
需要source-db-url
,其中包括GoCD H2数据库的位置。数据库的位置取决于你的GoCD服务器运行的发行版。请参考GoCD安装文档以识别文件位置。 -
运行命令(以下示例适用于在Linux上运行的GoCD服务器)-
./bin/gocd-database-migrator \ --insert \ --progress \ --source-db-url='jdbc:h2:/var/lib/go-server/db/h2db/cruise' \ --source-db-user='sa' \ --source-db-password='' \ --target-db-url='jdbc:h2:/var/lib/go-server/db/h2db/new_cruise' \ --target-db-user='sa' \ --target-db-password=''
对于在Windows上运行的GoCD服务器,请参阅以下示例-
bin\gocd-database-migrator.bat ^ --insert ^ --progress ^ --source-db-url="jdbc:h2:C:\Program Files (x86)\Go Server\db\h2db\cruise" ^ --source-db-user="sa" ^ --source-db-password="" ^ --target-db-url="jdbc:h2:C:\Program Files (x86)\Go Server\db\h2db\new_cruise" ^ --target-db-user="sa" ^ --target-db-password=""
注意: 该
source-db-url
和target-db-url
仅包含文件名的前缀(cruise
和new_cruise
),即使实际文件名为:cruise.h2.db
和new_cruise.mv.db
. -
删除、备份或移动文件/var/lib/go-server/db/h2db/cruise.h2.db.
-
通过移动文件替换旧数据库为迁移后的数据库/var/lib/go-server/db/h2db/new_cruise.mv.db为/var/lib/go-server/db/h2db/cruise.mv.db.
-
确保新文件的文件权限和所有权正确(与旧文件相同
cruise.mv.db
)。cruise.h2.db
文件)。
4.2 从PostgreSQL迁移到PostgreSQL
-
在PostgreSQL中创建一个空数据库。参考PostgreSQL文档获取有关创建空数据库的信息。
-
通过提供所需选项的正确参数来运行命令。以下是一个示例:
./bin/gocd-database-migrator \ --insert \ --progress \ --source-db-url='jdbc:postgresql://localhost:5432/cruise' \ --source-db-user='postgres' \ --source-db-password='pass' \ --target-db-url='jdbc:postgresql://localhost:5432/new_cruise' --target-db-user='postgres' \ --target-db-password='pass'
4.3 从H2迁移到PostgreSQL
-
在PostgreSQL中创建一个空数据库。参考PostgreSQL文档获取有关创建空数据库的信息。
-
通过提供所需选项的正确参数来运行命令,
./bin/gocd-database-migrator \ --insert \ --progress \ --source-db-url='jdbc:h2:/var/lib/go-server/db/h2db/cruise' \ --source-db-user='sa' \ --source-db-password='' \ --target-db-url='jdbc:postgresql://localhost:5432/new_cruise' --target-db-user='postgres' \ --target-db-password='pass'
4.4 从H2迁移到MySQL
-
在MySQL中创建一个空数据库。参考MySQL文档获取有关创建空数据库的信息。
-
通过提供所需选项的正确参数来运行命令,
./bin/gocd-database-migrator \ --insert \ --progress \ --source-db-url='jdbc:h2:/var/lib/go-server/db/h2db/cruise' \ --source-db-user='sa' \ --source-db-password='' \ --target-db-url='jdbc:mysql://localhost:3306/new_cruise' --target-db-user='root' \ --target-db-password='password'
第5步:配置db.properties
您的GoCD服务器
5.1 启用GoCD使用H2数据库
GoCD默认情况下运行在H2上。配置db.properties
是不必要的。只需确保目录<<GoCD_installation_directory>>/db/h2db/
已经不包含cruise.h2.db
(20.4.0
H2数据库格式)并且只包含cruise.mv.db
(20.5.0
+ H2数据库格式)。
5.2 启用GoCD使用PostgreSQL或MySQL数据库
需要在 GoCD 的配置目录中创建一个名为db.properties
需要在GoCD的配置目录中创建。此文件应包含有关PostgreSQL或MySQL服务器的信息,以便GoCD服务器可以连接到它。参考GoCD数据库连接属性文档了解该文件的格式和有效键的更多信息。
GoCD的配置目录位置因操作系统而异。通常,在使用RPM或Debian安装程序的Linux系统上,此文件需要位于/etc/go/db.properties
。该安装文档提供了有关位置的信息。
-
MySQL的样本配置:
db.properties
PostgreSQL的样本配置:db.driver=org.postgresql.Driver db.url=jdbc:postgresql://localhost:5432/new_cruise db.user=postgres db.password=pass
-
MySQL的样本配置:
db.properties
MySQL的样本配置:db.driver=com.mysql.cj.jdbc.Driver db.url=jdbc:mysql://localhost:3306/gocd db.user=root db.password=password
第6步:仅适用于使用(旧)商业PostgreSQL插件的用户
完成上述步骤后,包括配置新的db.properties
GoCD核心的配置:
-
从插件目录中删除PostgreSQL插件jar(通常在Linux上为
/var/lib/go-server/addons
)。 -
从配置目录中删除
postgresqldb.properties
文件(通常在Linux上为/etc/go
)。
第7步:升级GoCD服务器
将您的GoCD服务器升级到20.5.0
+ 并启动服务器。
排查问题
可能出现的问题有:
数据库为只读模式
在升级后,您可能会在 GoCD 服务器日志中看到如下消息:
Caused by: org.h2.jdbc.JdbcSQLNonTransientException: The database is read only; SQL statement:
UPDATE PUBLIC.DATABASECHANGELOGLOCK SET LOCKED = TRUE, LOCKEDBY = '10.16.0.5 (10.16.0.5)', LOCKGRANTED = '2020-06-17 15:07:20.707' WHERE ID = 1 AND LOCKED = FALSE [90097-200]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:505)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:429)
at org.h2.message.DbException.get(DbException.java:205)
这可能是由于 H2 DB 文件(通常位于/var/lib/go-server/db/h2db/cruise.mv.db
在 Linux 上)权限或所有权设置错误导致的。
MySQL:标识符大小写敏感性
如果您正在使用 MySQL,则可能会在 GoCD 服务器日志中看到类似以下的消息:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.commons.dbcp2.BasicDataSource]: Factory method 'getDataSource' threw exception; nested exception is java.sql.SQLException: Unable to migrate the database
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
... 73 common frames omitted
Caused by: java.sql.SQLException: Unable to migrate the database
at com.thoughtworks.go.server.database.migration.DatabaseMigrator.migrate(DatabaseMigrator.java:68)
at com.thoughtworks.go.server.database.Database.getDataSource(Database.java:63)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
... 74 common frames omitted
Caused by: liquibase.exception.MigrationFailedException: Migration failed for change set db-migration-scripts/initial/create-trigger.xml::107::gocd(generated):
Reason: liquibase.exception.DatabaseException: Table 'gocd.buildStateTransitions' doesn't exist [Failed SQL: (1146) CREATE TRIGGER lastTransitionedTimeUpdate
AFTER INSERT ON buildStateTransitions
FOR EACH ROW
BEGIN
UPDATE stages SET lastTransitionedTime = NEW.statechangetime WHERE stages.id = NEW.stageid;
END]
at liquibase.changelog.ChangeSet.execute(ChangeSet.java:646)
at liquibase.changelog.visitor.UpdateVisitor.visit(UpdateVisitor.java:53)
at liquibase.changelog.ChangeLogIterator.run(ChangeLogIterator.java:83)
at liquibase.Liquibase.update(Liquibase.java:202)
at liquibase.Liquibase.update(Liquibase.java:179)
at liquibase.Liquibase.update(Liquibase.java:175)
at com.thoughtworks.go.server.database.migration.DatabaseMigrator.migrate(DatabaseMigrator.java:54)
... 80 common frames omitted
Caused by: liquibase.exception.DatabaseException: Table 'gocd.buildStateTransitions' doesn't exist [Failed SQL: (1146) CREATE TRIGGER lastTransitionedTimeUpdate
AFTER INSERT ON buildStateTransitions
FOR EACH ROW
BEGIN
UPDATE stages SET lastTransitionedTime = NEW.statechangetime WHERE stages.id = NEW.stageid;
END]
at liquibase.executor.jvm.JdbcExecutor$ExecuteStatementCallback.doInStatement(JdbcExecutor.java:402)
at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:59)
at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:131)
at liquibase.database.AbstractJdbcDatabase.execute(AbstractJdbcDatabase.java:1276)
at liquibase.database.AbstractJdbcDatabase.executeStatements(AbstractJdbcDatabase.java:1258)
at liquibase.changelog.ChangeSet.execute(ChangeSet.java:609)
... 86 common frames omitted
Caused by: java.sql.SQLSyntaxErrorException: Table 'gocd.buildStateTransitions' doesn't exist
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql.cj.jdbc.StatementImpl.executeInternal(StatementImpl.java:764)
at com.mysql.cj.jdbc.StatementImpl.execute(StatementImpl.java:648)
at org.apache.commons.dbcp2.DelegatingStatement.execute(DelegatingStatement.java:194)
at org.apache.commons.dbcp2.DelegatingStatement.execute(DelegatingStatement.java:194)
at liquibase.executor.jvm.JdbcExecutor$ExecuteStatementCallback.doInStatement(JdbcExecutor.java:398)
... 91 common frames omitted
如果您看到此消息,最可能的原因是您的 MySQL 实例启用了大小写敏感标识符。GoCD 需要大小写不敏感的标识符,您需要更改 MySQL 实例以启用这一点。请注意,根据文档,一旦初始化了 MySQL 实例,就无法更改该lower_case_table_names
变量。您可能需要重新创建实例。