乐闻世界logo
搜索文章和话题

YAML 在 CI/CD 流水线中如何使用?有哪些常见的 CI/CD YAML 配置模式?

2月21日 14:20

YAML 在 CI/CD(持续集成/持续部署)流水线中被广泛使用,特别是在 GitHub Actions、GitLab CI、CircleCI 等平台上。理解 YAML 在 CI/CD 中的应用对于 DevOps 工程师至关重要。

YAML 在 CI/CD 中的作用

1. 定义流水线配置

YAML 文件定义了 CI/CD 流水线的所有步骤、触发条件和环境配置。

2. 声明式配置

使用 YAML 可以以声明式的方式描述整个构建和部署过程。

3. 版本控制

YAML 配置文件可以像代码一样进行版本控制和审查。

常见 CI/CD 平台的 YAML 配置

1. GitHub Actions

GitHub Actions 使用 .github/workflows/ 目录下的 YAML 文件定义工作流。

yaml
# .github/workflows/ci.yml name: CI Pipeline on: push: branches: [main, develop] pull_request: branches: [main] schedule: - cron: '0 0 * * *' # 每天午夜运行 env: NODE_VERSION: '18.x' DOCKER_REGISTRY: ghcr.io jobs: test: name: Run Tests runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: 'npm' - name: Install dependencies run: npm ci - name: Run linter run: npm run lint - name: Run tests run: npm test - name: Upload coverage uses: codecov/codecov-action@v3 with: files: ./coverage/lcov.info build: name: Build Docker Image runs-on: ubuntu-latest needs: test outputs: image-tag: ${{ steps.meta.outputs.tags }} steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Log in to Container Registry uses: docker/login-action@v3 with: registry: ${{ env.DOCKER_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ env.DOCKER_REGISTRY }}/${{ github.repository }} tags: | type=ref,event=branch type=sha,prefix= - name: Build and push uses: docker/build-push-action@v5 with: context: . push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max deploy: name: Deploy to Production runs-on: ubuntu-latest needs: build if: github.ref == 'refs/heads/main' environment: production steps: - name: Checkout code uses: actions/checkout@v4 - name: Deploy to Kubernetes uses: azure/k8s-deploy@v4 with: manifests: | k8s/deployment.yaml k8s/service.yaml images: | ${{ needs.build.outputs.image-tag }} kubectl-version: 'latest'

2. GitLab CI

GitLab CI 使用项目根目录下的 .gitlab-ci.yml 文件。

yaml
# .gitlab-ci.yml stages: - test - build - deploy variables: NODE_VERSION: "18" DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA DOCKER_TLS_CERTDIR: "/certs" cache: key: ${CI_COMMIT_REF_SLUG} paths: - node_modules/ before_script: - npm ci test: stage: test image: node:${NODE_VERSION} script: - npm run lint - npm test coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/' artifacts: reports: coverage_report: coverage_format: cobertura path: coverage/cobertura-coverage.xml paths: - coverage/ expire_in: 1 week build: stage: build image: docker:24 services: - docker:24-dind variables: DOCKER_DRIVER: overlay2 before_script: - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY script: - docker build -t $DOCKER_IMAGE . - docker push $DOCKER_IMAGE only: - main - develop deploy:staging: stage: deploy image: bitnami/kubectl:latest script: - kubectl config use-context $KUBE_CONTEXT_STAGING - kubectl set image deployment/app app=$DOCKER_IMAGE -n staging - kubectl rollout status deployment/app -n staging environment: name: staging url: https://staging.example.com only: - develop deploy:production: stage: deploy image: bitnami/kubectl:latest script: - kubectl config use-context $KUBE_CONTEXT_PRODUCTION - kubectl set image deployment/app app=$DOCKER_IMAGE -n production - kubectl rollout status deployment/app -n production environment: name: production url: https://example.com when: manual only: - main

3. CircleCI

CircleCI 使用项目根目录下的 .circleci/config.yml 文件。

yaml
# .circleci/config.yml version: 2.1 orbs: node: circleci/node@5.1.0 docker: circleci/docker@2.4.0 executors: node-executor: docker: - image: cimg/node:18.19 working_directory: ~/project jobs: test: executor: node-executor steps: - checkout - node/install-packages - run: name: Run linter command: npm run lint - run: name: Run tests command: npm test - run: name: Generate coverage report command: npm run test:coverage - store_test_results: path: test-results - store_artifacts: path: coverage build: executor: docker/docker steps: - checkout - setup_remote_docker - docker/check - docker/build: image: myapp tag: $CIRCLE_SHA1 - docker/push: image: myapp tag: $CIRCLE_SHA1 deploy: executor: node-executor steps: - checkout - run: name: Deploy to production command: | kubectl set image deployment/app \ app=myapp:$CIRCLE_SHA1 \ -n production workflows: version: 2 test-build-deploy: jobs: - test - build: requires: - test filters: branches: only: - main - develop - deploy: requires: - build filters: branches: only: main

