使用 GitHub Actions 重构和优化发布流程的实用技巧

译者 | 刘汪洋
审校 | 重楼
概括:这篇文章分享了作者在使用 Github Actions 作为 CI/CD 工具时遇到的一些问题和解决方案 , 包括如何避免重复代码、如何管理环境变量、如何使用缓存和工件、如何利用复用工作流等 。
开始构建发布流水线GreptimeDB 自开源伊始 , 就采用 GitHub Actions 实现了自动化软件构建过程 , 从而诞生了首个发布流水线 。
对于开源项目 , 构建一个稳定且一致的发布流水线具有以下关键价值:

  1. 供应随时可用的软件构件:身为软件供应链的上游生产者 , 我们必须为不同的下游用户提供安全、可信赖、随时可用的软件构件 , 如二进制文件、镜像等 。
  2. 优化开发者体验:用户可无需繁琐配置或从零开始设置和编译 , 即可获取适合各自平台的即时可执行的软件构件 。
  3. 实现发布工作流的自动化测试:结合不同类型的回归测试(例如性能、稳定性、集成测试等)和自动发布流程 , 以提高软件的整体质量 。
虽有其他替代方案 , 如 Circle CI、Travis CI、GitLab CI , 或自托管的开源项目如 Tekton 和 Argo Workflow ,  但选择 GitHub Actions 的理由显而易见:它与 GitHub 生态系统融合 , 为用户提供了便捷的操作界面和丰富的软件市场访问权限 。
然而 , 用户友好并不意味着维护轻松 。相反 , GitHub Actions 的维护可能变得复杂 。GreptimeDB 的最初开源版本中的 release.yml 仅包含了精炼的183行代码 。但随着许多贡献者的修改 , 这份文件逐渐演变并整合了:
  • 构建多样化平台上的构件;
  • 构建激活软件构件的不同功能开关;
  • 在实际构建之前执行集成测试;
  • 将软件构件推送到不同仓库(如 DockerHub、ACR、S3等);
  • 控制不同的发布条件(如手动触发、错误容限等);
  • 等等 。
还有 , 由于一些特殊需求(如调试发布、每日构建等) , 在不同的内部仓库中产生了许多只有微小差异的相似流水线分支 , 这增加了维护的压力 。
随着构建要求的复杂性不断提高 , release.yml 文件迅速变得庞大 , 充满了冗余配置 , 维护难度增大 。如果不及时进行重构 , 发布流水线将面临迅速甚至彻底的失效风险 。
发布流水线退化问题分析随着构建要求的复杂性不断提高 , release.yml 文件迅速变得庞大 , 充满了冗余配置 , 维护难度增大 。如果不及时进行重构 , 发布流水线将面临迅速甚至彻底的失效风险 。
发布流水线退化问题分析审查release.yml文件后 , 我们需要识别一些促使它迅速退化的因素 。只有深入了解问题的根源 , 我们才能制定合适的重构方案 。
  1. 语言局限性:GitHub Actions 的基于 YAML 的领域特定语言(DSL)与通用编程语言相比表现力不足 , 从而可能产生冗余和难以维护的代码 。
  2. 调试难度高:GitHub Actions 因难以调试而闻名 , 特别是项目使用的 Rust 语言编译成本较高 , 进一步加长了调试周期 。尽管如 act 等工具可以在本地执行 GitHub Actions , 但实际运行操作仍然必须进行 , 因此无法有效缩短编写-运行-调试的周期 。
  3. 动作解耦不足:GitHub Actions 通过 Composite 组合不同动作 。我们由于缺乏经验 , 未将逻辑分解为独立动作 , 而是将所有内容集中到一个 YAML 文件中 , 因此维护起来较为困难 。
  4. 重复构建问题:由于 GitHub 缺乏支持 ARM64 的虚拟机实例 , 为了优化编译性能 , 我们选择在 GitHub 的 x86_64 虚拟机实例上进行 AMD64 和 ARM64 软件构件的跨平台编译 。虽然可以使用 Docker Buildx 激活 QEMU 进行 ARM64 平台模拟构建 , 但性能不佳 。由于我们依赖于 GitHub Runner 主机环境而非 Dockerfile , 实现一致的可重复构建颇具挑战性 。


    推荐阅读