文章

GitHub Actions 实战指南

GitHub Actions 实战指南

概述

GitHub Actions 是 GitHub 原生的 CI/CD 平台,通过 YAML 定义 Workflow,在事件驱动(push/PR/release)下自动执行。

核心概念

Workflow(工作流)
 └── Job(作业,可并行/串行)
      └── Step(步骤)
           └── Action(可复用组件) 或 Shell 命令
概念职责示例
Workflow一个完整的自动化流程.github/workflows/ci.yml
Event触发条件push, pull_request, schedule, workflow_dispatch
Job在同一个 Runner 上执行的一组 Stepbuild, test, deploy
Step最小执行单元uses: actions/checkout@v4run: npm test
Action可复用的步骤组件docker/login-action, actions/setup-go
Runner执行 Job 的机器ubuntu-latest, self-hosted

Job 间的依赖与并行

jobs:
  lint:             # 无依赖,最先执行
    runs-on: ubuntu-latest
    steps: [ ... ]

  test:
    needs: lint     # 等 lint 完成
    runs-on: ubuntu-latest
    steps: [ ... ]

  build:
    needs: test     # 等 test 完成
    strategy:
      matrix:       # 矩阵构建:3 个并行 Job
        go-version: ['1.21', '1.22', '1.23']
    runs-on: ubuntu-latest
    steps: [ ... ]

标准 CI Workflow(Go 项目)

name: CI

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

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

jobs:
  # ── 代码检查 ──
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with: { go-version: '${{ env.GO_VERSION }}' }
      - name: golangci-lint
        uses: golangci/golangci-lint-action@v6
        with: { version: latest }

  # ── 测试 ──
  test:
    needs: lint
    runs-on: ubuntu-latest
    services:
      mysql:                    # 声明 Service Container
        image: mysql:8.0
        env:
          MYSQL_ROOT_PASSWORD: password
          MYSQL_DATABASE: testdb
        ports: ['3306:3306']
        options: >-
          --health-cmd "mysqladmin ping -h localhost"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with: { go-version: '${{ env.GO_VERSION }}' }
      - name: Run tests
        run: go test -v -race -coverprofile=coverage.out ./...
      - name: Upload coverage
        uses: actions/upload-artifact@v4
        with:
          name: coverage
          path: coverage.out

  # ── 安全扫描 ──
  security:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Trivy scan
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          format: 'sarif'
          output: 'trivy-results.sarif'
      - name: Upload SARIF
        uses: github/codeql-action/upload-sarif@v3
        with: { sarif_file: 'trivy-results.sarif' }

  # ── 构建与推送镜像 ──
  build-push:
    needs: security
    if: github.ref == 'refs/heads/main'  # 仅 main 分支推送镜像
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write              # 需要推送 GHCR 权限
    steps:
      - uses: actions/checkout@v4
      - name: Docker meta
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=sha,format=short
            type=ref,event=branch
      - name: Login to GHCR
        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@v6
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

关键技巧

1. Context 与 Expressions

# 常用的 Context
${{ github.ref }}              # refs/heads/main 或 refs/tags/v1.0
${{ github.sha }}              # 完整的 commit SHA
${{ github.event_name }}       # push / pull_request / ...
${{ github.repository }}       # owner/repo
${{ github.run_id }}           # 本次 Workflow 的唯一 ID

# 条件表达式
if: ${{ github.ref == 'refs/heads/main' }}
if: ${{ failure() }}            # 前面步骤失败了执行
if: ${{ always() }}             # 无论如何都执行(即使失败)

2. Matrix Strategy(矩阵构建)

strategy:
  fail-fast: false              # 一个失败不取消其他
  matrix:
    os: [ubuntu-latest, macos-latest]
    go-version: ['1.22', '1.23']
    # 排除特定组合
    exclude:
      - os: macos-latest
        go-version: '1.22'

3. 缓存加速

# Go modules 缓存
- uses: actions/cache@v4
  with:
    path: ~/go/pkg/mod
    key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
    restore-keys: ${{ runner.os }}-go-

# Docker 层缓存(不需要显式配置,直接用 build-push-action 的 gha cache)
# npm/node_modules 缓存
- uses: actions/cache@v4
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}

4. Secrets 与环境变量

env:
  GLOBAL_VAR: 'shared value'

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production       # 绑定 Environment(需 GitHub 端配置审批策略)
    env:
      JOB_VAR: 'job-level value'
    steps:
      - run: echo ${{ secrets.DEPLOY_TOKEN }}    # Secret 自动遮蔽
      - run: echo $GLOBAL_VAR
      - run: echo $JOB_VAR

5. 自定义 Action(复用)

.github/actions/my-action/
├── action.yml
└── script.sh
# action.yml
name: 'My Custom Action'
description: 'Do something'
inputs:
  name:
    description: 'Your name'
    required: true
    default: 'World'
outputs:
  result:
    description: 'Result'
    value: ${{ steps.hello.outputs.greeting }}
runs:
  using: 'composite'
  steps:
    - id: hello
      run: echo "greeting=Hello, ${{ inputs.name }}" >> $GITHUB_OUTPUT
      shell: bash
# 使用自定义 Action
- uses: ./.github/actions/my-action
  with:
    name: 'CI User'

常用 Actions 速查

Action用途
actions/checkout@v4检出代码
actions/setup-go/node/python/java@v5设置语言环境
actions/cache@v4缓存依赖
actions/upload-artifact@v4上传构建产物
actions/download-artifact@v4下载构建产物
docker/login-action@v3Docker 登录
docker/build-push-action@v6构建 + 推送镜像
docker/metadata-action@v5生成镜像标签
aquasecurity/trivy-action安全扫描
golangci/golangci-lint-action@v6Go Lint
github/codeql-actionSAST 代码安全分析
softprops/action-gh-release@v2创建 GitHub Release

CI/CD 部署到 K8s 示例

deploy:
  needs: build-push
  runs-on: ubuntu-latest
  environment: production
  steps:
    - uses: actions/checkout@v4
    - name: Set up kubectl
      uses: azure/setup-kubectl@v4
    - name: Set K8s context
      uses: azure/k8s-set-context@v4
      with:
        kubeconfig: ${{ secrets.KUBECONFIG }}
    - name: Deploy with Helm
      run: |
        helm upgrade --install my-app ./helm/chart \
          --set image.tag=${{ github.sha }} \
          --namespace production

常见问题 / 坑点

问题原因解决方案
Secrets 在 PR from fork 不可用安全策略,防止泄露使用 pull_request_target 事件(需谨慎)
自建 Runner 被标记 offline内存/磁盘不足或服务停止监控 Runner 状态 + 配置 ephemeral Runner
Docker 构建慢未启用缓存cache-from: type=gha, cache-to: type=gha
Workflow 超时默认 360 分钟timeout-minutes: 30 合理设限
矩阵构建中一个失败全停fail-fast: truefail-fast: false

关联知识

参考资源

学习时间

阶段时间备注
初次学习2026-07-14Workflow/Job/Step + 缓存 + Docker + K8s 部署

状态: 📖 已掌握 下次复习日期: 2026-08-14