- 约925字
- 技术
- 2026年4月17日
从30分钟到5分钟,我花了3周时间优化GitHub Actions。
这不是什么高大上的架构改造,而是3个看似简单却容易被忽视的配置调整。如果你也在为CI/CD构建时间太长而头疼,这篇踩坑总结应该能帮到你。
背景:30分钟的痛
去年接手的项目,CI/CD流程是这样的:每次push代码,等待30分钟才能部署到测试环境。团队里每个人都抱怨,但一直没人管。
我决定花时间彻底解决这个问题。花了3天排查,定位到3个主要瓶颈:
- 依赖安装每次都重新下载
- 测试脚本没有并行化
- 镜像构建没有缓存
接下来一个个解决。
第一个优化:依赖缓存
第一个问题是最容易解决的——每次构建都重新下载依赖。
- name: Cache node modules
uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
加上这个缓存之后,第二次构建时间直接从30分钟降到18分钟。原理很简单:依赖包不常变,缓存下来能省掉大量下载时间。
但这只是开始。
第二个优化:测试并行化
第二个问题更隐蔽:测试脚本是串行执行的。
- name: Run tests
run: npm run test
- name: Run lint
run: npm run lint
这两个步骤是完全独立的,完全可以并行。GitHub Actions 的 matrix strategy 可以轻松实现:
strategy:
matrix:
task: [test, lint, type-check]
jobs:
${{ matrix.task }}:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm run ${{ matrix.task }}
加上这个改动后,构建时间从18分钟降到10分钟。
第三个优化:Docker层缓存
最后一个大问题在镜像构建阶段。之前每次构建都要从头开始编译,浪费时间。
改用 docker/build-push-action 并开启缓存:
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: false
tags: myapp:latest
cache-from: type=registry,ref=myapp:buildcache
cache-to: type=registry,ref=myapp:buildcache,mode=max
这样每次构建都会复用上一层的缓存结果,只有变动的部分才需要重新构建。
最终,构建时间从10分钟降到5分钟。
复盘:踩过的坑
优化过程中也踩过几个坑:
第一,不要过度缓存。最初我尝试缓存了整个 node_modules 目录,结果在新版本依赖发布后导致构建失败。后来改成只缓存 node_modules 目录本身,让 npm install 在依赖变化时自动更新。
第二,matrix 任务数量要合理。最初我把所有任务都放进 matrix,导致并发数太高反而增加了队列等待时间。后来把相关任务打包,每个 job 控制在 3-4 个子任务。
第三,缓存策略要定期清理。buildcache 会不断增长,要设置过期时间或者定期手动清理,否则磁盘空间会爆。
下一步
目前构建时间是5分钟,下一步目标是降到3分钟。计划尝试:
- 使用更小的基础镜像
- 把静态资源提前上传到 CDN
- 优化测试覆盖率统计
如果你也在优化CI/CD,欢迎在评论区分享你的经验。