☰
Databasus 的 assets/tools:数据库客户端二进制捆绑体系的版本标识、运行时解析与刷新机制
2026/9/25 5:07:37 网站建设 项目流程
  • 数据库
  • 灾备

【免费下载链接】databasus

PostgreSQL backup tool with Point-In-Time-Recovery and restore verification

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

Databasus 把 PostgreSQL、MySQL、MariaDB、MongoDB 四个引擎的客户端二进制直接提交在仓库的assets/tools/目录下,由 Go 后端在运行时按GOOS/GOARCH解析具体路径。读完本篇,你将理解这套捆绑树的目录布局与"发布线身份"(release line identity)设计、启动时逐个执行--version的校验机制、各引擎捆绑版本的来源与刷新流程,以及二进制对运行镜像共享库的依赖边界,并能在本地安全地刷新或新增一个客户端版本。

为什么把二进制提交进仓库,而不是在 Dockerfile 里 apt 安装

Databasus 备份流程依赖每个引擎每个受支持主版本的官方客户端:PostgreSQL 的pg_dump/pg_restore/psql(17+ 还有pg_basebackup等),MySQL 与 MariaDB 的mysqldump/mysql(MariaDB 侧为mariadb-dump/mariadb),MongoDB 的mongodump/mongorestore。项目最初的方案是在构建镜像时从 PGDG、MySQL、MariaDB、MongoDB 各自的 apt 仓库逐个apt-get install。当支持矩阵扩大后,这条路径出现了 CI 耗时超 30 分钟且频繁因镜像源超时、GPG 密钥轮换等外部原因失败,Dockerfile 里堆满仓库配置、密钥导入、多主版本安装等复杂度。

ADR-0005 记录的决策是:把实际用到的客户端二进制一次性下载后,按"引擎 + 主版本 + 架构"提交到assets/下,Dockerfile 只做COPY。收益是构建不再依赖任何第三方包仓库(可从干净 checkout 离线可复现构建)、发进镜像的字节就是仓库里可 review 的字节、升级客户端是一个可见的二进制替换提交。assets/tools/AGENTS.md也由此立下第一条规则:仓库里的字节就是发版的字节,因此二进制必须在运行时环境中验证,而不是在开发机上验证。

目录布局与架构键

整棵树的形状在两种架构下完全一致(每个子树一个 arch):

assets/tools/<arch>/ postgresql/postgresql-{12,13,14,15,16,17,18}/bin/ pg_dump, pg_restore, psql mysql/mysql-{5.7,8.0,8.4,9,26}/bin/ mysql, mysqldump mysql/mysql-26/lib/private/ libssl.so.3, libcrypto.so.3 mariadb/mariadb-{10.6,12.3,13.0}/bin/ mariadb, mariadb-dump mongodb/bin/ mongodump, mongorestore

<arch>的取值由 backend/internal/util/tools/paths.go 中的archAssetsKey()依据runtime.GOOS+runtime.GOARCH决定,不支持的组合会直接 panic(没有客户端二进制后端无法工作):

GOOS / GOARCHkey体积
linux/amd64x64~157 MB
linux/arm64arm~146 MB

后端解析单个二进制的完整路径规则是assets/tools/<arch>/<engine>/<engine>-<bundle>/bin/<command>。根目录不是写死的:AssetsToolsDir从当前工作目录逐级向上查找assets/tools/<arch-key>目录(Docker 里 cwd 是/app,解析到/app/assets/tools/<arch-key>/),找不到则 panic,见 paths.go。

版本标识是"发布线",不是补丁号

理解这棵树的关键概念是:目录名是一个发布线(release line),不是一个补丁号。mysql-26只装一个 26.x 的构建,但要服务所有 MySQL 26.x 服务器;mariadb-13.0装一个 13.0.x 构建,服务所有 MariaDB 13.x 服务器。目录名是我们自己贴的标签,构建捆绑时没有任何东西能强制它与实际字节一致——兜底是启动校验:后端会运行每个二进制的 version flag,拒绝任何"报告版本不属于本目录所登记发布线"的捆绑,使"名字"和"字节"无法悄悄漂移。

