作业与阶段 #

一、Stage(阶段)概念 #

什么是Stage? #

Stage是Pipeline的逻辑分组,用于组织Job的执行顺序。同一Stage中的Job并行执行,不同Stage按顺序执行。

text
┌─────────────────────────────────────────────────────────┐
│                      Pipeline                            │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  Stage 1: Build                                          │
│  ┌─────────────┐  ┌─────────────┐                       │
│  │ build_job_1 │  │ build_job_2 │  (并行执行)            │
│  └─────────────┘  └─────────────┘                       │
│         ↓                ↓                               │
│  Stage 2: Test                                           │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ test_unit   │  │ test_e2e    │  │ test_integ  │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
│         ↓                ↓                ↓              │
│  Stage 3: Deploy                                         │
│  ┌─────────────┐                                         │
│  │ deploy_job  │                                         │
│  └─────────────┘                                         │
│                                                          │
└─────────────────────────────────────────────────────────┘

定义Stages #

yaml
stages:
  - build
  - test
  - deploy

默认Stages #

如果不定义stages,GitLab使用以下默认值:

yaml
stages:
  - build
  - test
  - deploy

Stage执行规则 #

  1. 同一Stage中的Job并行执行
  2. 前一个Stage的所有Job成功后,下一个Stage才开始
  3. 如果某个Stage中有Job失败,后续Stage不会执行

二、Job(作业)概念 #

什么是Job? #

Job是Pipeline的最小执行单元,定义了具体的执行任务。

yaml
job_name:
  stage: test
  script:
    - echo "Running tests"
    - npm test

Job命名规则 #

  • 必须是有效的YAML键名
  • 每个Job名称必须唯一
  • 不能使用GitLab保留关键字

保留关键字:

text
image, services, stages, types, before_script, after_script,
variables, cache, include, true, false, nil

Job基本结构 #

yaml
job_name:
  stage: stage_name
  script:
    - command1
    - command2
  variables:
    VAR: value
  only:
    - main

三、Job类型 #

1. 普通Job #

yaml
test_job:
  stage: test
  script:
    - npm test

2. 手动Job #

yaml
deploy_production:
  stage: deploy
  script:
    - echo "Deploying..."
  when: manual

3. 延迟Job #

yaml
deploy_job:
  stage: deploy
  script:
    - echo "Deploying..."
  when: delayed
  start_in: 30 minutes

4. 触发Job #

yaml
trigger_downstream:
  stage: deploy
  trigger:
    project: my-group/my-project
    branch: main

5. 隐藏Job(模板) #

.开头的Job不会执行,可作为模板:

yaml
.template:
  script:
    - echo "Template script"

real_job:
  extends: .template

四、Stage执行流程 #

顺序执行 #

yaml
stages:
  - build
  - test
  - deploy

build_job:
  stage: build
  script: echo "Building..."

test_job:
  stage: test
  script: echo "Testing..."

deploy_job:
  stage: deploy
  script: echo "Deploying..."

执行顺序:

text
build_job → test_job → deploy_job

并行执行 #

yaml
stages:
  - test

test_unit:
  stage: test
  script: npm run test:unit

test_integration:
  stage: test
  script: npm run test:integration

test_e2e:
  stage: test
  script: npm run test:e2e

执行顺序:

text
test_unit ┐
test_integration ├─ 并行执行
test_e2e ┘

五、needs关键字(DAG) #

什么是DAG? #

DAG(有向无环图)允许Job不按Stage顺序执行,而是按依赖关系执行。

yaml
stages:
  - build
  - test
  - deploy

build_a:
  stage: build
  script: echo "Build A"

build_b:
  stage: build
  script: echo "Build B"

test_a:
  stage: test
  needs: [build_a]
  script: echo "Test A"

test_b:
  stage: test
  needs: [build_b]
  script: echo "Test B"

deploy:
  stage: deploy
  needs: [test_a, test_b]
  script: echo "Deploy"

执行图:

text
build_a → test_a ┐
                  ├→ deploy
build_b → test_b ┘

needs与artifacts #

yaml
build:
  stage: build
  script:
    - npm run build
  artifacts:
    paths:
      - dist/

test:
  stage: test
  needs:
    - job: build
      artifacts: true
  script:
    - ls dist/

needs与optional #

yaml
test:
  stage: test
  needs:
    - job: lint
      optional: true
  script:
    - npm test

六、Job控制 #

1. 条件执行 #

使用rules:

yaml
deploy_production:
  stage: deploy
  script:
    - echo "Deploying..."
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: manual
    - when: never

使用only/except:

yaml
deploy_production:
  stage: deploy
  script:
    - echo "Deploying..."
  only:
    - main

2. 失败处理 #

yaml
lint:
  stage: test
  script:
    - npm run lint
  allow_failure: true

test:
  stage: test
  script:
    - npm test

