GitHub Actions 作业Job #

作业(Job)是工作流中的执行单元,由一组步骤组成,在同一个运行器上执行。本节深入探讨作业的各个方面。

作业概述 #

什么是作业? #

作业是工作流的基本执行单元,具有以下特点:

  • 在同一个运行器上执行
  • 共享相同的文件系统
  • 可以并行或顺序执行
  • 可以设置依赖关系

作业结构 #

yaml
jobs:
  job-id:                    # 作业标识符
    name: Job Display Name   # 显示名称
    runs-on: ubuntu-latest   # 运行环境
    needs: [other-job]       # 依赖关系
    if: condition            # 条件执行
    env:                     # 环境变量
      VAR: value
    steps:                   # 步骤列表
      - run: echo "Hello"

运行器配置 #

GitHub托管运行器 #

yaml
jobs:
  ubuntu-job:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Running on Ubuntu"

  windows-job:
    runs-on: windows-latest
    steps:
      - run: Write-Host "Running on Windows"

  macos-job:
    runs-on: macos-latest
    steps:
      - run: echo "Running on macOS"

运行器标签 #

yaml
# 使用特定版本
runs-on: ubuntu-22.04
runs-on: windows-2022
runs-on: macos-13

# 使用多个标签
runs-on: [self-hosted, linux, x64]

# 使用标签表达式
runs-on: ${{ matrix.os }}

自托管运行器 #

yaml
jobs:
  self-hosted-job:
    runs-on: self-hosted
    steps:
      - run: echo "Running on self-hosted runner"

  # 带标签的自托管运行器
  labeled-runner:
    runs-on: [self-hosted, linux, gpu]
    steps:
      - run: echo "Running on GPU runner"

作业依赖 #

基本依赖 #

yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building..."

  test:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "Testing..."

  deploy:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying..."

多作业依赖 #

yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building..."

  test-unit:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "Unit testing..."

  test-integration:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "Integration testing..."

  test-e2e:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "E2E testing..."

  deploy:
    needs: [test-unit, test-integration, test-e2e]
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying..."

依赖图可视化 #

text
          ┌─────────┐
          │  build  │
          └────┬────┘
               │
     ┌─────────┼─────────┐
     │         │         │
     ▼         ▼         ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│test-unit│ │test-int │ │ test-e2e│
└────┬────┘ └────┬────┘ └────┬────┘
     │         │         │
     └─────────┼─────────┘
               │
               ▼
          ┌─────────┐
          │ deploy  │
          └─────────┘

条件执行 #

基本条件 #

yaml
jobs:
  deploy:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying to production"

  deploy-staging:
    if: github.ref == 'refs/heads/develop'
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying to staging"

使用上下文 #

yaml
jobs:
  build:
    if: github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - run: echo "Push event"

  pr-check:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - run: echo "Pull request event"

使用作业状态 #

yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: exit 0

  notify-success:
    needs: build
    if: success()
    runs-on: ubuntu-latest
    steps:
      - run: echo "Build succeeded"

  notify-failure:
    needs: build
    if: failure()
    runs-on: ubuntu-latest
    steps:
      - run: echo "Build failed"

  notify-always:
    needs: build
    if: always()
    runs-on: ubuntu-latest
    steps:
      - run: echo "Build finished"

矩阵构建 #

基本矩阵 #

yaml
jobs:
  test:
    strategy:
      matrix:
        node: [16, 18, 20]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: node --version

多维度矩阵 #

yaml
jobs:
  test:
    strategy:
      matrix:
        node: [16, 18, 20]
        os: [ubuntu-latest, windows-latest, macos-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: node --version

包含配置 #

yaml
jobs:
  test:
    strategy:
      matrix:
        node: [16, 18, 20]
        os: [ubuntu-latest]
        include:
          - node: 20
            os: windows-latest
            experimental: true
          - node: 20
            os: macos-latest
            coverage: true
    runs-on: ${{ matrix.os }}
    steps:
      - run: echo "Node ${{ matrix.node }} on ${{ matrix.os }}"

排除配置 #

yaml
jobs:
  test:
    strategy:
      matrix:
        node: [16, 18, 20]
        os: [ubuntu-latest, windows-latest]
        exclude:
          - node: 16
            os: windows-latest
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}

