☰
Devtron GoLang-migrate 预设插件详解:在 CI/CD 流水线中执行数据库迁移
2026/10/14 15:21:06 网站建设 项目流程
  • 云原生
  • DevOps
  • 运维

【免费下载链接】devtron

The only Kubernetes dashboard you need

项目地址:https://gitcode.com/gh_mirrors/dev/devtron
点击查看免费下载

本文以 Devtron 官方文档 GoLang-migrate 插件指南 为主体,完整覆盖该预设插件(GoLang-migrate)的适用前提、在流水线中的配置步骤、全部输入变量说明与注意事项,并结合 Devtron 仓库中注册该插件的数据库迁移脚本(scripts/sql/259_migration_plugin.up.sql)、插件框架源码(pkg/plugin/repository/GlobalPluginRepository.go)以及 Devtron 自身使用同一套变量模型执行数据库迁移的 Job 清单(manifests/yamls/migrator.yaml),深入解析插件内置脚本的真实执行逻辑、支持的数据类型连接串格式,以及输出变量如何在任务链中传递。读完后,你可以把基于 golang-migrate 格式 SQL 脚本的数据库版本升级,安全地编排进 Devtron 的 Pre/Post-Build 或 Deploy 阶段。

一、插件定位与适用前提

GoLang-migrate 是 Devtron 内置的一个PRESET(预设)插件,其官方描述为:“This plugin provides a seamless way to manage and execute database migrations, ensuring your database schema evolves safely and predictably with your application code.” 插件的核心行为来自 golang-migrate 工具:Migrate 从源文件中读取迁移脚本(migrations),并以正确的顺序将其应用到数据库。

使用前提(原文档明确要求):

  • 你的仓库中必须已有符合 golang-migrate 工具格式的 SQL 文件(即带版本号前缀的 up/down 迁移文件,存放在 Git 仓库某个目录下);
  • 插件支持的目标数据库类型为postgres、mongodb、mongodb+srv、mysql、sqlserver,其余类型需要通过POST_COMMAND自行拼接命令(见后文“注意事项”)。

从仓库源码看,该插件是在数据库迁移脚本 scripts/sql/259_migration_plugin.up.sql 中注册进系统的:

  • 向plugin_metadata表插入名为GoLang-migrate的记录,type字段为PRESET;
  • 向plugin_stage_mapping表写入该插件的阶段映射,决定它能在哪些流水线阶段被选用(插件阶段类型常量定义见 GlobalPluginRepository.go 中的CI = 1、CD = 2、CI_CD = 3、SCANNER = 4);
  • 向plugin_pipeline_script表写入一段SHELL类型的内置脚本——这就是插件真正执行迁移的逻辑载体(第三节详解);
  • 向plugin_step_variable表批量插入DB_TYPE、DB_HOST等全部输入/输出变量定义。插件类型(SHARED/PRESET)的合法性校验位于 pkg/plugin/bean/bean.go 的validate:"oneof=SHARED PRESET"约束中。对应的回滚脚本 scripts/sql/259_migration_plugin.down.sql 会按相同规则清理这些记录。插件在界面中的图标由迁移脚本 scripts/sql/30602400_plugin_icons_update.up.sql 更新,对应仓库内的 assets/plugin-icons/ic-plugin-golang-migrate.png。

关于 Devtron CI 流水线中 Pre-Build / Post-Build 阶段与预设插件的整体机制,可参阅 预构建与后构建阶段指南;该插件在预设插件总览中的入口见 Preset Plugins 列表。

二、在流水线中添加 GoLang-migrate 任务

原文档给出的操作流程如下,可完整复现:

  1. 进入Edit build pipeline(编辑构建流水线)页面,选择Pre-Build Stage(或 Post-Build Stage);
  2. 点击+ Add task;
  3. 在PRESET PLUGINS中选择GoLang-migrate。

随后完成以下字段配置:

  • 在Task name字段输入相关名称(必填);
  • 在Description字段输入任务的描述信息(可选);
  • 为输入变量提供取值。注意:变量的值可以来自前一个构建阶段的输出变量、全局变量,或自定义值;
  • 配置Trigger/Skip Condition(触发/跳过条件):这是一个决定任务执行或跳过的条件语句,可选择Set trigger conditions(满足条件才执行)或Set skip conditions(满足条件则跳过);
  • 点击Update Pipeline保存。

三、输入变量完整参考