3. 重试机制 #

yaml
flaky_test:
  stage: test
  script:
    - npm test
  retry:
    max: 2
    when:
      - script_failure
      - runner_system_failure
      - stuck_or_timeout_failure

4. 超时控制 #

yaml
long_job:
  stage: build
  script:
    - ./long-script.sh
  timeout: 2h

5. 并行执行 #

yaml
test:
  stage: test
  parallel: 5
  script:
    - echo "Running test $CI_NODE_INDEX of $CI_NODE_TOTAL"

矩阵并行:

yaml
test:
  stage: test
  parallel:
    matrix:
      - NODE: [16, 18, 20]
        OS: [linux, windows, macos]
  image: node:${NODE}
  tags:
    - ${OS}
  script:
    - echo "Testing Node ${NODE} on ${OS}"

七、Job产物传递 #

artifacts传递 #

yaml
build:
  stage: build
  script:
    - npm run build
  artifacts:
    paths:
      - dist/

test:
  stage: test
  dependencies:
    - build
  script:
    - ls dist/
    - npm test

dependencies限制 #

yaml
build_a:
  stage: build
  script: echo "Build A"
  artifacts:
    paths:
      - dist_a/

build_b:
  stage: build
  script: echo "Build B"
  artifacts:
    paths:
      - dist_b/

test:
  stage: test
  dependencies:
    - build_a
  script:
    - ls dist_a/

八、Stage和Job最佳实践 #

1. 合理划分Stage #

yaml
stages:
  - lint
  - build
  - test
  - security
  - deploy

2. 使用模板复用配置 #

yaml
.node_template:
  image: node:18
  before_script:
    - npm ci
  cache:
    paths:
      - node_modules/

lint:
  extends: .node_template
  stage: lint
  script:
    - npm run lint

test:
  extends: .node_template
  stage: test
  script:
    - npm test

3. 使用needs优化执行 #

yaml
stages:
  - lint
  - build
  - test

lint:
  stage: lint
  script: npm run lint

build:
  stage: build
  script: npm run build

test_unit:
  stage: test
  needs: [build]
  script: npm run test:unit

test_integration:
  stage: test
  needs: [build, lint]
  script: npm run test:integration

4. 控制并发 #

yaml
deploy_production:
  stage: deploy
  resource_group: production
  script:
    - echo "Deploying..."

5. 环境管理 #

yaml
deploy_staging:
  stage: deploy
  environment:
    name: staging
    url: https://staging.example.com
    on_stop: stop_staging
  script:
    - echo "Deploying to staging"

stop_staging:
  stage: deploy
  environment:
    name: staging
    action: stop
  script:
    - echo "Stopping staging"
  when: manual

九、完整示例 #

微服务项目 #

yaml
stages:
  - lint
  - build
  - test
  - security
  - package
  - deploy

variables:
  DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

lint:
  stage: lint
  image: node:18
  script:
    - npm ci
    - npm run lint
  allow_failure: true

build:
  stage: build
  image: node:18
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 week

test_unit:
  stage: test
  image: node:18
  needs: [build]
  script:
    - npm ci
    - npm run test:unit
  coverage: '/Coverage: \d+%/'

test_integration:
  stage: test
  image: node:18
  services:
    - postgres:14
  needs: [build]
  script:
    - npm ci
    - npm run test:integration

security_scan:
  stage: security
  image: docker:latest
  needs: [build]
  script:
    - echo "Running security scan..."
  allow_failure: true

docker_build:
  stage: package
  image: docker:latest
  services:
    - docker:dind
  needs: [test_unit, test_integration]
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $DOCKER_IMAGE .
    - docker push $DOCKER_IMAGE

deploy_staging:
  stage: deploy
  image: bitnami/kubectl:latest
  needs: [docker_build]
  environment:
    name: staging
    url: https://staging.example.com
  script:
    - kubectl set image deployment/myapp myapp=$DOCKER_IMAGE
  only:
    - develop

deploy_production:
  stage: deploy
  image: bitnami/kubectl:latest
  needs: [docker_build, security_scan]
  environment:
    name: production
    url: https://example.com
  script:
    - kubectl set image deployment/myapp myapp=$DOCKER_IMAGE
  only:
    - main
  when: manual

十、常见问题 #

1. Stage执行顺序不对 #

确保stages定义正确:

yaml
stages:
  - build
  - test
  - deploy

2. Job没有并行执行 #

检查是否在同一个stage:

yaml
stages:
  - test

test_unit:
  stage: test

test_integration:
  stage: test

3. needs找不到artifacts #

确保artifacts正确传递:

yaml
build:
  artifacts:
    paths:
      - dist/

test:
  needs:
    - job: build
      artifacts: true

下一步 #

现在你已经掌握了Jobs和Stages的概念,接下来让我们学习 流水线类型

最后更新:2026-03-28