GitHub Actions 完整DevOps流程 #

本节通过一个完整的DevOps示例,展示从代码到生产的全流程自动化。

DevOps概述 #

DevOps流程 #

text
代码提交 → CI检查 → 构建 → 测试 → 部署Staging → 验证 → 部署Production → 监控

核心原则 #

  • 自动化一切
  • 持续集成
  • 持续部署
  • 快速反馈
  • 安全第一

项目结构 #

text
project/
├── .github/
│   ├── workflows/
│   │   ├── ci.yml
│   │   ├── cd.yml
│   │   ├── security.yml
│   │   └── release.yml
│   └── actions/
│       └── setup/
│           └── action.yml
├── src/
├── tests/
├── kubernetes/
│   ├── deployment.yaml
│   └── service.yaml
├── Dockerfile
└── package.json

CI工作流 #

yaml
# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

env:
  CI: true
  NODE_VERSION: '20'

jobs:
  lint:
    name: Lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/setup
      - run: npm run lint
      - run: npm run format:check

  type-check:
    name: Type Check
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/setup
      - run: npm run type-check

  test:
    name: Test
    needs: [lint, type-check]
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node: [18, 20]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
          cache: 'npm'
      - run: npm ci
      - run: npm run test:coverage
      - if: matrix.node == '20'
        uses: actions/upload-artifact@v4
        with:
          name: coverage
          path: coverage/

  build:
    name: Build
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/setup
      - run: npm run build
      - uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/

CD工作流 #

yaml
# .github/workflows/cd.yml
name: CD

on:
  push:
    branches: [main]
    tags: ['v*']
  workflow_dispatch:
    inputs:
      environment:
        type: choice
        options: [staging, production]
        default: staging

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  prepare:
    runs-on: ubuntu-latest
    outputs:
      environment: ${{ steps.set.outputs.environment }}
      version: ${{ steps.set.outputs.version }}
    steps:
      - id: set
        run: |
          if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
            echo "environment=${{ github.event.inputs.environment }}" >> $GITHUB_OUTPUT
          elif [ "${{ github.ref_type }}" == "tag" ]; then
            echo "environment=production" >> $GITHUB_OUTPUT
          else
            echo "environment=staging" >> $GITHUB_OUTPUT
          fi
          echo "version=${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT

  build-image:
    needs: prepare
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    outputs:
      image: ${{ steps.build.outputs.image }}
    steps:
      - uses: actions/checkout@v4

      - uses: docker/setup-buildx-action@v3
      - uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - id: build
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.version }}
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max

  deploy:
    needs: [prepare, build-image]
    runs-on: ubuntu-latest
    environment: ${{ needs.prepare.outputs.environment }}
    steps:
      - uses: actions/checkout@v4

      - uses: azure/k8s-set-context@v3
        with:
          kubeconfig: ${{ secrets.KUBE_CONFIG }}

      - uses: azure/k8s-deploy@v4
        with:
          namespace: ${{ needs.prepare.outputs.environment }}
          manifests: kubernetes/
          images: ${{ needs.build-image.outputs.image }}

  verify:
    needs: [prepare, deploy]
    runs-on: ubuntu-latest
    steps:
      - name: Health check
        run: |
          url="https://${{ needs.prepare.outputs.environment }}.example.com/health"
          for i in {1..30}; do
            if curl -sf "$url"; then
              echo "Health check passed"
              exit 0
            fi
            sleep 10
          done
          echo "Health check failed"
          exit 1

  notify:
    needs: [prepare, build-image, deploy, verify]
    if: always()
    runs-on: ubuntu-latest
    steps:
      - uses: slackapi/slack-github-action@v1
        with:
          channel-id: 'deployments'
          slack-message: |
            ${{ job.status == 'success' && ':rocket:' || ':x:' }} Deployment ${{ job.status }}
            Environment: ${{ needs.prepare.outputs.environment }}
            Version: ${{ needs.prepare.outputs.version }}
        env:
          SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

安全扫描工作流 #

yaml
# .github/workflows/security.yml
name: Security

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 0 * * *'

jobs:
  codeql:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    steps:
      - uses: actions/checkout@v4
      - uses: github/codeql-action/init@v2
        with:
          languages: javascript
      - uses: github/codeql-action/analyze@v2

  trivy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          severity: 'CRITICAL,HIGH'

  dependency-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/setup
      - run: npm audit --audit-level=high
      - uses: snyk/actions/node@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

  secret-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: trufflesecurity/trufflehog@main
        with:
          path: ./
          base: ${{ github.event.repository.default_branch }}

发布工作流 #

yaml
# .github/workflows/release.yml
name: Release

on:
  push:
    tags: ['v*']

permissions:
  contents: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: ./.github/actions/setup

      - name: Build
        run: npm run build

      - name: Create Release
        uses: softprops/action-gh-release@v1
        with:
          files: dist/*
          generate_release_notes: true

      - name: Publish to NPM
        run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Composite Action #

yaml
# .github/actions/setup/action.yml
name: 'Setup Node.js'
description: 通过的DevOps示例,学习如何构建从代码到生产的自动化流程。

runs:
  using: 'composite'
  steps:
    - uses: actions/setup-node@v4
      with:
        node-version: '20'
        cache: 'npm'

    - name: Install dependencies
      shell: bash
      run: npm ci

Kubernetes配置 #

yaml
# kubernetes/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: IMAGE_PLACEHOLDER
          ports:
            - containerPort: 3000
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi
          livenessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 10
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /ready
              port: 3000
            initialDelaySeconds: 5
            periodSeconds: 5

监控和告警 #

Prometheus指标 #

yaml
- name: Expose metrics
  uses: prometheus/client_golang

告警规则 #

yaml
- name: Alert on high error rate
  if: failure()
  uses: slackapi/slack-github-action@v1

最佳实践 #

1. 使用环境保护 #

yaml
environment: production

2. 使用OIDC认证 #

yaml
permissions:
  id-token: write

3. 使用并发控制 #

yaml
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

4. 使用最小权限 #

yaml
permissions:
  contents: read

5. 添加健康检查 #

yaml
- name: Health check
  run: curl -sf https://example.com/health

下一步学习 #

小结 #

  • DevOps实现全流程自动化
  • 使用多个工作流分离关注点
  • 使用Composite Action复用配置
  • 使用环境保护生产环境
  • 添加安全扫描
  • 设置监控和告警
  • 使用Kubernetes进行容器编排
最后更新:2026-03-28