CI/CD 流水线搭建指南
两年前我们还是手动 FTP 上传代码,现在全自动 CI/CD。记录一下这个过程。
以前的痛
# 开发者电脑
npm run build
scp -r dist/* user@server:/var/www/html/
# 然后祈祷别出问题
问题:
- 每次部署 15 分钟
- 有人传错分支
- 没有回滚机制
- 出问题互相甩锅
现在的流程
代码提交 → 自动测试 → 自动构建 → 自动部署 → 通知
整个流程 5 分钟,人不用管。
GitHub Actions 配置
基础结构
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm test
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist
deploy:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: dist
- name: Deploy to server
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
source: "dist/*"
target: "/var/www/html"
环境变量管理
敏感信息不要写进代码,用 GitHub Secrets:
| Secret 名称 | 用途 |
|---|---|
| HOST | 服务器地址 |
| USERNAME | SSH 用户名 |
| SSH_KEY | 私钥 |
| DATABASE_URL | 数据库连接串 |
在 Settings → Secrets and variables → Actions 里配置。
分环境部署
开发环境
每次 PR 自动部署到测试服务器:
deploy-dev:
needs: build
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Deploy to dev
run: |
echo "Deploying PR #${{ github.event.number }} to dev server"
# 部署逻辑
生产环境
只有 main 分支才部署:
deploy-prod:
needs: build
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- name: Deploy to production
run: |
echo "Deploying to production"
部署确认
重要操作加人工确认:
deploy-prod:
environment:
name: production
url: https://example.com
在 GitHub 上创建 Environment,配置 Required reviewers。部署前需要审批。
回滚机制
rollback:
runs-on: ubuntu-latest
steps:
- name: Get previous release
id: prev
run: |
PREV=$(ls -t /var/www/releases | head -2 | tail -1)
echo "version=$PREV" >> $GITHUB_OUTPUT
- name: Rollback
run: |
ln -sfn /var/www/releases/${{ steps.prev.outputs.version }} /var/www/html/current
保留最近 5 个版本,随时可以回滚。
通知
部署结果发到钉钉/飞书:
notify:
runs-on: ubuntu-latest
needs: [deploy]
if: always()
steps:
- name: Notify
uses: actionsflow/action-dingtalk@v1
with:
webhook: ${{ secrets.DINGTALK_WEBHOOK }}
content: |
项目: ${{ github.repository }}
分支: ${{ github.ref }}
状态: ${{ job.status }}
提交者: ${{ github.actor }}
性能优化
| 优化项 | 效果 |
|---|---|
| npm cache | 节省 30s |
| 并行任务 | 节省 2min |
| 增量构建 | 节省 1min |
| 取消旧构建 | 节省资源 |
配置缓存:
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm # 启用缓存
常见问题
1. 构建超时
默认超时 6 小时,可以调整:
jobs:
build:
timeout-minutes: 30
2. 磁盘空间不足
Runner 只有 14GB,大项目可能不够:
- name: Free disk space
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
3. 权限问题
- name: Fix permissions
run: sudo chown -R $USER:$USER .
成本
GitHub Actions 免费额度:
- 公开仓库:无限
- 私有仓库:2000 分钟/月
我们团队每月用约 1500 分钟,免费额度够用。
总结
CI/CD 带来的好处:
- 部署时间从 15 分钟到 5 分钟
- 人力投入减少 80%
- 人为错误几乎为零
- 出问题可以快速回滚
投入产出比很高,每个团队都应该做。
不要追求完美,先跑起来再优化。我们从最简单的手动触发部署开始,逐步加自动化,花了一个月才搞完。