CI/CD流水线搭建实战
一、CI/CD概述
CI/CD是现代软件开发的核心实践,通过自动化流程实现持续集成、持续交付和持续部署,大幅提升开发效率和软件质量。
核心概念:
- CI(Continuous Integration)持续集成:频繁将代码合并到主干,自动构建和测试
- CD(Continuous Delivery)持续交付:自动化部署到预发布环境,手动发布到生产
- CD(Continuous Deployment)持续部署:全自动部署到生产环境
CI/CD流水线价值:
- 快速反馈:代码提交立即验证,问题早发现早解决
- 降低风险:频繁小批量发布,减少变更风险
- 提高效率:自动化重复工作,释放人力
- 质量保障:自动化测试,确保代码质量
- 标准化:统一构建部署流程,消除环境差异
二、主流CI/CD工具对比
| 工具 | 类型 | 优势 | 适用场景 |
|---|---|---|---|
| Jenkins | 自托管 | 高度可定制,插件丰富 | 复杂企业级流水线 |
| GitLab CI | 集成式 | GitLab原生集成,配置简单 | GitLab代码托管用户 |
| GitHub Actions | SaaS | GitHub原生,市场丰富 | GitHub开源项目 |
| Drone | 云原生 | Docker原生,轻量高效 | Kubernetes环境 |
| CircleCI | SaaS | 速度快,配置简单 | 中小团队 |
工具选型建议:
- 中小团队:GitHub Actions / GitLab CI
- 企业级:Jenkins / GitLab CI
- 云原生:Drone / Tekton
- 开源项目:GitHub Actions
三、GitLab CI完整实战
1. 基础配置(.gitlab-ci.yml)
# 定义执行阶段
stages:
- build # 构建
- test # 测试
- deploy # 部署
# 全局变量
variables:
DOCKER_IMAGE: $CI_REGISTRY/myapp:latest
NODE_ENV: production
# 缓存配置
cache:
paths:
- node_modules/
- .npm/2. 构建阶段
build_job:
stage: build
image: node:18-alpine
script:
- npm config set registry https://registry.npmmirror.com
- npm ci
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 week
only:
- main
- develop
tags:
- docker3. 测试阶段
lint_job:
stage: test
image: node:18-alpine
script:
- npm ci
- npm run lint
unit_test_job:
stage: test
image: node:18-alpine
script:
- npm ci
- npm run test:unit
coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
e2e_test_job:
stage: test
image: cypress/browsers:node18-chrome109
script:
- npm ci
- npm run test:e2e
when: manual # 手动触发4. Docker镜像构建
docker_build_job:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $DOCKER_IMAGE .
- docker push $DOCKER_IMAGE
only:
- main5. 部署阶段
deploy_staging:
stage: deploy
image: alpine:latest
script:
- apk add --no-cache openssh-client
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- ssh -o StrictHostKeyChecking=no user@staging-server "docker pull $DOCKER_IMAGE && docker-compose up -d"
environment:
name: staging
url: https://staging.myapp.com
only:
- develop
deploy_production:
stage: deploy
script:
- echo "部署到生产环境"
environment:
name: production
url: https://myapp.com
when: manual # 生产环境手动确认
only:
- main四、GitHub Actions实战
1. 基础工作流配置
# .github/workflows/ci.yml
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-test:
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 run test
- name: Build
run: npm run build2. Docker构建与推送
build-and-push-image:
runs-on: ubuntu-latest
needs: build-and-test
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Log in to Container registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}3. 自动部署到服务器
deploy:
runs-on: ubuntu-latest
needs: build-and-push-image
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy to server
uses: appleboy/ssh-action@v0.1.10
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /opt/myapp
docker-compose pull
docker-compose up -d
docker image prune -f五、Jenkins Pipeline实战
1. Jenkinsfile(声明式流水线)
pipeline {
agent any
environment {
DOCKER_CREDENTIALS = credentials('docker-registry')
SSH_CREDENTIALS = credentials('ssh-deploy')
}
options {
buildDiscarder(logRotator(numToKeepStr: '10'))
timeout(time: 30, unit: 'MINUTES')
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build') {
agent {
docker {
image 'node:18-alpine'
reuseNode true
}
}
steps {
sh 'npm ci'
sh 'npm run build'
}
}
stage('Test') {
parallel {
stage('Unit Test') {
steps {
sh 'npm run test:unit'
}
}
stage('Lint') {
steps {
sh 'npm run lint'
}
}
}
}
stage('Docker Build') {
steps {
script {
docker.withRegistry('https://registry.example.com', 'docker-registry') {
def image = docker.build("myapp:${BUILD_NUMBER}")
image.push()
image.push('latest')
}
}
}
}
stage('Deploy Staging') {
when {
branch 'develop'
}
steps {
sshagent(['ssh-deploy']) {
sh '''
ssh -o StrictHostKeyChecking=no user@staging "
cd /opt/myapp &&
docker-compose pull &&
docker-compose up -d
"
'''
}
}
}
stage('Deploy Production') {
when {
branch 'main'
}
input {
message 'Deploy to production?'
ok 'Yes, deploy'
}
steps {
echo 'Deploying to production...'
}
}
}
post {
success {
echo 'Pipeline succeeded!'
}
failure {
echo 'Pipeline failed!'
// 发送钉钉/企业微信通知
}
always {
cleanWs()
}
}
}六、流水线最佳实践
1. 流水线设计原则
代码提交 → 构建 → 测试 → 镜像 → 预发布 → 生产
↓ ↓ ↓ ↓ ↓ ↓
快速反馈 一致 质量 一次 验证 人工
环境 门禁 构建 功能 确认2. 关键优化点
加速构建:
# 1. 依赖缓存
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
# 2. 并行执行
parallel:
matrix:
- NODE_VERSION: ['16', '18', '20']
# 3. 按需执行
rules:
- changes:
- src/**/*
- package.json质量门禁:
# 代码质量扫描
sonar-scanner \
-Dsonar.projectKey=myapp \
-Dsonar.qualitygate.wait=true
# 安全漏洞扫描
trivy image $DOCKER_IMAGE
# 依赖漏洞检查
npm audit --audit-level high3. 通知与告警
钉钉通知示例:
notify:
stage: .post
script:
- |
curl "$DINGTALK_WEBHOOK" \
-H 'Content-Type: application/json' \
-d "{
\"msgtype\": \"text\",
\"text\": {
\"content\": \"构建${CI_JOB_STATUS}: ${CI_PROJECT_NAME}\n分支: ${CI_COMMIT_BRANCH}\n日志: ${CI_JOB_URL}\"
}
}"
when: always七、常见问题与解决方案
1. 流水线太慢?
- ✅ 启用依赖缓存
- ✅ 并行执行任务
- ✅ 优化Docker镜像(多阶段构建)
- ✅ 使用更快的构建机器
2. 测试不稳定?
- ✅ 测试隔离,避免互相影响
- ✅ 增加重试机制
- ✅ 分离单元测试和E2E测试
- ✅ 优化测试用例
3. 部署失败?
- ✅ 蓝绿部署/滚动发布
- ✅ 自动化回滚机制
- ✅ 健康检查验证
- ✅ 灰度发布策略
4. 安全问题?
- ✅ 密钥使用CI变量,不硬编码
- ✅ 镜像安全扫描
- ✅ 最小权限原则
- ✅ 定期轮换凭证
总结
CI/CD实施路径:
- 基础搭建:选择工具,配置基础流水线
- 自动化测试:单元测试、集成测试、E2E测试
- 容器化:Docker标准化构建产物
- 环境分离:开发、测试、预发、生产
- 高级特性:蓝绿部署、灰度发布、自动回滚
- 监控告警:流水线可视化、失败告警
记住:CI/CD不是目的,提升交付效率和质量才是核心!