原文档给出的变量表如下,本文在此基础上结合注册脚本 scripts/sql/259_migration_plugin.up.sql 中plugin_step_variable的定义,补充了默认值、是否允许为空等实操信息:

变量类型说明
DB_TYPEString当前插件支持 postgres、mongodb、mongodb+srv、mysql、sqlserver。
DB_HOSTString数据库服务器的主机名、服务端点或 IP 地址。
DB_PORTString数据库服务器监听端口号。
DB_NAMEString要连接的目标数据库实例名称。
DB_USERString连接数据库所需用户名。
DB_PASSWORDString连接数据库所需密码。
SCRIPT_LOCATIONString需要在目标数据库上执行的 SQL 文件位置(仓库内相对路径,允许为空,见下文)。
MIGRATE_IMAGEStringgolang-migrate 的 Docker 镜像,默认值:migrate/migrate(允许为空时回落到默认值)。
MIGRATE_TO_VERSIONString迁移到哪个版本的 SQL 脚本(默认值:0,表示执行目录内所有文件)。
PARAMString随数据库查询一起执行的额外连接参数(允许为空),通常以键值对形式给出,例如sslmode=disable。
POST_COMMANDString脚本末尾执行的后置命令(允许为空)。

此外,注册脚本中还定义了一个输出变量POST_MIGRATION_VERION(variable_type为OUTPUT),描述为 “migration version after running the SQL files”(执行 SQL 文件后的迁移版本),它会被导出为后续任务可用的环境变量(细节见下节)。

其中DB_HOST、DB_NAME、DB_USER、DB_PASSWORD、MIGRATE_TO_VERSION在注册脚本中allow_empty_value为f(不允许为空)或带有默认值,SCRIPT_LOCATION、MIGRATE_IMAGE、PARAM、POST_COMMAND允许为空。

四、内置脚本执行原理:源码级解析

插件注册时写入的 SHELL 脚本(即 scripts/sql/259_migration_plugin.up.sql 中plugin_pipeline_script的$$...$$内容)完整揭示了变量是如何被消费的,其执行逻辑可以归纳为以下五步:

  1. 前置校验与上下文打印:脚本开启set -e与set -o pipefail;若DB_HOST或DB_NAME为空则打印 “Please enter DB_HOST / DB_NAME” 并以非零码退出;同时通过git rev-parse打印当前分支与提交,用于审计这次迁移对应的代码版本。若SCRIPT_LOCATION为空,则回落到当前目录.并打印 “we are running migration on current location”。

  2. 构造连接串:仅当DB_USER非空时拼接DB_CRED="$DB_USER:$DB_PASSWORD@"。随后按DB_TYPE分支构造不同数据库的 DSN:

    • postgres→postgres://$DB_CRED$DB_HOST:$DB_PORT/$DB_NAME?"$PARAM"
    • mongodb/mongodb+srv→ 对应mongodb:///mongodb+srv://前缀,同样携带DB_HOST、DB_PORT、DB_NAME与PARAM;
    • mysql→mysql://$DB_CRED$DB/$DB_NAME?"$PARAM",其中DB被显式定义为tcp($DB_HOST:$DB_PORT)(mysql DSN 的 tcp 地址格式);
    • sqlserver→sqlserver://$DB_CRED$DB_HOST:$DB_PORT?"$PARAM"(该格式不带库名路径)。
  3. 选择迁移目标版本:若MIGRATE_TO_VERSION等于0,执行up(应用全部迁移);否则执行goto $MIGRATE_TO_VERSION(迁移到指定版本)。对应的docker run命令形如:

    docker run -v $PWD:$PWD $MIGRATE_IMAGE \ -path $PWD/$SCRIPT_LOCATION \ -database <按DB_TYPE拼接的连接串> up

    即把当前工作目录挂载进容器(-v $PWD:$PWD),并指向仓库内的 SQL 脚本目录-path $PWD/$SCRIPT_LOCATION——这就是为什么迁移文件必须放在 CI 检出的 Git 仓库里,由SCRIPT_LOCATION指定。

  4. 执行后置命令并导出结果版本:所有分支执行完迁移后都会运行$POST_COMMAND,然后通过再次调用migrate version子命令把当前数据库版本写入migration-golang-current-version.txt,并导出POST_MIGRATION_VERION环境变量(为空时回落到"0"),最后打印 “migration completed”。这一输出变量即可被流水线中下一个任务作为输入变量引用,用于把“迁移后的数据库版本”传递给后续步骤(例如部署阶段做校验)。

  5. 兜底分支:若DB_TYPE不在五种支持类型内,仅打印 “no database matched”——此时应按原文档 Notes 的建议改用POST_COMMAND手动执行(见第五节)。

