☰
Baserow CI/CD 流水线全解:5 个阶段如何把一次提交变成 Dockerhub 上的镜像
2026/9/26 7:44:04 网站建设 项目流程

Baserow CI/CD 流水线全解:5 个阶段如何把一次提交变成 Dockerhub 上的镜像

【免费下载链接】baserowBuild databases, automations, apps & agents with AI — no code. Open source platform available on cloud and self-hosted. GDPR, HIPAA, SOC 2 compliant. Best Airtable alternative.项目地址: https://gitcode.com/GitHub_Trending/ba/baserow

如果你自托管过 Baserow——这款开源自托管无代码数据库(常被称为 Airtable 的开源替代方案),大概率拉过baserow/backend:latest这类镜像,却很少关心它们是怎么来的。答案就在仓库根目录的 .gitlab-ci.yml 里:一条基于 GitLab CI 的流水线,把"推一个 commit"这件事拆成五个阶段——构建开发镜像、跑测试、构建生产镜像、推送发布、触发下游项目。本文按这条流水线的实际走向,讲清每个阶段做什么、什么分支下会跳过、以及缓存与发布环节的几个设计取舍。

先记住三根分支和两个前缀

流水线的所有行为都由分支决定,先立好坐标系:

分支角色流水线行为
feature branches从develop切出的功能分支只做构建 + 测试,不构建生产镜像,不推送
develop集成所有新功能的开发分支全流程执行,测试通过的生产镜像推 Dockerhub 并打develop-latest标签
master官方发布分支全流程执行,且额外构建 ARM64 多平台镜像;打 tag 时才真正发布版本

配套的两个镜像标签前缀贯穿整个流程:

  • ci-latest-<commit sha>:构建阶段的产物,供同一条流水线的后续阶段使用;
  • ci-tested-<commit sha>:测试全部通过后才打上的"合格章",发布阶段只允许推送带这个前缀的镜像。

所有具体的作业定义不在 .gitlab-ci.yml 里,而是复用 .gitlab/ci_includes/jobs.yml 中的公共模板(如.build-baserow-image、.build-final-baserow-image),主文件只负责声明阶段、变量和各类only/except规则。

阶段一:构建开发镜像,顺手当缓存用

第一个build阶段构建backend_dev和web-frontend_dev两个"开发版"镜像。这里的"开发版"指的是多阶段 Dockerfile 中--target ci的那个阶段:包含全部 Python 依赖和 Node 依赖,但不包含完整的应用代码。

为什么要专门构建它?两个用途:

  1. 依赖缓存。开发镜像里预装好的库可以被后续构建复用,不用每次重新安装;
  2. 测试环境。lint 和 test 阶段直接把这个镜像当容器跑,把 git 源码挂载进去即可,测试机不需要再装一遍环境。

构建时带BUILDKIT_INLINE_CACHE=1参数,保证镜像的所有中间层都可被下一次构建缓存。构建完的镜像同时打上ci-latest-$CI_COMMIT_SHORT_SHA(供本条流水线内部按 SHA 精确引用)和ci-latest-$分支名(供本分支下条流水线做缓存种子)两个标签。

阶段二:lint 与测试,只在相关目录变动时跑

lint和test阶段都套用了.skippable-job模板:只有RUN_WHEN_CHANGES_MADE_IN指定的目录(如backend/、premium/backend/、enterprise/backend/)有改动时才执行;若历史上同一提交(或更早提交)已成功跑过且相关文件没变化,还会直接复用上次结果跳过。

测试本身做了两层拆分:

  • 后端 pytest:拆成backend-test-group-1到group-10共 10 个并行作业,每个作业跑PYTEST_SPLIT_GROUP指定的 1/10 测试集。之所以不用 pytest-xdist 的-n参数,是因为 SaaS runner 只有单虚拟核,进程内并行反而更慢。跑完后collect-backend-coverage作业把 10 份覆盖率数据合并成一份 Cobertura 报告;
  • E2E 测试(Playwright + Firefox):e2e-tests-group-1到group-4按SHARD_INDEX四分片,服务里同时拉起pgvector/pgvector:pg14、redis:6-alpine、adobe/s3mock以及后端/前端的 CI 开发镜像,完整模拟一套 Baserow 服务。仅 feature 分支跑,develop/master上靠其他覆盖。

前端则跑web-frontend-lint(eslint + stylelint)和web-frontend-test,另有docker-file-hadolint检查所有 Dockerfile、mjml-compiled-check保证邮件模板编译产物已提交。

