从零搭建CI集成流水线的那些坑我都帮你踩过了
优化前:CI流水线慢得要命
最近把项目迁移到新的CI/CD流程,结果发现构建时间从原来的3分钟拖到了快8分钟,每次提交代码都得等半天,简直要命。最恶心的是测试阶段,光跑单元测试就要花4分多钟,感觉整个流程都在浪费时间。
我查了下之前的构建日志,发现几个明显的问题:依赖安装太慢、缓存没利用好、还有些测试其实可以在并行执行却串行跑了。最让我崩溃的是Docker镜像层没有合理利用,每次构建都是重新拉取所有依赖。
找到瓶颈了!
用GitHub Actions的详细日志看了下各步骤耗时,问题基本集中在几个地方:
- npm install 用了快2分钟
- 单元测试执行时间过长
- Docker build 时间能压缩但没处理
- 多个环境部署串行执行
我用 npm ls --depth=0 和 npm audit 先确认了依赖树没有循环引用,然后重点看缓存策略。确实,之前的 .npmrc 配置有问题,而且 Actions 中的缓存key设置也不够精细。
核心优化方案
先说最重要的依赖安装优化。原来的做法是每次都全量安装,现在改成按package-lock.json的hash值缓存node_modules:
- name: Get npm cache directory
id: npm-cache
run: |
echo "::set-output name=dir::$(npm config get cache)"
- name: Cache node modules
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
run: npm ci --prefer-offline --no-audit
这样改完后依赖安装时间从2分钟降到了30秒左右,效果很明显。npm ci本身就比npm install快不少,加上离线模式更是减少了网络请求。
接下来是测试环节的并行化。之前一个测试文件一个测试文件地跑,现在我把测试分成4个组,并行执行:
# 定义矩阵策略
strategy:
matrix:
shard: [1, 2, 3, 4]
# 测试命令改为分片执行
run: npm run test -- --shard=${{ matrix.shard }}/4
这样原本需要4分多钟的测试,现在1分钟出头就能搞定。不过要注意测试数据隔离,避免多个实例同时操作数据库产生冲突。
还有就是Docker镜像优化,这部分改动最大。原来的Dockerfile每层都没考虑到缓存复用:
# 优化前:所有东西一股脑放进去
COPY . .
RUN npm install
RUN npm run build
# 优化后:分层缓存
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY . .
RUN npm run build
这样做的好处是只有package.json变化时才会重新install依赖,大部分时候直接用缓存。构建时间从原来的3分钟降到了1分半。
缓存策略深度优化
除了node_modules,我还针对构建产物做了缓存。特别是TypeScript编译的增量缓存:
- name: Cache TypeScript build
uses: actions/cache@v3
with:
path: |
dist/**
.tsbuildinfo
key: ${{ runner.os }}-typescript-build-${{ hashFiles('src/**', 'tsconfig.json') }}
配合tsconfig.json启用incremental编译:
{
"compilerOptions": {
"incremental": true,
"tsBuildInfoFile": ".tsbuildinfo"
}
}
这个改动让后续的构建速度提升了不少,特别是只改了一个小文件的情况下,编译时间从30秒降到了5秒以内。
CI配置精简
之前有些不必要的步骤,比如每次都重新初始化环境变量、重复的权限检查等。我把这些冗余操作都删掉了,同时把一些可以合并的步骤合并起来。
还有一个容易忽略的地方是文件同步,原来每步都用cp命令复制文件,现在统一用actions/upload-artifact和actions/download-artifact,减少I/O操作。
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: build-output
path: dist/
retention-days: 7
性能数据对比
优化前后对比数据:
- 总构建时间:7分45秒 → 2分18秒
- 依赖安装:2分15秒 → 32秒
- 单元测试:4分20秒 → 1分15秒
- Docker构建:3分05秒 → 1分25秒
整体效率提升了约70%,这个提升还是很明显的。最重要的是开发体验变好了,提交代码后很快就能看到结果,不用干等着。
不过优化过程中也踩过几个坑。比如并行测试时数据库连接池不够用导致测试失败,后来加了数据库连接池的配置才解决。还有缓存key的设计,一开始用的太宽泛导致缓存命中率不高。
持续监控很重要
光优化完还不够,我还加了监控告警,一旦构建时间超过3分钟就发通知。用GitHub的workflow_run事件来监听构建状态:
on:
workflow_run:
workflows: ["CI Build"]
types: [completed]
jobs:
notify:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
steps:
- name: Check build time
run: |
duration=$(curl -s -H "Authorization: token $GITHUB_TOKEN"
"${{ github.event.workflow_run.artifacts_url }}" | jq -r '.artifacts[0].created_at')
# 添加超时检查逻辑
这样可以及时发现性能退化,防止后续提交影响构建效率。
还有提升空间
目前的优化主要集中在构建环节,后续还打算做几个改进:
- 进一步细分测试模块,提高并行度
- 考虑用更快的包管理器,比如yarn 2.0+
- 引入更智能的缓存策略,根据文件变化频率动态调整
不过现有的改动已经满足当前需求了,整个CI流程跑起来顺畅多了。
以上是我个人对CI集成性能优化的完整讲解,有更优的实现方式欢迎评论区交流。

暂无评论