五、注意事项与安全建议(原文档 Notes 全量继承)

原文档 Notes 部分给出三条重要建议,均与源码行为相互印证:

  1. 数据库在 Devtron 集群内不可达时:在pre-deploy或post-deploy阶段使用in-cluster/ Execute tasks in application environment(在应用环境中执行任务)特性。因为 Pre/Post-Build 阶段的插件任务默认在 CI 构建环境中运行,若目标数据库位于业务应用所在的集群、且从 Devtron 集群网络不可访问,就应改用部署阶段的应用环境执行迁移。

  2. DB_TYPE不受支持时:内置脚本会落入 “no database matched” 分支而不做任何迁移,此时应通过POST_COMMAND手动运行 golang-migrate 命令,原文档给出的模板为:

    POST_COMMAND: docker run -v $PWD:$PWD $MIGRATE_IMAGE -path $PWD/$SCRIPT_LOCATION -database <myDB-connection-string>" goto $MIGRATE_TO_VERSION;

    即把<myDB-connection-string>替换为你自己的完整 DSN,其余变量语义与内置分支保持一致。

  3. 密码安全:建议配合scope-variable(范围变量)特性管理DB_PASSWORD,避免明文密码直接写死在流水线变量中。

六、同一套变量模型的实证:Devtron 自身的迁移 Job

除了作为插件存在,golang-migrate 也是 Devtron 自身数据库升级的基础。仓库中 manifests/yamls/migrator.yaml(以及集成测试镜像的 tests/integrationTesting/migrator.yaml)定义了一系列postgresql-migrate-*Job,其容器环境采用了与插件几乎一致的变量模型:DB_TYPE=postgres、DB_HOST、DB_PORT、DB_NAME、MIGRATE_TO_VERSION=0、SCRIPT_LOCATION=scripts/sql/,再通过envFrom.secretRef注入密码。可以推断,插件设计的这套环境变量抽象,与 Devtron 内部升级工具链(quay.io/devtron/migrator镜像)是同一思路:统一用DB_*变量描述目标库,用SCRIPT_LOCATION指向仓库内 golang-migrate 格式的 SQL 目录,用MIGRATE_TO_VERSION=0表示“跑到最新”。仓库内的 scripts/sql/ 目录(700+ 个.sql文件)就是这些 Job 迁移的实际脚本来源。

一个值得注意的格式约束来自迁移脚本 scripts/sql/36304600_add_ci_artifact_query_indexes.up.sql 的注释:“CREATE INDEX CONCURRENTLY cannot run inside a transaction (golang-migrate wraps each migration in a transaction).” 这说明golang-migrate 会把每个迁移文件包裹在一个事务中执行,因此编写迁移 SQL 时不能使用必须在事务外执行的语句(如CREATE INDEX CONCURRENTLY),该脚本改用幂等的CREATE INDEX IF NOT EXISTS规避了此限制。这一点对你在 CI 中使用本插件编写迁移文件同样适用。

七、小结

  • GoLang-migrate 是 Devtron 的 PRESET 插件,把 golang-migrate 的“按序应用 SQL 迁移文件”能力封装为流水线任务,支持 postgres、mongodb、mongodb+srv、mysql、sqlserver 五种DB_TYPE;
  • 配置路径为:Edit build pipeline → Pre/Post-Build Stage(或部署阶段)→ + Add task → PRESET PLUGINS → GoLang-migrate,随后填写DB_*、SCRIPT_LOCATION、MIGRATE_IMAGE(默认migrate/migrate)、MIGRATE_TO_VERSION(默认0全量)、PARAM、POST_COMMAND,并设置 Trigger/Skip Condition;
  • 源码层面,插件通过 scripts/sql/259_migration_plugin.up.sql 注册,其内置 SHELL 脚本负责校验必填变量、按DB_TYPE拼接 DSN、以up/goto执行迁移、执行POST_COMMAND并导出POST_MIGRATION_VERION供下游任务消费;
  • 若数据库网络不可达请在部署阶段使用 in-cluster 执行;若DB_TYPE不受支持请用POST_COMMAND手动拼接命令;DB_PASSWORD建议使用 scope-variable 管理。
  • 云原生
  • DevOps
  • 运维

【免费下载链接】devtron

The only Kubernetes dashboard you need

项目地址:https://gitcode.com/gh_mirrors/dev/devtron
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询