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

How is YAML used in CI/CD pipelines? What are common CI/CD YAML configuration patterns?

2月21日 14:20

YAML is widely used in CI/CD (Continuous Integration/Continuous Deployment) pipelines, especially on platforms like GitHub Actions, GitLab CI, and CircleCI. Understanding YAML's application in CI/CD is crucial for DevOps engineers.

Role of YAML in CI/CD

1. Define Pipeline Configuration

YAML files define all steps, trigger conditions, and environment configurations of CI/CD pipelines.

2. Declarative Configuration

YAML allows describing the entire build and deployment process in a declarative manner.

3. Version Control

YAML configuration files can be version controlled and reviewed like code.

YAML Configurations for Common CI/CD Platforms

1. GitHub Actions

GitHub Actions uses YAML files in the .github/workflows/ directory to define workflows.

yaml
# .github/workflows/ci.yml name: CI Pipeline on: push: branches: [main, develop] pull_request: branches: [main] schedule: - cron: '0 0 * * *' # Run daily at midnight 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 uses the .gitlab-ci.yml file in the project root.

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 uses the .circleci/config.yml file in the project root.

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

Advanced YAML Features in CI/CD

1. Conditional Execution

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

2. Matrix Builds

yaml
# GitHub Actions matrix builds 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. Cache Dependencies

yaml
# GitHub Actions caching - 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. Parallel Execution

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

5. Environment Variables and Secrets

yaml
# GitHub Actions environment variables 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. Workflow Reuse

yaml
# Reusable workflow # .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
# Call reusable workflow # .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 }}

Best Practices

1. Modular Configuration

yaml
# Use YAML anchors and aliases to reuse configuration .defaults: &defaults runs-on: ubuntu-latest timeout-minutes: 30 job1: <<: *defaults steps: - run: echo "Job 1" job2: <<: *defaults steps: - run: echo "Job 2"

2. Use Environment Variables

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

3. Error Handling

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. Resource Optimization

yaml
# Use concurrency limits concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true # Use timeouts jobs: test: timeout-minutes: 30 steps: - run: npm test

Common Issues and Solutions

1. YAML Syntax Errors

yaml
# ❌ Error: Inconsistent indentation jobs: test: runs-on: ubuntu-latest steps: - run: echo "test" # ✅ Correct: Consistent indentation jobs: test: runs-on: ubuntu-latest steps: - run: echo "test"

2. Undefined Environment Variables

yaml
# Use default values env: DATABASE_URL: ${{ secrets.DATABASE_URL || 'sqlite://:memory:' }}

3. Dependency Cache Invalidation

yaml
# Use versioned cache keys - uses: actions/cache@v3 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('.nvmrc') }}

Tools and Resources

  1. GitHub Actions Linter: https://actionlint.github.io/
  2. GitLab CI Linter: Built into GitLab UI
  3. CircleCI Config Validator: https://circleci.com/docs/2.0/configuration-reference/
  4. CI/CD YAML Editor Plugins: VS Code extensions

Mastering YAML's application in CI/CD can significantly improve development efficiency and deployment quality.

标签:YAML