YAML 在 CI/CD 中的高级特性

1. 条件执行

yaml
# GitHub Actions 条件执行 deploy: runs-on: ubuntu-latest if: github.event_name == 'push' && github.ref == 'refs/heads/main' steps: - name: Deploy run: echo "Deploying to production"

2. 矩阵构建

yaml
# GitHub Actions 矩阵构建 test: runs-on: ubuntu-latest strategy: matrix: node-version: [16.x, 18.x, 20.x] os: [ubuntu-latest, windows-latest, macos-latest] steps: - uses: actions/checkout@v4 - name: Setup Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - run: npm test

3. 缓存依赖

yaml
# 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-

4. 并行执行

yaml
# GitLab CI 并行执行 test: parallel: 4 script: - npm test -- --shard $CI_NODE_INDEX/$CI_NODE_TOTAL

5. 环境变量和密钥

yaml
# GitHub Actions 环境变量 env: DATABASE_URL: ${{ secrets.DATABASE_URL }} API_KEY: ${{ secrets.API_KEY }} steps: - name: Deploy env: ENVIRONMENT: production run: | echo $DATABASE_URL echo $API_KEY

6. 工作流复用

yaml
# 可复用的工作流 # .github/workflows/reusable-deploy.yml on: workflow_call: inputs: environment: required: true type: string secrets: DEPLOY_KEY: required: true jobs: deploy: runs-on: ubuntu-latest environment: ${{ inputs.environment }} steps: - name: Deploy run: | echo "Deploying to ${{ inputs.environment }}" echo ${{ secrets.DEPLOY_KEY }}
yaml
# 调用可复用工作流 # .github/workflows/ci.yml jobs: deploy-staging: uses: ./.github/workflows/reusable-deploy.yml with: environment: staging secrets: DEPLOY_KEY: ${{ secrets.STAGING_DEPLOY_KEY }} deploy-production: uses: ./.github/workflows/reusable-deploy.yml with: environment: production secrets: DEPLOY_KEY: ${{ secrets.PRODUCTION_DEPLOY_KEY }}

最佳实践

1. 模块化配置

yaml
# 使用 YAML 锚点和别名复用配置 .defaults: &defaults runs-on: ubuntu-latest timeout-minutes: 30 job1: <<: *defaults steps: - run: echo "Job 1" job2: <<: *defaults steps: - run: echo "Job 2"

2. 使用环境变量

yaml
env: NODE_ENV: production LOG_LEVEL: info jobs: build: env: BUILD_ENV: ${{ github.ref }} steps: - run: echo $NODE_ENV

3. 错误处理

yaml
steps: - name: Run tests id: test continue-on-error: true run: npm test - name: Upload test results if: always() && steps.test.outcome == 'failure' uses: actions/upload-artifact@v3 with: name: test-results path: test-results/

4. 资源优化

yaml
# 使用并发限制 concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true # 使用超时 jobs: test: timeout-minutes: 30 steps: - run: npm test

常见问题和解决方案

1. YAML 语法错误

yaml
# ❌ 错误:缩进不一致 jobs: test: runs-on: ubuntu-latest steps: - run: echo "test" # ✅ 正确:一致的缩进 jobs: test: runs-on: ubuntu-latest steps: - run: echo "test"

2. 环境变量未定义

yaml
# 使用默认值 env: DATABASE_URL: ${{ secrets.DATABASE_URL || 'sqlite://:memory:' }}

3. 依赖缓存失效

yaml
# 使用版本化的缓存键 - uses: actions/cache@v3 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('.nvmrc') }}

工具和资源

  1. GitHub Actions Linter: https://actionlint.github.io/
  2. GitLab CI Linter: 内置在 GitLab UI 中
  3. CircleCI Config Validator: https://circleci.com/docs/2.0/configuration-reference/
  4. CI/CD YAML 编辑器插件: VS Code 扩展

掌握 YAML 在 CI/CD 中的应用可以显著提高开发效率和部署质量。

标签:YAML