mcpField
G
github-actions-templates

github-actions-templates

github.com/ckorhonen云与 DevOps2244 次安装5 周前更新
代码仓库

关于 github-actions-templates

github-actions-templates 是面向应用开发团队的 GitHub Actions 工作流模式指南,涵盖测试、构建与部署。除常见模板外,还说明密钥、权限、矩阵构建、缓存和工作流故障的处理方式。

主要功能

  1. 01测试与部署工作流模式
  2. 02Docker 构建和推送模板
  3. 03Kubernetes 部署与矩阵构建
  4. 04密钥和权限处理建议
  5. 05缓存问题与故障排查

适用场景

  1. 01为项目配置持续集成与部署
  2. 02自动构建并推送 Docker 镜像
  3. 03部署应用到 Kubernetes
  4. 04排查工作流中的权限或缓存问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ckorhonen/claude-skills --skill github-actions-templates

安装后在 Claude Code 中输入/github-actions-templates确认已加载。

详细介绍

GitHub Actions 模板

用于测试、构建和部署应用程序的生产就绪型 GitHub Actions 工作流模式。

用途

为各种技术栈创建高效、安全的 GitHub Actions 工作流,以实现持续集成和部署。

使用场景

  • 自动化测试和部署
  • 构建 Docker 镜像并推送到镜像仓库
  • 部署到 Kubernetes 集群
  • 运行安全扫描
  • 为多个环境实现矩阵构建

常见工作流模式

模式 1:测试工作流
name: Test

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

jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [18.x, 20.x]

    steps:
      - uses: actions/checkout@v4

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.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
模式 2:构建并推送 Docker 镜像
name: Build and Push

on:
  push:
    branches: [main]
    tags: ["v*"]

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

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - uses: actions/checkout@v4

      - name: Log in to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}

      - 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
模式 3:部署到 Kubernetes
name: Deploy to Kubernetes

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-west-2

      - name: Update kubeconfig
        run: |
          aws eks update-kubeconfig --name production-cluster --region us-west-2

      - name: Deploy to Kubernetes
        run: |
          kubectl apply -f k8s/
          kubectl rollout status deployment/my-app -n production
          kubectl get services -n production

      - name: Verify deployment
        run: |
          kubectl get pods -n production
          kubectl describe deployment my-app -n production
模式 4:矩阵构建
name: Matrix Build

on: [push, pull_request]

jobs:
  build:
    runs-on: ${{ matrix.os }}

    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        python-version: ["3.9", "3.10", "3.11", "3.12"]

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt

      - name: Run tests
        run: pytest

工作流最佳实践

  1. 使用指定版本的操作(@v4,而不是 @latest)
  2. 缓存依赖项以加快构建速度
  3. 使用机密存储敏感数据
  4. 在 PR 上实施状态检查
  5. 使用矩阵构建进行多版本测试
  6. 设置适当的权限
  7. 对常见模式使用可复用工作流
  8. 为生产环境实施审批关卡
  9. 添加失败通知步骤
  10. 对敏感工作负载使用自托管运行器

可复用工作流

# .github/workflows/reusable-test.yml
name: Reusable Test Workflow

on:
  workflow_call:
    inputs:
      node-version:
        required: true
        type: string
    secrets:
      NPM_TOKEN:
        required: true

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ inputs.node-version }}
      - run: npm ci
      - run: npm test

使用可复用工作流:

jobs:
  call-test:
    uses: ./.github/workflows/reusable-test.yml
    with:
      node-version: "20.x"
    secrets:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

安全扫描

name: Security Scan

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

jobs:
  security:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: "fs"
          scan-ref: "."
          format: "sarif"
          output: "trivy-results.sarif"

      - name: Upload Trivy results to GitHub Security
        uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: "trivy-results.sarif"

      - name: Run Snyk Security Scan
        uses: snyk/actions/node@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

需要审批的部署

name: Deploy to Production

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

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://app.example.com

    steps:
      - uses: actions/checkout@v4

      - name: Deploy application
        run: |
          echo "Deploying to production..."
          # Deployment commands here

      - name: Notify Slack
        if: success()
        uses: slackapi/slack-github-action@v1
        with:
          webhook-url: ${{ secrets.SLACK_WEBHOOK }}
          payload: |
            {
              "text": "Deployment to production completed successfully!"
            }

常见陷阱

本节记录了会导致 GitHub Actions 工作流静默或意外失败的真实故障模式和反模式。

1. 工作流语法错误