版本比较的实现集中在 releaseline.go:

  • parseReleaseLine把"26"、"10.6"这类标识拆成数字分量;
  • compareReleaseLines按数字逐位比较,保证后加入的新标识自动排到正确位置,不需要维护任何查找表(README 明确告诫"不要再去找版本表来扩展——已经没有遗留的了");
  • isVersionOnReleaseLine判断客户端报告的版本(如10.6.28)是否属于某条发布线:客户端可以比线号晚一个补丁,但绝不能来自另一条线。

这个设计的动机来自一个真实事故:捆绑内二进制版本不一致曾让 issue #725(pg_dump 18.1 悄悄输出错误的 sequence 值)长期未被发现。因此刷新时的铁律是同一条发布线内所有二进制必须来自同一个上游构建。

各引擎的捆绑版本明细

PostgreSQL

两个架构捆绑的 minor 完全相同,来源是 Debian bookworm 的 PGDG(apt.postgresql.org的postgresql-client-<major>):

majorminorsource package
1212.2212.22-3.pgdg12+1(final,EOL)
1313.2313.23-1.pgdg12+1(final,EOL)
1414.2314.23-1.pgdg12+1
1515.1815.18-1.pgdg12+1
1616.1416.14-1.pgdg12+1
1717.1017.10-1.pgdg12+1
1818.418.4-1.pgdg12+1

12 和 13 已过上游 EOL,表中的 minor 就是该主版本永远存在的最后一个小版本。

PostgreSQL 还是校验的"致命层":从 postgresql.go 可以看到,12–16 要求pg_dump与psql,而 17+ 额外要求pg_basebackup、pg_receivewal、pg_combinebackup(pg_basebackup --incremental与pg_combinebackup是 PG 17+ 才有的能力,服务于 Databasus 的 PG 17 物理备份链路)。common.go 中只有 PostgreSQL 捆绑损坏会让进程退出,其他引擎缺失则降级为警告并禁用该版本支持——一个不备份任何 MySQL 数据库的实例没有理由因为缺mysqldump而拒绝启动。

MySQL

两个架构的补丁号相同,来源是上游 glibc2.28 静态链接二进制 tarball,URL 模板形如https://cdn.mysql.com/Downloads/MySQL-<dir>/mysql-<patch>-linux-glibc2.28-{x86_64,aarch64}.tar.xz,其中<dir>在 9 及以前按发布线命名(如MySQL-9.0),26 起按<major>.<minor>(如MySQL-26.7):

bundlepatchnotes
mysql-5.75.7.44该线最后一个补丁;仅 amd64
mysql-8.08.0.46
mysql-8.48.4.11长期支持线
mysql-99.7.2服务所有 9.x 服务器
mysql-2626.7.0日历式命名;服务所有 26.x 服务器;自带 OpenSSL

MySQL 是"每条发布线一个专属客户端"的形态(mysql.go 中版本标识直接等于捆绑目录名后缀)。mysql-5.7只有 amd64——上游从未为 aarch64 构建过 5.7 客户端,所以arm/mysql/mysql-5.7/是故意不存在的;在 arm64 部署上连 5.7 服务器会在连接测试阶段被拒绝。

版本解析要注意 5.7 与 8.0+ 的--version输出形态不同:8.0+ 是mysqldump Ver 8.0.46 for ...,而 5.7 用工具自己的版本号并把服务器版本放在Distrib后面(mysqldump Ver 10.13 Distrib 5.7.44, for ...),所以 mysql.go 维护了两条正则(Distrib优先,Ver兜底)。

MariaDB

补丁号两个架构相同,由 tools/refresh-mariadb-bundle.sh 从厂商官方包仓库解包得到:

bundlepatchsource repository and suite
mariadb-10.610.6.28repo/10.6/ubuntu,ubu2204
mariadb-12.312.3.3repo/12.3/debian,deb12(bookworm)
mariadb-13.013.0.2repo/13.0/ubuntu,ubu2204

MariaDB 与 MySQL 的形态不同:它维护"服务器版本标识"和"客户端版本"两个值,因为一个客户端要服务多条服务器发布线。三层客户端的映射在 mariadb.go 的GetMariadbClientVersionForServer中:

  • 10.6(legacy)服务 MariaDB 5.5 和 10.1。存在它的原因是新版客户端会查询generation_expression列,而该列是 10.2 才加入information_schema.columns的。10.6 包里的真实程序仍叫mysql和mysqldump,刷新脚本会把它们以mariadb/mariadb-dump的名字装进捆绑目录;
  • 12.3(modern)按设计服务 10.2 到 12.x 的所有线;
  • 13.0服务 13 线——12.3 客户端比 13 线更老,覆盖不了。