矩阵策略选项 #

yaml
jobs:
  test:
    strategy:
      matrix:
        node: [16, 18, 20]
      fail-fast: false      # 一个失败不取消其他
      max-parallel: 4       # 最大并行数
    runs-on: ubuntu-latest
    steps:
      - run: echo "Testing"

作业输出 #

定义输出 #

yaml
jobs:
  build:
    outputs:
      version: ${{ steps.version.outputs.value }}
      artifact: ${{ steps.artifact.outputs.path }}
    runs-on: ubuntu-latest
    steps:
      - id: version
        run: echo "value=1.0.0" >> $GITHUB_OUTPUT
      - id: artifact
        run: echo "path=dist/" >> $GITHUB_OUTPUT

使用输出 #

yaml
jobs:
  build:
    outputs:
      version: ${{ steps.version.outputs.value }}
    steps:
      - id: version
        run: echo "value=1.0.0" >> $GITHUB_OUTPUT

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying version ${{ needs.build.outputs.version }}"

环境配置 #

使用环境 #

yaml
jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://example.com
    steps:
      - run: echo "Deploying to production"

环境变量 #

yaml
jobs:
  build:
    runs-on: ubuntu-latest
    env:
      CI: true
      NODE_ENV: test
    steps:
      - run: echo $CI

使用环境Secrets #

yaml
jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - run: |
          echo "Deploying with token"
        env:
          TOKEN: ${{ secrets.DEPLOY_TOKEN }}

超时和重试 #

作业超时 #

yaml
jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - run: echo "This job will timeout after 30 minutes"

步骤超时 #

yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "This step will timeout after 5 minutes"
        timeout-minutes: 5

容器支持 #

在容器中运行 #

yaml
jobs:
  docker-job:
    runs-on: ubuntu-latest
    container:
      image: node:20
      options: --cpus 1
      env:
        NODE_ENV: test
      volumes:
        - my_volume:/volume_mount
    steps:
      - run: node --version

服务容器 #

yaml
jobs:
  test:
    runs-on: ubuntu-latest
    
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_USER: test
          POSTGRES_PASSWORD: test
          POSTGRES_DB: test
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

      redis:
        image: redis:7
        ports:
          - 6379:6379
        options: >-
          --health-cmd "redis-cli ping"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
      - name: Test with services
        run: |
          psql -h localhost -U test -d test -c "SELECT 1"
          redis-cli ping
        env:
          PGPASSWORD: test

作业示例 #

完整CI作业 #

yaml
jobs:
  lint:
    name: Lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm run lint

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

  build:
    name: Build
    needs: test
    runs-on: ubuntu-latest
    outputs:
      artifact: dist
    
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm run build
      - uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/

带服务容器的测试 #

yaml
jobs:
  integration-test:
    runs-on: ubuntu-latest
    
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_USER: test
          POSTGRES_PASSWORD: test
          POSTGRES_DB: testdb
        ports:
          - 5432:5432
        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
    
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm run test:integration
        env:
          DATABASE_URL: postgresql://test:test@localhost:5432/testdb

最佳实践 #

1. 合理设置依赖 #

yaml
# 并行执行独立作业
jobs:
  lint:
    runs-on: ubuntu-latest
  type-check:
    runs-on: ubuntu-latest
  test:
    runs-on: ubuntu-latest

  # 依赖多个作业
  build:
    needs: [lint, type-check, test]
    runs-on: ubuntu-latest

2. 使用矩阵优化测试 #

yaml
strategy:
  matrix:
    include:
      - node: 20
        os: ubuntu-latest
      - node: 18
        os: ubuntu-latest

3. 设置合理的超时 #

yaml
jobs:
  build:
    timeout-minutes: 30

4. 使用环境保护敏感操作 #

yaml
jobs:
  deploy:
    environment: production

下一步学习 #

小结 #

  • 作业是工作流的执行单元
  • 可以设置作业依赖关系
  • 支持矩阵构建进行多配置测试
  • 可以使用服务容器
  • 支持容器化运行
  • 可以定义和使用作业输出
  • 使用环境保护敏感操作
最后更新:2026-03-28