阶段三:生产镜像只在 develop、master 或[build-all]时构建

build-final阶段构建不带 dev 目标的正式镜像:backend、web-frontend,以及 all-in-one 的baserow、Cloudron、Heroku 变体(后者需要[build-all]或BUILD_ALL_IN_ONE=true才构建,Heroku 镜像只是验证可构建性,不会推送)。

这一阶段复用阶段一的开发镜像作为--cache-from,只重新构建应用层,所以很快。构建成功且测试全部通过后,dev 和正式镜像都会补打ci-tested-$CI_COMMIT_SHORT_SHA标签——这是发布阶段的准入门槛。

在 feature 分支上,正式镜像的构建作业(如build-final-backend-image-manual)处于when: manual状态,不点不跑,默认只走阶段一、二。

阶段四:镜像何时被推到 Dockerhub

publish阶段的推送作业按分支和 tag 分三类:

触发条件推送的标签
develop最新提交baserow/backend:develop-latest、baserow/web-frontend:develop-latest、baserow/baserow:develop-latest(all-in-one)、baserow/cloudron:develop-latest
对 master 最新提交打版本 tag(如1.8.2)baserow/backend:1.8.2+baserow/backend:latest
对 master 历史提交补打 tag只推baserow/backend:<tag>,不动latest

每个 publish 作业都有SKIP_IF_TAG_NOT_ON_BRANCH: master和SKIP_IF_NOT_LATEST_COMMIT_ON_BRANCH保护:非 master 上的 tag 直接失败(tag 只允许打在 master),非分支最新提交则跳过,防止把过期的ci-tested镜像推出去。tag 触发的流水线里所有 build 作业被except: tags排除——tag 流水线唯一的职责就是"把已经测过的镜像换个标签推出去",如果那个 SHA 的测试没通过或镜像不存在,publish 会直接失败。

另外,master 的 tag 流水线还会跑publish-helm-chart:打包 deploy/helm 下的 Helm chart,触发 chart 仓库的流水线完成上传,版本号取自 git tag。

阶段五:通知下游项目重建

trigger-saas-build作业在develop上把CI_COMMIT_SHA、已测试镜像地址等变量传递给依赖 Baserow 镜像的下游项目(如 saas 项目),让它们的流水线可以复用上游刚构建的产物,而不必自己再构建一遍。

用两个提交标签和一条手动流水线控制行为

不需要改配置,改提交信息即可:

  • [skip-ci]:该 commit 完全跳过流水线;
  • [build-all]:在任意分支强制构建全部镜像,包括 all-in-one、cloudron、heroku 等正式变体。

更细粒度的控制来自手动流水线:在 GitLab 的 pipelines/new 页面为指定分支手动触发,可以临时覆盖任意变量。.gitlab-ci.yml 顶部就声明了这些可覆盖项:

  • TRIGGER_FULL_IMAGE_REBUILD=yes:所有构建加--no-cache --pull,完全从零重建;
  • ENABLE_JOB_SKIPPING:是否允许跳过历史已成功的测试;
  • ENABLE_COVERAGE:是否生成覆盖率报告;
  • BUILD_ALL_IN_ONE=true:强制构建 all-in-one 镜像。

调试 CI 配置本身时(比如改了 jobs.yml 想验证),手动流水线是最直接的手段。

发布一个新版本到 Dockerhub 的完整步骤

