CI/CD 流水线优化指南——从入门到高效

CI/CD 流水线优化指南——从入门到高效

作者: CaoZH
日期: 2026-04-15
本文为原创教程


很多团队的 CI/CD 流水线一次构建要跑 30 分钟以上,严重拖慢开发效率。本文从实际优化经验出发,系统性地介绍如何让 CI/CD 流水线跑得更快更稳。

一、测量现状

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
name: CI Pipeline

on: [push]

jobs:
# 记录每个阶段的耗时,找到瓶颈
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
run: echo "耗时分析"

- name: Install dependencies
run: echo "依赖安装时间"

- name: Lint
run: echo "Lint 时间"

- name: Test
run: echo "测试时间"

- name: Build
run: echo "构建时间"

使用 GitHub Actions 的 Summary 页面查看每个步骤耗时,找到最慢的部分。

二、缓存策略

依赖缓存

1
2
3
4
5
6
7
- name: Cache npm dependencies
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-

Maven 缓存

1
2
3
4
5
6
7
- name: Cache Maven dependencies
uses: actions/cache@v4
with:
path: ~/.m2
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-

Docker 镜像缓存

1
2
3
4
5
6
7
- name: Cache Docker layers
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-

三、并行化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
jobs:
# 并行运行 Lint 和 Test
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run lint

test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run test

# 测试矩阵(多版本、多平台)
test-matrix:
strategy:
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, windows-latest]

runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test

# 测试通过后才构建和部署
build:
needs: [lint, test, test-matrix]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run build

四、条件执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 只在特定路径变更时才运行
on:
push:
paths:
- 'src/**'
- 'package.json'
- '.github/workflows/**'
paths-ignore:
- 'docs/**'
- 'README.md'
- '*.md'

jobs:
backend-test:
# 只在后端代码变更时才运行
if: contains(join(github.event.commits.*.modified, ','), 'backend/')

deploy:
# 只在 main 分支且测试通过后部署
if: github.ref == 'refs/heads/main' && success()

五、分阶段流水线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
name: Efficient CI/CD

on:
push:
branches: [main, develop]
paths-ignore: ['docs/**', '*.md']

jobs:
# 阶段一:快速检查
quick-checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci --prefer-offline
- run: npm run lint
- run: npm run type-check
- run: npm run test:unit -- --changed

# 阶段二:全面测试
full-tests:
needs: quick-checks
strategy:
matrix:
shard: [1, 2, 3, 4]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run test -- --shard=${{ matrix.shard }}/4

# 阶段三:构建
build:
needs: full-tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- run: |
docker build \
--cache-from=type=gha \
--cache-to=type=gha,mode=max \
-t myapp:${{ github.sha }} .
- run: docker push myapp:${{ github.sha }}

# 阶段四:部署
deploy:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: |
ssh deploy@server "docker pull myapp:${{ github.sha }} && docker compose up -d"

六、优化效果对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
## 优化前(35分钟)
检出 → 安装依赖 → Lint → 测试 → 构建 → Docker构建 → 部署
(5m) (8m) (3m) (5m) (8m) (4m) (2m)
全部串行执行

## 优化后(8分钟)
┌── 检出(30s)
├── 安装依赖并行 ↓
│ ├── Lint(2m) ← 并行
│ ├── 单元测试(3m) ← 并行
│ └── 类型检查(1m) ← 并行
├── 集成测试(3m,分片4×并行)
├── Docker构建(2m,带缓存)
└── 部署(1m,条件执行)

七、错误处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 失败时自动重试
- name: Flaky test retry
uses: nick-fields/retry@v3
with:
timeout_minutes: 10
max_attempts: 3
command: npm run test:e2e

# 发送通知
- name: Notify on failure
if: failure()
uses: slackapi/slack-github-action@v2
with:
webhook: ${{ secrets.SLACK_WEBHOOK }}
message: "CI 失败: ${{ github.repository }}@${{ github.ref }}"

# 收集调试信息
- name: Upload debug info
if: failure()
uses: actions/upload-artifact@v4
with:
name: debug-info
path: |
test-results/
*.log

八、总结

1
2
3
4
5
6
7
8
9
10
11
12
13
14
## CI/CD 优化清单

□ 启用依赖缓存(npm/Maven/Docker)
□ 并行运行独立任务
□ 使用测试分片加速大规模测试
□ 只在需要时运行 CI(path filter)
□ 使用条件执行(只部署 main 分支)
□ Docker 构建缓存
□ 失败时自动重试不稳定测试
□ 分阶段流水线(快速失败)

## 效果
优化前:30-60 分钟
优化后:5-15 分钟

首发于 CaoZH 的笔记