# 前端CI/CD自动化部署实践
持续集成(CI)和持续部署(CD)是现代开发流程中不可或缺的一部分。在我参与的多个项目中,自动化部署显著提高了团队效率,减少了人为错误。本文将分享如何为前端项目搭建一套完整的CI/CD流程。
# 什么是CI/CD?
- 持续集成(Continuous Integration): 开发人员频繁地将代码集成到主分支,通过自动化构建和测试确保新代码不会破坏现有功能
- 持续交付(Continuous Delivery): 将代码变更自动发布到预生产环境,等待手动批准后发布到生产环境
- 持续部署(Continuous Deployment): 自动将通过测试的代码变更发布到生产环境
# 前端CI/CD的价值
- 提高发布频率:从传统的每周发布到可能每天多次发布
- 减少人为错误:避免手动操作带来的失误
- 快速发现问题:在开发初期就发现问题
- 保证代码质量:通过自动化测试和代码检查提高质量
- 团队协作更顺畅:减少合并冲突,提高协作效率
# 工具选择
常用的CI/CD工具:
- Jenkins: 功能强大,高度可定制,开源
- GitHub Actions: 与GitHub紧密集成,配置简单
- GitLab CI/CD: 与GitLab一体化,适合自托管GitLab
- Circle CI: 云服务,易于配置
- Travis CI: 开源项目免费使用
在字节跳动期间,我们使用内部CI系统,而在其他项目中,我常用Jenkins和GitHub Actions。本文将主要介绍GitHub Actions的配置。
# GitHub Actions实战配置
# 基本概念
GitHub Actions的几个核心概念:
- Workflow(工作流): 一个自动化流程,由一个或多个jobs组成
- Event(事件): 触发workflow的条件,如push、pull request
- Job(作业): workflow中的一个单独的执行单元
- Step(步骤): job中的一个任务
- Action(动作): 可重用的自动化操作
# 基础配置
在项目根目录创建.github/workflows/ci-cd.yml:
name: Frontend CI/CD
# 触发条件
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
# 检出代码
- uses: actions/checkout@v3
# 设置Node.js环境
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '16'
cache: 'npm'
# 安装依赖
- name: Install dependencies
run: npm ci
# 运行代码检查
- name: Run linting
run: npm run lint
# 运行单元测试
- name: Run tests
run: npm run test
# 构建项目
- name: Build project
run: npm run build
# 保存构建产物
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: build-files
path: dist/
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
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
# 多环境部署配置
为开发、测试和生产环境配置不同的部署流程:
name: Frontend CI/CD
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
# 前面的步骤相同...
# 保存构建产物
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: build-files
path: dist/
deploy-dev:
needs: build-and-test
if: github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
steps:
# 下载构建产物
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: build-files
path: dist
# 部署到开发环境
- name: Deploy to Dev
uses: easingthemes/ssh-deploy@main
with:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
ARGS: "-avz --delete"
SOURCE: "dist/"
REMOTE_HOST: ${{ secrets.DEV_HOST }}
REMOTE_USER: ${{ secrets.DEV_USER }}
TARGET: ${{ secrets.DEV_TARGET_DIR }}
deploy-prod:
needs: build-and-test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production # 需要手动批准
steps:
# 下载构建产物
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: build-files
path: dist
# 部署到生产环境
- name: Deploy to Production
uses: easingthemes/ssh-deploy@main
with:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
ARGS: "-avz --delete"
SOURCE: "dist/"
REMOTE_HOST: ${{ secrets.PROD_HOST }}
REMOTE_USER: ${{ secrets.PROD_USER }}
TARGET: ${{ secrets.PROD_TARGET_DIR }}
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# 配置环境变量和密钥
在GitHub仓库的Settings -> Secrets and variables -> Actions中添加以下密钥:
SSH_PRIVATE_KEY: SSH私钥DEV_HOST: 开发服务器主机DEV_USER: 开发服务器用户名DEV_TARGET_DIR: 开发服务器部署目录PROD_HOST: 生产服务器主机PROD_USER: 生产服务器用户名PROD_TARGET_DIR: 生产服务器部署目录
# Jenkins配置实例
在比特大陆项目中,我们使用Jenkins构建了一套完整的CI/CD流程。以下是Jenkinsfile示例:
pipeline {
agent {
docker {
image 'node:16-alpine'
}
}
stages {
stage('Install') {
steps {
sh 'npm ci'
}
}
stage('Lint & Test') {
parallel {
stage('Lint') {
steps {
sh 'npm run lint'
}
}
stage('Test') {
steps {
sh 'npm run test'
}
}
}
}
stage('Build') {
steps {
sh 'npm run build'
}
}
stage('Deploy Dev') {
when {
branch 'develop'
}
steps {
sshagent(['jenkins-ssh-key']) {
sh '''
rsync -avz --delete dist/ user@dev-server:/path/to/deployment/
'''
}
}
}
stage('Deploy Production') {
when {
branch 'main'
}
steps {
input message: '确认部署到生产环境?'
sshagent(['jenkins-ssh-key']) {
sh '''
rsync -avz --delete dist/ user@prod-server:/path/to/deployment/
'''
}
}
}
}
post {
always {
cleanWs()
}
success {
slackSend channel: '#deployments',
color: 'good',
message: "部署成功: ${env.JOB_NAME} ${env.BUILD_NUMBER}"
}
failure {
slackSend channel: '#deployments',
color: 'danger',
message: "部署失败: ${env.JOB_NAME} ${env.BUILD_NUMBER}"
}
}
}
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# 最佳实践
# 1. 环境分离
为不同环境(开发、测试、预生产、生产)配置独立的部署流程:
# 环境变量配置
.env.development
.env.staging
.env.production
1
2
3
4
2
3
4
# 2. 回滚策略
确保能够快速回滚到上一个稳定版本:
# GitHub Actions中的回滚作业
rollback:
needs: deploy-prod
if: failure()
runs-on: ubuntu-latest
steps:
# 部署上一个稳定版本
- name: Rollback to previous version
run: |
# 回滚脚本
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 3. 版本控制
每次部署添加版本标签:
# 部署前自动打tag
git tag v$(cat package.json | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[",]//g' | tr -d '[:space:]')-$(date +%Y%m%d%H%M%S)
git push --tags
1
2
3
2
3
# 4. 缓存优化
缓存依赖以加速构建:
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
1
2
3
4
5
6
7
2
3
4
5
6
7
# 5. 并行任务
将独立任务并行执行以减少总构建时间:
jobs:
lint:
# 代码检查任务
test:
# 单元测试任务
build:
needs: [lint, test]
# 构建任务
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 真实案例分析
在字节跳动飞书人事项目中,我们的CI/CD流程包括:
- 代码提交:提交代码到feature分支
- 自动检查:触发ESLint代码检查和Jest单元测试
- PR审核:通过代码审核后合并到develop分支
- 自动构建:合并后自动触发构建
- 测试环境部署:自动部署到测试环境
- 功能测试:QA进行功能测试
- 预发布:将验证过的代码合并到staging分支并部署到预发环境
- 生产部署:经过预发环境验证后,合并到main分支并部署到生产环境
这套流程每天处理超过20次部署,大大提高了团队的开发效率。
# 监控与通知
将部署状态通知集成到工作流中:
- name: Slack Notification
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
fields: repo,message,commit,author,action,eventName,ref,workflow
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
if: always()
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 进阶主题
- 蓝绿部署:准备两个相同的生产环境,交替部署
- 金丝雀发布:逐步将流量引导到新版本
- A/B测试集成:在部署流程中集成A/B测试
- 性能监控:自动监控部署后的应用性能
# 总结
构建一套完善的前端CI/CD系统不仅能提高开发效率,还能提升代码质量和用户体验。根据项目规模和团队需求选择合适的工具和策略,循序渐进地实现自动化部署。
在我的职业生涯中,从最初的手动部署到现在的全自动CI/CD流程,我深刻体会到工程化对前端开发的重要性。希望本文能为您实现前端自动化部署提供有价值的参考。