刷新脚本的用法是tools/refresh-mariadb-bundle.sh <bundle> <arch>(bundle 为10.6 | 12.3 | 13.0,arch 为amd64 | arm64)。它的几个实现细节值得注意:包版本在脚本内逐捆绑写死(如10.6.28+maria~ubu2204)而不是取"该线最新补丁",这样相隔一周刷新的两个架构拿到的是同一构建;.deb 只解包不安装(dpkg-deb -x,无 dpkg 时回退ar+tar),因此在 amd64 主机上构建 arm64 树无需模拟执行;最后用install -m 0755落盘并打印 sha256。

MongoDB

两个架构统一捆绑 MongoDB Database Tools 100.16.1,向后兼容所有受支持服务器版本(4.2 – 8.2);MongoDB 4.0 不受支持(wire version 7,需要更老的 mongodump)。MongoDB 是唯一"不按发布线命名"的捆绑——mongodb.go 中它没有版本线可对齐,校验只要求二进制能启动。

启动校验:每个二进制都要亲自跑一遍--version

文件存在且带可执行位只说明目录没摆错,说明不了缺失共享库——而这恰恰是新捆绑最容易引入的故障。因此 common.go 的runClients会把每个必需命令以--version实际启动(10 秒超时,超时视同缺失),用各引擎自己的解析器读出版本号,再断言其属于目录所登记的发布线。三个细节:

  • 结果按 bin 目录缓存(executionVerdicts):容器健康探测每 30 秒一次,若每次探测都启动全部二进制,高负载主机可能误报不健康,所以每个进程只跑一次;
  • 解析器按引擎分开:PostgreSQL 匹配(PostgreSQL) 17.10,MariaDB 用正则(\d[\d.]*)-MariaDB(mariadb-dump --version会打印两个数字,-MariaDB前面那个才是服务器线,另一个是协议版本),MySQL 匹配Distrib/Ver,见 mariadb.go;
  • CheckAllClientTools同时服务于启动(config)与健康检查(healthcheck),纯函数、不记日志不退出,由调用方决定致命还是告警。

二进制如何进入镜像

