🔄 第09课:GitHub Actions

📚 核心概念

🎯 GitHub Actions:CI/CD即代码

GitHub Actions是GitHub原生的CI/CD平台,用YAML定义工作流,与代码仓库深度集成。它将持续集成从"配置Jenkins"变成了"写YAML文件",大幅降低了CI/CD门槛。

⚙️ GitHub Actions架构

  事件触发                 工作流                运行器
  ┌──────┐           ┌──────────┐          ┌──────────┐
  │ push │           │ Workflow │          │  Runner  │
  │ PR   │──触发────▶│  .yaml   │──调度───▶│ (VM/容器)│
  │定时   │           │          │          │          │
  │手动   │           │ Job1     │──▶ Step1 │ npm ci   │
  └──────┘           │ Job2     │──▶ Step2 │ npm test │
                    │ Job3     │──▶ Step3 │ docker   │
                    └──────────┘          └──────────┘
                         │
                    ┌────┴────┐
                    │ Actions │
                    │ Market  │
                    │ place   │
                    │ (复用)   │
                    └─────────┘

📐 核心概念

⌨️ 命令实操

⌨️ 实操命令

1. CI流水线配置 ✅

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

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

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

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20, 22]
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Lint
        run: npm run lint
      
      - name: Unit tests
        run: npm test -- --coverage
      
      - name: Upload coverage
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}

  build:
    needs: test
    runs-on: ubuntu-latest
    outputs:
      image-tag: ${{ steps.meta.outputs.tags }}
    steps:
      - uses: actions/checkout@v4
      
      - name: Login to Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      
      - name: Build and Push
        uses: docker/build-push-action@v5
        with:
          push: true
          tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}

2. CD部署流水线 ✅

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

on:
  workflow_run:
    workflows: ["CI Pipeline"]
    types: [completed]
    branches: [main]

jobs:
  deploy-staging:
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - uses: actions/checkout@v4
      
      - name: Deploy to Staging
        run: |
          kubectl set image deployment/app             app=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}             -n staging
          kubectl rollout status deployment/app -n staging --timeout=300s
      
      - name: Smoke Test
        run: |
          sleep 30
          curl -f https://staging.example.com/health || exit 1

  deploy-production:
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: Deploy to Production
        run: |
          kubectl set image deployment/app             app=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}             -n production

      - name: Canary Check
        run: |
          # 检查错误率是否上升
          ERROR_RATE=$(curl -s prometheus:9090/api/v1/query             | jq '.data.result[0].value[1]')
          if (( $(echo "$ERROR_RATE > 0.01" | bc -l) )); then
            echo "❌ Error rate too high, rolling back"
            kubectl rollout undo deployment/app -n production
            exit 1
          fi

3. 自定义Action ✅

Custom Action
# actions/deploy-slx/action.yml
name: 'Deploy SLX'
description: 'Deploy service to Kubernetes with canary'
inputs:
  environment:
    description: 'Target environment'
    required: true
  image-tag:
    description: 'Container image tag'
    required: true
  canary-weight:
    description: 'Canary traffic percentage'
    default: '10'
outputs:
  deploy-url:
    description: 'Deployed service URL'

runs:
  using: 'composite'
  steps:
    - name: Validate inputs
      shell: bash
      run: |
        [[ "${{ inputs.environment }}" =~ ^(staging|production)$ ]] || exit 1
        
    - name: Deploy
      shell: bash
      run: |
        echo "Deploying ${{ inputs.image-tag }} to ${{ inputs.environment }}"
        kubectl apply -f k8s/${{ inputs.environment }}/
        
    - name: Wait for rollout
      shell: bash
      run: |
        kubectl rollout status deployment/app           -n ${{ inputs.environment }} --timeout=300s

📐 架构图

📐 架构图:GitHub Actions完整流水线

  开发者            GitHub                Runners             部署
  ┌──────┐      ┌──────────┐         ┌──────────┐        ┌──────────┐
  │ git  │      │  Repo    │         │ Runner 1 │        │          │
  │ push │─────▶│ .github/ │──调度──▶│ Lint+Test│        │ Staging  │
  └──────┘      │ workflows│         └──────────┘        │  K8s     │
               └────┬─────┘         ┌──────────┐        │          │
                    │      ──调度──▶│ Runner 2 │──部署──▶│          │
                    │               │ Build    │        └──────────┘
                    │               └──────────┘
                    │               ┌──────────┐        ┌──────────┐
                    │      ──调度──▶│ Runner 3 │──部署──▶│ Prod K8s │
                    │               │ Deploy   │        │          │
                    │               └──────────┘        └──────────┘
                    │
                    │ 通知
                    ▼
              ┌──────────┐
              │ Slack/   │
              │ 钉钉     │
              └──────────┘

🔧 故障排查

🔧 故障排查

❌ 问题1:Actions工作流不触发

# 常见原因:
# 1. YAML语法错误 → 用actionlint检查
# 2. 分支过滤器不匹配
# 3. 使用了secrets但fork PR无权限
# 4. 工作流文件在错误的分支

# 调试方法:
# 1. 查看Actions标签页的错误信息
# 2. 启用debug日志
# A: 设置secrets: ACTIONS_STEP_DEBUG=true
#    A: 设置secrets: ACTIONS_RUNNER_DEBUG=true

# 3. 使用act本地运行
brew install act
act push  # 本地模拟push事件

📐 GitHub Actions核心概念

2. CD部署流水线 ✅

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

on:
  workflow_run:
    workflows: ["CI Pipeline"]
    types: [completed]
    branches: [main]

jobs:
  deploy-staging:
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to Staging
        run: |
          kubectl set image deployment/app \
            app=ghcr.io/myapp:${{ github.sha }} -n staging
          kubectl rollout status deployment/app -n staging
      - name: Smoke Test
        run: |
          sleep 30
          curl -f https://staging.example.com/health

  deploy-production:
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: Deploy to Production
        run: |
          kubectl set image deployment/app \
            app=ghcr.io/myapp:${{ github.sha }} -n production

3. 自定义Action ✅

Custom Action
# actions/deploy/action.yml
name: 'Deploy to K8s'
description: 'Deploy service with canary rollout'
inputs:
  environment:
    description: 'Target environment'
    required: true
  image-tag:
    description: 'Container image tag'
    required: true

runs:
  using: 'composite'
  steps:
    - name: Validate
      shell: bash
      run: |
        [[ "${{ inputs.environment }}" =~ ^(staging|production)$ ]] || exit 1
    - name: Deploy
      shell: bash
      run: |
        kubectl apply -f k8s/${{ inputs.environment }}/
        kubectl rollout status deployment/app \
          -n ${{ inputs.environment }} --timeout=300s

❌ 问题1:Actions工作流不触发

# 常见原因:
# 1. YAML语法错误 → 用actionlint检查
# 2. 分支过滤器不匹配
# 3. fork PR无secrets权限

# 调试方法:
# 1. 查看Actions标签页错误信息
# 2. 启用debug: 设置secrets ACTIONS_STEP_DEBUG=true
# 3. 使用act本地运行
brew install act && act push

🏆 成就解锁:CI/CD工程师!

掌握GitHub Actions工作流、自定义Action、CI/CD流水线设计——这是现代DevOps的核心技能。