问题: YAML 缩进、引号和表达式语法是导致静默失败的最常见原因。

常见错误:

缩进错误
# ❌ WRONG - Missing indentation
on: push
jobs:
test:
  runs-on: ubuntu-latest
  steps:
  - run: npm test

# ✅ CORRECT
on: push
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: npm test

错误消息: "unexpected mapping value" or "mapping values are not allowed here" 修复方法: YAML 严格要求使用 2 个空格缩进。在工作流中使用 yamllint 等 YAML 检查工具。

表达式语法混淆
# ❌ WRONG - Using $ without github context
- run: echo ${{ matrix.node-version }}

# ❌ WRONG - Missing quotes on complex expressions
env:
  MY_VAR: ${{ github.event.pull_request.title }}

# ✅ CORRECT
- run: echo "${{ matrix.node-version }}"

# ✅ CORRECT with quotes for strings
env:
  MY_VAR: "${{ github.event.pull_request.title }}"

错误消息: "Unable to process template language" or "unrecognized named value" 修复方法: 对用于 Shell 命令或作为字符串的表达式始终加引号。GitHub Actions 要求正确使用引号,以确保安全展开。

多行字符串未使用管道语法
# ❌ WRONG - Multiline without | or >
- run: echo "Line 1
Line 2"

# ✅ CORRECT using pipe (preserves newlines)
- run: |
  npm install
  npm run build
  npm test

# ✅ CORRECT using >  (folds newlines)
- name: Summary
  run: >
    This is a long
    command that spans
    multiple lines

错误消息: "expected '<block end>', but found '\\n'" 修复方法: 使用 | 表示文本块(保留换行符),或使用 > 表示折叠块(将换行符折叠为空格)。


2. 机密处理错误

问题: 机密是最常被错误处理的元素。GitHub Actions 对机密何时可用有特定规则。

关键错误:

在工作流文件中硬编码机密
# ❌ ABSOLUTELY WRONG - Secret is now in git history
- run: |
  aws s3 sync . s3://my-bucket \
    --aws-access-key-id AKIA1234567890ABCDEF \
    --aws-secret-access-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

错误消息: 初始时没有,但这是严重的安全漏洞。 修复方法: 始终使用 ${{ secrets.SECRET_NAME }},并在 GitHub 仓库设置中定义机密。

在非机密上下文中访问机密
# ❌ WRONG - Secrets not available in if: conditionals
if: ${{ secrets.DEPLOY_KEY != '' }}

# ✅ CORRECT - Secrets work in env: blocks at job and step level
jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      MESSAGE: ${{ secrets.MY_SECRET }} # ← Works at job level
    steps:
      - name: Deploy
        env:
          DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }} # ← Works at step level
        run: |
          # Now DEPLOY_KEY is available here
          ./deploy.sh

错误消息: 机密显示为 ***(已屏蔽),但在 if: 条件中使用时实际上为空或未定义。 修复方法: 在作业或步骤级别的 env: 块中使用机密。切勿在 if: 条件中使用机密——它们在那里不可用。

