前端CI/CD流水线搭建:从代码提交到自动部署
大家好,我是蔓蔓。在大厂工作时,我负责搭建了团队的CI/CD流水线,将部署时间从原来的30分钟缩短到了5分钟以内。今天我来和大家分享如何从零开始搭建一套完整的前端CI/CD流水线。
CI/CD概述
什么是CI/CD
- CI(持续集成):频繁地将代码集成到主分支,并进行自动化测试
- CD(持续交付/部署):自动化地将代码部署到生产环境
为什么需要CI/CD
- 减少人工操作:自动化构建、测试、部署流程
- 提高代码质量:每次提交都进行自动化测试
- 快速反馈:发现问题及时修复
- 降低部署风险:小步快跑,减少单次变更
流水线架构
整体流程
代码提交 → 代码审查 → 自动化测试 → 构建 → 部署 → 监控关键组件
- 版本控制:Git(GitHub/GitLab/GitHub)
- CI工具:GitHub Actions、GitLab CI、Jenkins
- 测试框架:Jest、Cypress、Playwright
- 构建工具:Webpack、Vite、Rollup
- 部署目标:Vercel、Netlify、云服务器、Docker
环境准备
安装必要工具
# 安装 Node.js curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - sudo apt-get install -y nodejs # 安装 npm 依赖 npm install # 安装 Docker(可选) sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io项目配置
{ "scripts": { "start": "vite", "build": "vite build", "test": "jest", "test:e2e": "cypress run", "lint": "eslint .", "preview": "vite preview" } }GitHub Actions配置
基础配置
name: CI/CD Pipeline on: push: branches: [main] pull_request: branches: [main] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '18' cache: 'npm' - name: Install dependencies run: npm ci - name: Lint run: npm run lint - name: Test run: npm test - name: Build run: npm run build - name: Deploy uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./dist多环境部署
jobs: deploy: runs-on: ubuntu-latest environment: name: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }} steps: - uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '18' - name: Install dependencies run: npm ci - name: Build run: npm run build env: NODE_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'development' }} - name: Deploy to Staging if: github.ref != 'refs/heads/main' run: npm run deploy:staging - name: Deploy to Production if: github.ref == 'refs/heads/main' run: npm run deploy:production测试集成
单元测试
// sum.test.js test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); });E2E测试
// cypress/integration/app.spec.js describe('App', () => { it('should display the welcome message', () => { cy.visit('/'); cy.contains('Welcome'); }); it('should login successfully', () => { cy.visit('/login'); cy.get('input[name="email"]').type('test@example.com'); cy.get('input[name="password"]').type('password'); cy.get('button[type="submit"]').click(); cy.contains('Dashboard'); }); });Docker部署
Dockerfile
# 开发环境 FROM node:18-alpine AS development WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . CMD ["npm", "start"] # 生产环境 FROM node:18-alpine AS production WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . RUN npm run build EXPOSE 3000 CMD ["npm", "run", "start:prod"]Docker Compose
version: '3.8' services: frontend: build: context: . target: production ports: - "3000:3000" environment: - NODE_ENV=production restart: unless-stopped部署策略
蓝绿部署
# 部署蓝环境 docker-compose up -d --build # 切换流量 nginx -s reload # 验证后停止绿环境 docker-compose -f docker-compose.green.yml down滚动更新
# 使用 Kubernetes 进行滚动更新 kubectl set image deployment/frontend frontend=myapp:v2 # 查看更新状态 kubectl rollout status deployment/frontend # 回滚到上一版本 kubectl rollout undo deployment/frontend监控告警
日志收集
// logger.js class Logger { constructor() { this.logEndpoint = process.env.LOG_ENDPOINT; } async log(message, level = 'info') { const payload = { timestamp: new Date().toISOString(), level, message, service: 'frontend' }; await fetch(this.logEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); } error(message, error) { this.log({ message, stack: error?.stack }, 'error'); } } export const logger = new Logger();性能监控
// 性能监控 const observer = new PerformanceObserver((entries) => { entries.forEach((entry) => { console.log(`${entry.name}: ${entry.duration}ms`); // 上报性能数据 fetch('/api/metrics', { method: 'POST', body: JSON.stringify({ name: entry.name, duration: entry.duration, timestamp: Date.now() }) }); }); }); observer.observe({ entryTypes: ['measure', 'navigation'] });安全性
密钥管理
# GitHub Secrets secrets: DATABASE_URL: ${{ secrets.DATABASE_URL }} API_KEY: ${{ secrets.API_KEY }} NODE_ENV: production安全扫描
- name: Security Scan uses: snyk/actions/node@master env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: args: monitor总结
一个完整的CI/CD流水线应该包含以下环节:
- 代码审查:确保代码质量
- 自动化测试:单元测试、集成测试、E2E测试
- 构建:生成生产环境代码
- 部署:自动化部署到目标环境
- 监控:实时监控应用状态
技术应当有温度,一个稳定可靠的CI/CD流水线,能够让开发者更加专注于创造价值,而不是重复的操作。
你在CI/CD方面有什么经验?欢迎在评论区交流~