CI/CD 流水线配置
概述
Jenkins、GitLab CI、GitHub Actions 等 CI/CD 工具配置技能。
GitHub Actions
基础工作流
.github/workflows/ci.yml
name: CI
on: push: branches: [main, develop] pull_request: branches: [main]
jobs: build: runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build
run: npm run build
矩阵构建
jobs: test: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] node-version: [16, 18, 20]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
Docker 构建与推送
jobs: docker: runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: user/app:${{ github.sha }}
部署到 Kubernetes
jobs: deploy: runs-on: ubuntu-latest needs: build
steps:
- uses: actions/checkout@v4
- name: Configure kubectl
uses: azure/k8s-set-context@v3
with:
kubeconfig: ${{ secrets.KUBE_CONFIG }}
- name: Deploy
run: |
kubectl set image deployment/app app=user/app:${{ github.sha }}
kubectl rollout status deployment/app
GitLab CI
基础配置
.gitlab-ci.yml
stages:
- build
- test
- deploy
variables: DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
build: 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
test: stage: test image: node:18 script: - npm ci - npm test coverage: '/Coverage: \d+.\d+%/'
deploy: stage: deploy image: bitnami/kubectl:latest script: - kubectl set image deployment/app app=$DOCKER_IMAGE only: - main environment: name: production url: https://app.example.com
多环境部署
.deploy_template: &deploy_template stage: deploy image: bitnami/kubectl:latest script: - kubectl config use-context $KUBE_CONTEXT - kubectl set image deployment/app app=$DOCKER_IMAGE
deploy_staging: <<: *deploy_template variables: KUBE_CONTEXT: staging environment: name: staging only: - develop
deploy_production: <<: *deploy_template variables: KUBE_CONTEXT: production environment: name: production only: - main when: manual
Jenkins
Jenkinsfile(声明式)
// Jenkinsfile pipeline { agent any
environment {
DOCKER_IMAGE = "user/app:${BUILD_NUMBER}"
DOCKER_CREDENTIALS = credentials('docker-hub')
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build') {
steps {
sh 'npm ci'
sh 'npm run build'
}
}
stage('Test') {
steps {
sh 'npm test'
}
post {
always {
junit 'test-results/*.xml'
}
}
}
stage('Docker Build') {
steps {
sh "docker build -t ${DOCKER_IMAGE} ."
}
}
stage('Docker Push') {
steps {
sh "echo ${DOCKER_CREDENTIALS_PSW} | docker login -u ${DOCKER_CREDENTIALS_USR} --password-stdin"
sh "docker push ${DOCKER_IMAGE}"
}
}
stage('Deploy') {
when {
branch 'main'
}
steps {
sh "kubectl set image deployment/app app=${DOCKER_IMAGE}"
}
}
}
post {
always {
cleanWs()
}
success {
slackSend channel: '#deployments', message: "Build ${BUILD_NUMBER} succeeded"
}
failure {
slackSend channel: '#deployments', message: "Build ${BUILD_NUMBER} failed"
}
}
}
Jenkinsfile(脚本式)
node { stage('Checkout') { checkout scm }
stage('Build') {
sh 'npm ci'
sh 'npm run build'
}
stage('Test') {
try {
sh 'npm test'
} finally {
junit 'test-results/*.xml'
}
}
if (env.BRANCH_NAME == 'main') {
stage('Deploy') {
sh 'kubectl apply -f k8s/'
}
}
}
通用模式
语义化版本发布
GitHub Actions
name: Release
on: push: tags: - 'v*'
jobs: release: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Get version
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Build
run: npm run build
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: dist/*
generate_release_notes: true
缓存依赖
GitHub Actions
- name: Cache node modules uses: actions/cache@v3 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-node-
GitLab CI
cache: key: ${CI_COMMIT_REF_SLUG} paths: - node_modules/
并行测试
GitHub Actions
jobs: test: runs-on: ubuntu-latest strategy: matrix: shard: [1, 2, 3, 4] steps: - uses: actions/checkout@v4 - run: npm ci - run: npm test -- --shard=${{ matrix.shard }}/4
条件执行
GitHub Actions
jobs: deploy: if: github.ref == 'refs/heads/main' && github.event_name == 'push' runs-on: ubuntu-latest steps: - run: echo "Deploying..."
GitLab CI
deploy: rules: - if: $CI_COMMIT_BRANCH == "main" when: manual - if: $CI_COMMIT_TAG when: always
常见场景
场景 1:PR 检查
name: PR Check
on: pull_request: types: [opened, synchronize, reopened]
jobs: 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 test
场景 2:定时任务
name: Scheduled Job
on: schedule: - cron: '0 2 * * *' # 每天凌晨2点
jobs: cleanup: runs-on: ubuntu-latest steps: - run: echo "Running cleanup..."
场景 3:手动触发
name: Manual Deploy
on: workflow_dispatch: inputs: environment: description: 'Environment to deploy' required: true default: 'staging' type: choice options: - staging - production
jobs: deploy: runs-on: ubuntu-latest steps: - run: echo "Deploying to ${{ inputs.environment }}"
故障排查
问题 排查方法
构建失败 查看日志、本地复现
权限问题 检查 secrets、token
缓存失效 检查 cache key
超时 增加 timeout、优化步骤