忘记将输出标记为敏感内容
# ❌ WRONG - Logs leak credentials
- name: Get credentials
  run: |
    TOKEN=$(curl -s https://api.example.com/token)
    echo "TOKEN=$TOKEN" >> $GITHUB_OUTPUT
    echo "Got token: $TOKEN"  # ← Logged!

# ✅ CORRECT - Mark as secret in action output
- name: Get credentials
  id: creds
  run: |
    TOKEN=$(curl -s https://api.example.com/token)
    echo "token=$TOKEN" >> $GITHUB_OUTPUT  # ← Set output
  # Then reference as:
  # ${{ steps.creds.outputs.token }}

错误消息: 凭据以明文形式出现在工作流日志中。 修复方法: 对敏感值使用 $GITHUB_OUTPUT,切勿直接通过 echo 输出。

可复用工作流中的机密上下文错误
# ❌ WRONG - Parent secrets aren't automatically passed
jobs:
  call-workflow:
    uses: ./.github/workflows/deploy.yml
    # secrets: inherit not specified!

# ✅ CORRECT
jobs:
  call-workflow:
    uses: ./.github/workflows/deploy.yml
    secrets: inherit  # ← Pass all parent secrets

错误消息: 工作流运行了,但被调用的工作流中的机密未定义。 修复方法: 调用需要机密的可复用工作流时,添加 secrets: inherit。


3. 权限问题

问题: GITHUB_TOKEN 默认作用域有限,而且权限很容易配置错误。

常见问题:

令牌权限不足
# ❌ WRONG - Trying to write packages with default permissions
- name: Push to Docker registry
  run: |
    docker push ghcr.io/${{ github.repository }}:latest
    # Fails with "permission denied" because GITHUB_TOKEN lacks 'packages: write'

# ✅ CORRECT - Explicitly grant permissions
jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read        # Read repo code
      packages: write       # Write Docker images
      id-token: write       # For OIDC token exchange
    steps:
    - uses: actions/checkout@v4
    - name: Push to Docker registry
      run: docker push ghcr.io/${{ github.repository }}:latest

错误消息: "authentication failed, permission denied" 或 API 返回 "Insufficient permissions" 修复方法: 始终在作业级别显式声明 permissions:,并指定所需作用域(contents、packages、id-token、pull-requests、issues、deployments 等)。

尝试使用 GITHUB_TOKEN 执行它无法完成的操作
# ❌ WRONG - GITHUB_TOKEN can't trigger other workflows
- name: Trigger deployment
  run: |
    curl -X POST https://api.github.com/repos/${{ github.repository }}/dispatches \
      -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
      -d '{"event_type":"deploy"}'
    # Fails silently - GITHUB_TOKEN lacks workflow permissions

# ✅ CORRECT - Use a PAT (Personal Access Token) or GitHub App token
- name: Trigger deployment
  run: |
    curl -X POST https://api.github.com/repos/${{ github.repository }}/dispatches \
      -H "Authorization: token ${{ secrets.WORKFLOW_PAT }}" \
      -d '{"event_type":"deploy"}'

错误消息: "Resource not accessible by integration"(HTTP 403) 修复方法: GITHUB_TOKEN 无法触发工作流(repository_dispatch)。请改用存储在 secrets 中的 PAT。

跨仓库访问失败
# ❌ WRONG - GITHUB_TOKEN only has access to current repo
- name: Clone another repo
  run: |
    git clone https://github.com/other-org/private-repo.git
    # Fails - GITHUB_TOKEN has no access

# ✅ CORRECT - Use a PAT with repo access
- name: Clone another repo
  run: |
    git clone https://x-access-token:${{ secrets.CROSS_REPO_PAT }}@github.com/other-org/private-repo.git

错误消息: "fatal: could not read Username for 'https://github.com': terminal prompts disabled" 修复方法: 使用具有 repo 或 read:repo_hook 权限范围的 Personal Access Token(PAT)进行跨仓库访问。


4. 矩阵策略失败

问题: 矩阵构建功能强大,但当组合有误或错误使用 exclude/include 时,可能会悄无声息地失败。

常见陷阱:

步骤中未定义矩阵上下文
# ❌ WRONG - Using matrix variables that don't exist
jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest]
        # No 'version' defined here
    steps:
    - run: echo "Version is ${{ matrix.version }}"  # ← Empty!

# ✅ CORRECT - Define all matrix variables used
jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest]
        version: ['1.0', '2.0']
    steps:
    - run: echo "Building for ${{ matrix.os }} v${{ matrix.version }}"

错误消息: 日志中的矩阵变量为空或未定义。 修复方法: 步骤中引用的所有变量都必须在 strategy.matrix 中定义。

exclude/include 语法错误
# ❌ WRONG - Invalid exclude syntax
jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        node-version: ['18', '20']
      exclude:
        - os: windows-latest, node-version: '18'  # ← Comma not allowed here

# ✅ CORRECT - Proper exclude syntax
jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        node-version: ['18', '20']
      exclude:
        - os: windows-latest
          node-version: '18'

# ✅ Using include for specific combinations
jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest]
        include:
          - os: windows-latest
            node-version: '20'  # ← Only windows + node 20

错误消息: 工作流在验证阶段解析失败。 修复方法: exclude 和 include 使用 YAML 列表语法,每个属性各占一行。

笛卡尔积膨胀
# ❌ WRONG - Creates 4 × 3 × 2 × 5 = 120 jobs unexpectedly
jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest, linux-arm64]
        node-version: ['16', '18', '20']
        npm-version: ['8', '9']
        python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
        # This is excessive and wastes CI minutes

# ✅ CORRECT - Use include for specific combinations
jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        include:
          - os: ubuntu-latest
            node-version: '20'
            npm-version: '9'
          - os: macos-latest
            node-version: '20'
            npm-version: '9'
          - os: windows-latest
            node-version: '18'
            npm-version: '8'