把上面几节串起来,一次正式发布(假设版本号1.8.2)的实际操作只有四步:

  1. 在 GitLab 上创建并合并develop→master的 MR,等 master 上合并提交的流水线跑完(完成构建 + 测试,产出ci-tested镜像);
  2. 在 GitLab 界面上给该合并提交打 git tag1.8.2;
  3. GitLab 自动为这个 tag 新建一条流水线,publish 作业把镜像推为baserow/*:1.8.2和baserow/*:latest;
  4. 同时publish-helm-chart把对应版本的 Helm chart 发布出去。

第 1 步如果没跑成功,第 3 步的流水线会失败且不推送任何东西——发布链路里没有"人工确认镜像"的环节,测试即放行。

缓存查找顺序:为什么 master 只认 develop 的缓存

构建作业找缓存的顺序是(见 .gitlab/ci_includes/jobs.yml 中.build-baserow-image的脚本):

  1. 非 master 分支:先拉本分支最新的ci-latest-$分支名镜像;
  2. 拉不到再拉ci-latest-develop;
  3. 都没有则完全从零构建。

master 是个例外:它只用 develop 的ci-latest镜像做缓存,不用自己的。原因写在官方文档 docs/development/ci-cd.md 里:

  • master 两次发布之间可能几周没有流水线,自己的ci-latest缓存要么早被清理,要么层内容严重过期;
  • 基础层若有破坏性变更,先让它在 develop 上暴露并被修好,master 复用 develop 验证过的层,避免"测试的镜像"和"发布的镜像"不是同一个;
  • 全量重建的工作只在 develop 做一次,master 直接受益,不重复劳动。

缓存的安全隐患,用每日全量重建来对冲

Docker 层缓存有个众所周知的问题:FROM base_image和apt upgrade这类层一旦被缓存,即使基础镜像发布了安全补丁也永远不会重跑。Baserow 的对策是:

  • 每日定时流水线:develop 分支上有一个 scheduled pipeline,设置TRIGGER_FULL_IMAGE_REBUILD=yes,让所有构建--no-cache --pull从零重建,刷新全部ci-latest-develop缓存镜像;
  • 顺带跑重型测试:同一条早间流水线会激活标记为@pytest.mark.once_per_day_in_ci的测试,这些测试平时不跑、每天只跑一次。

由于 master 和其他分支的缓存源头都指向 develop 的ci-latest镜像,一次每日重建就覆盖了所有分支的缓存安全。

临时镜像方面,ci-latest-*和ci-tested-*前缀的镜像由 GitLab 的 registry 清理规则在 7 天后自动删除(每天 11:00 CET 执行一次清理作业)。

ARM 多平台构建:为什么只有 master 做

master 上推送到 Dockerhub 的镜像同时支持linux/amd64和linux/arm64/v8,由BUILD_ARM和BUILD_ARM_ON_BRANCH=master两个变量控制。实现方式是 Docker buildx 的远程构建:CI 作业通过 SSH 连接一台专用 ARM64 服务器,把 ARM 部分的构建卸载过去(.build-baserow-image脚本里的docker buildx create --append ... --platform linux/arm64/v8 "$ARM_TARGET")。

两个设计取舍:

  • 为什么不在 develop 上构建 ARM:加 ARM 会让流水线多花 5–10 分钟,把它只放在 master 上能显著加速日常开发迭代,develop 和 feature 分支的镜像只支持 AMD64;
  • 为什么不用 QEMU 模拟:实测在 runner 上模拟 ARM 构建单个镜像要 1 小时以上,专用硬件是必要的。

本地怎么跑对应的测试

CI 里跑的东西本地基本都能复现,入口在 justfile 和 dev.sh:

# 后端测试(全部 / 并行 / 指定目录) just b test just b test -n=auto just b test tests/path/ # 用内存盘 PostgreSQL(端口 5433)加速 2-5 倍 just test-db start DATABASE_URL=postgres://baserow:baserow@localhost:5433/baserow just b test -n=auto just test-db down

更细节的设置(--reuse-db、BASEROW_TESTS_SETUP_DB_FIXTURE等)见 docs/development/running-tests.md。E2E 测试对应e2e-tests/目录,本地可用e2e-tests/run-e2e-tests-locally.sh启动;dev.sh 也会开一个 "e2e tests" 标签页直接调起它。

常见疑问速答

develop 的develop-latest和 master 的latest有什么区别?develop-latest是开发中的滚动镜像,每次 develop 提交成功后覆盖;latest只在 master 打版本 tag 时更新,指向正式发布的最后一个版本。想尝鲜拉前者,求稳拉后者或具体版本号。

为什么 tag 打在非 master 提交上会失败?tag 流水线不做构建,只推送已存在的ci-tested镜像,而"这个提交是否在 master 上通过过完整流水线"正是SKIP_IF_TAG_NOT_ON_BRANCH检查的内容,保证发布镜像一定经过测试。

改了 CI 配置想立即验证?.gitlab/ci_util_image和.gitlab/ci_dind_image两个基础 CI 镜像的构建作业是when: manual,且只在对应目录或 .gitlab-ci.yml 变化时出现——提 MR 改完配置,在流水线页面手动点一下即可重建并推送。

CI 全流程文档在哪?仓库内的 docs/development/ci-cd.md 是最权威的版本,包括本文涉及的缓存逻辑、发布流程和 FAQ 的完整推导。

【免费下载链接】baserowBuild databases, automations, apps & agents with AI — no code. Open source platform available on cloud and self-hosted. GDPR, HIPAA, SOC 2 compliant. Best Airtable alternative.项目地址: https://gitcode.com/GitHub_Trending/ba/baserow

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

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

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

立即咨询