根目录的 Dockerfile 通过 buildkit bind mount 把assets/tools挂进来,按TARGETARCH只拷贝匹配的架构子树到/app/assets/tools/,然后对 postgresql/mysql/mariadb/mongodb 四棵子树的bin/*统一chmod +x。这也是 AGENTS 清单强调"确认可执行位已记录在 git 索引"的原因:git ls-files -s必须显示100755——以100644提交的二进制不会在构建时失败,而是在运行时失败。

运行时共享库依赖边界

捆绑二进制全部以 glibc 2.28 或更低为目标,而运行镜像是debian:bookworm-slim(glibc 2.36)。它们从运行镜像需要、但不能自带这些共享库:

libraryneeded by
libc、libm、libgcc_s、libstdc++所有二进制
libssl.so.3、libcrypto.so.3MySQL 8.0 至 9 及 MariaDB 客户端、libpq
libz.so.1、libzstd.so.1、liblz4.so.1MariaDB 客户端、libpq
libncurses.so.6、libtinfo.so.6MySQL 8.0+ 与 MariaDB 交互客户端
libncurses.so.5、libtinfo.so.5仅 MySQL 5.7 交互客户端
libreadline.so.8PostgreSQL 13+ 的psql
libedit.so.2所有mariadb交互客户端、PostgreSQL 12 的psql
libpq.so.5PostgreSQL 客户端
libgssapi_krb5.so.2MongoDB 工具

三个特殊案例:

  1. MySQL 26 自带 OpenSSL。26 客户端调用 OpenSSL 3.2 的符号,而 bookworm 只带 3.0;其RUNPATH是$ORIGIN/../lib/private,所以mysql-26/lib/private/里放着与二进制同源自上游 tarball 的libssl.so.3和libcrypto.so.3(OpenSSL 3.5.7),加载器会优先于镜像里的副本。校验 OpenSSL 符号版本的方法与 glibc 相同,用objdump -T按OPENSSL_3\.[0-9]+检查——开发机上更新的 OpenSSL 会掩盖问题,所以必须在运行镜像里跑一次。
  2. libedit.so.2是"搭便车"进镜像的。它不是 Dockerfile 显式安装的,而是postgresql-common的依赖;删掉那个包就会连带带走 MariaDB 交互客户端。它也是非 Debian 开发机唯一缺的 soname——Fedora 提供的是上游libedit.so.0。backend/Makefile 的libedit-shimtarget 用符号链接 +LD_LIBRARY_PATH绕过这一点,make test-fedora和make run-fedora都依赖它。
  3. 验证命令模板。新增/刷新二进制后,在运行基础镜像里跑一遍是最小验证:
docker run --rm --platform linux/amd64 -v "$PWD/assets/tools:/tools:ro" \ debian:bookworm-slim bash -c 'apt-get update -qq && \ apt-get install -y -qq libedit2 libncurses6 libtinfo6 libssl3 >/dev/null && \ /tools/x64/<engine>/<bundle>/bin/<command> --version'

刷新补丁与新增版本的检查清单

刷新风险低于新增版本,但它同时更换了所有使用该捆绑的服务器的客户端,不是静默操作。assets/tools/AGENTS.md 给出的流程要点:

刷新一个补丁:

  • 同一捆绑内所有二进制必须来自同一上游构建(issue #725 的教训);
  • 在刷新脚本里固定确切的上游包版本,不取"该线最新补丁";
  • 两个架构在同一次变更中从同一上游源刷新;
  • 提交前在debian:bookworm-slim里运行刷新后的二进制;
  • 用git ls-files -s确认可执行位为100755;
  • 跑该引擎的完整测试矩阵(测试矩阵位于backend/internal/features/databases/databases/<engine>/model_test.go与backend/internal/features/tests/logical/<engine>/backup_restore_test.go,会拉起每个版本真实的服务器);
  • 在同一次变更里更新本目录 README 的表格。

新增一个引擎版本:先确认上游是否仍对该线发补丁(短期线大约活一个季度,优先捆绑同时代的长期支持线);按"厂商架构无关 tarball → Debian 仓库 → Ubuntu 仓库 → 老企业发行版 RPM"的顺序核查双架构二进制是否存在,查完一种来源不要就下结论;用objdump -T <binary> | grep -oE 'GLIBC_2\.[0-9]+' | sort -uV | tail -1比对 glibc 要求、用objdump -p <binary> | grep NEEDED列共享库,全部必须已在镜像中;捆绑目录与"版本身份"必须一起落地(后端常量和frontend/src/entity/databases/model/<engine>/里的前端常量同名同值,缺失会直接变成编译错误而不是空白字段);最后同步更新根 README 与assets/readme/下五份语言副本的支持版本列表。

这里不能做的事:不要往Dockerfile里装客户端二进制(ADR-0005 已否决);不要为了迁就一个客户端而往运行镜像里加共享库——如果存在基于镜像既有库构建的版本,用那个版本;构建捆绑时不要信任目录名,用--version实际运行来确认二进制身份(启动校验只是最后一道网,不是第一道)。

小结

assets/tools/的设计可以浓缩为三条:发布线命名把"一个补丁"与"一条版本线"解耦,由 releaseline.go 的数值比较支撑,使升级、回退判断不再依赖查找表;CheckAllClientTools用真实执行而非静态检查来守住"目录名与字节一致"的承诺,且对缺失共享库这类最高风险故障直接暴露;刷新流程(以 refresh-mariadb-bundle.sh 为代表)通过版本钉死、解包不安装、双架构同源、运行镜像内验证,保证两个架构永远不会悄悄分叉。这套机制让 Databasus 的多引擎备份能力建立在"仓库里的字节即发版的字节"之上。

  • 数据库
  • 灾备

【免费下载链接】databasus

PostgreSQL backup tool with Point-In-Time-Recovery and restore verification

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

相关推荐

上一篇:Clean Code PHP:提升PHP代码质量的终极指南
下一篇:MoneyPrinterPlus终极指南:一键AI批量生成短视频,轻松实现流量变现💰

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

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

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

立即咨询