错误消息: 没有错误,但 CI 开支突然翻了四倍。 修复方法: 使用 include 定义特定组合,而不是让矩阵生成笛卡尔积。


5. 缓存错误

问题: GitHub Actions 的缓存策略较为保守——过期缓存可能保留数月,导致难以查明的构建失败。

关键问题:

过期缓存导致反复失败
# ❌ WRONG - Cache key doesn't change, stale deps stay cached
- uses: actions/cache@v3
  with:
    path: node_modules
    key: deps-${{ runner.os }} # ← Never changes!
    restore-keys: |
      deps-${{ runner.os }}

# ✅ CORRECT - Include lockfile hash in cache key
- uses: actions/cache@v3
  with:
    path: node_modules
    key: deps-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      deps-${{ runner.os }}-

错误消息: 构建在本地通过,却在 CI 中因难以理解的模块错误而失败。 修复方法: 始终在缓存键中包含依赖锁定文件的哈希值:npm 使用 ${{ hashFiles('**/package-lock.json') }},pip 使用 ${{ hashFiles('**/requirements.txt') }}。

语言运行时的缓存路径错误
# ❌ WRONG - Caching wrong path, cache misses happen
- name: Setup Node
  uses: actions/setup-node@v4
  with:
    node-version: "20.x"
- uses: actions/cache@v3
  with:
    path: /tmp/node_modules # ← Wrong path!
    key: deps-${{ hashFiles('package-lock.json') }}

# ✅ CORRECT - Let action handle caching, or use right path
- name: Setup Node
  uses: actions/setup-node@v4
  with:
    node-version: "20.x"
    cache: "npm" # ← Let the action handle caching

# OR if manual caching:
- uses: actions/cache@v3
  with:
    path: ~/.npm # ← Correct npm cache location
    key: npm-${{ hashFiles('package-lock.json') }}

错误消息: 工作流运行缓慢,反复下载依赖项。 修复方法: 使用 setup-node@v4 内置的 cache: 参数,或缓存语言运行时的官方缓存目录(例如 ~/.npm、~/.pip-cache)。

缓存失效竞争条件
# ❌ WRONG - Multiple branches writing to same cache
branches:
  - main
  - develop
  - '*'

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/cache@v3
      with:
        path: dist
        key: build-${{ hashFiles('package.json') }}
        # develop branch builds with old deps, overwrites cache
        # main branch then gets develop's stale build artifacts

# ✅ CORRECT - Include branch in cache key or read-only on non-main
- uses: actions/cache@v3
  with:
    path: dist
    key: build-${{ github.ref }}-${{ hashFiles('package.json') }}
    restore-keys: |
      build-refs/heads/main-
      build-refs/heads/develop-

错误消息: 合并后出现难以查明的测试失败(缓存受到其他分支的污染)。 修复方法: 在缓存键中包含 ${{ github.ref }},以隔离各分支的缓存;或者在非主分支上使用只读模式。

Docker 层缓存未保留
# ❌ WRONG - Rebuilds every layer despite cache-from
- uses: docker/build-push-action@v5
  with:
    context: .
    push: true
    tags: myimage:latest
    # cache-from: type=gha missing!

# ✅ CORRECT - Use GitHub Actions cache backend
- uses: docker/build-push-action@v5
  with:
    context: .
    push: true
    tags: myimage:latest
    cache-from: type=gha
    cache-to: type=gha,mode=max

错误消息: 尽管本地缓存正常工作,Docker 构建仍然非常缓慢。 修复方法: 始终在 docker/build-push-action 中包含 cache-from: type=gha 和 cache-to: type=gha,mode=max,以便在多次运行之间缓存各层。


调试工作流

工作流失败时的实用技巧:

  1. 启用调试日志: 在仓库设置中设置 ACTIONS_STEP_DEBUG=true secret,以查看详细日志
  2. 检查权限: API 调用失败时,检查作业的 permissions: 块
  3. 验证 YAML: 推送前,在本地对工作流文件运行 yamllint
  4. 在本地测试矩阵: 在本地测试脚本中模拟矩阵组合
  5. 检查缓存: 在 GitHub 界面的“Actions” → “Caches”下查看缓存条目
  6. 检查 secrets: 确认所有 ${{ secrets.NAME }} 均已在仓库设置中定义

相关技能

  • gitlab-ci-patterns - 用于 GitLab CI 工作流
  • deployment-pipeline-design - 用于流水线架构
  • secrets-management - 用于 secrets 管理

评论

支持 Markdown