第六章:GitLab CI 从零到一:Runner 配置与 YAML 语法

如果你已经在使用 GitLab 管理代码,那么 GitLab CI/CD 是最自然的选择------它内置在 GitLab 中,无需额外部署 Jenkins 服务器。本章从零开始介绍 GitLab CI/CD 的核心概念:Pipeline、Job、Stage、Runner,以及 .gitlab-ci.yml 的语法。通过一个完整的示例,你将学会如何用 YAML 文件定义 CI/CD 流水线。

一、GitLab CI/CD 核心概念

GitLab CI/CD 是 GitLab 内置的持续集成与持续交付功能,与代码仓库无缝集成。

核心规则:

同一个 Stage 中的 Job 并行执行。

只有当前 Stage 的所有 Job 都成功后,才会进入下一个 Stage。

任何一个 Job 失败,Pipeline 立即停止(除非配置了 allow_failure: true)。

二、Runner:CI/CD 的执行引擎

Runner 是 GitLab CI/CD 的执行器,负责运行 Pipeline 中的 Job。GitLab 提供两种 Runner:

2.1 安装 GitLab Runner(Linux)

bash 复制代码
# 添加官方仓库
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash

# 安装
sudo apt-get install gitlab-runner

2.2 注册 Runner

bash 复制代码
sudo gitlab-runner register

按提示输入:

GitLab 实例 URL:如 https://gitlab.com 或自托管地址。

注册 Token:在项目 → Settings → CI/CD → Runners 中获取。

描述:如 docker-runner。

标签:如 docker(用于指定 Runner 执行特定 Job)。

执行器:选择 docker(最常用),或 shell、kubernetes 等。

2.3 使用 Docker 执行器

注册时选择 docker 执行器后,每个 Job 会在一个新的 Docker 容器中运行,保证环境隔离和一致性。

bash 复制代码
# 注册时设置默认镜像
Please enter the default Docker image: alpine:latest

三、.gitlab-ci.yml:声明式流水线定义

GitLab CI/CD 的流水线通过项目根目录下的 .gitlab-ci.yml 文件定义。这是一个 YAML 文件,GitLab 在每次代码推送时自动解析并执行。

3.1 最简示例

yaml 复制代码
# 定义 Stages(按顺序执行)
stages:
  - build
  - test
  - deploy

# 每个 Job 属于一个 Stage
build-job:
  stage: build
  script:
    - echo "正在编译代码..."
    - mvn clean compile

test-job:
  stage: test
  script:
    - echo "正在运行测试..."
    - mvn test

deploy-job:
  stage: deploy
  script:
    - echo "正在部署到生产环境..."
    - scp target/*.jar user@server:/app/

3.2 一个更完整的示例

yaml 复制代码
# 定义变量
variables:
  MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
  DOCKER_REGISTRY: "registry.gitlab.com"
  IMAGE_TAG: "$CI_COMMIT_SHORT_SHA"

# 定义 Stages
stages:
  - build
  - test
  - package
  - deploy

# 缓存 Maven 依赖,加速后续构建
cache:
  paths:
    - .m2/repository/

# 使用 Docker 镜像作为执行环境
image: maven:3.8.4-openjdk-17

# Build Job
build:
  stage: build
  script:
    - mvn clean compile
  artifacts:
    paths:
      - target/classes/

# Test Job(并行执行)
test:unit:
  stage: test
  script:
    - mvn test
  artifacts:
    paths:
      - target/surefire-reports/
    reports:
      junit: target/surefire-reports/*.xml

test:integration:
  stage: test
  script:
    - mvn verify -Pintegration-test
  allow_failure: true   # 集成测试失败不阻断 Pipeline

# Package Job(打包并构建镜像)
package:
  stage: package
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker build -t $DOCKER_REGISTRY/$CI_PROJECT_PATH:$IMAGE_TAG .
    - docker push $DOCKER_REGISTRY/$CI_PROJECT_PATH:$IMAGE_TAG
  only:
    - main

# Deploy Job(仅 main 分支触发)
deploy:
  stage: deploy
  script:
    - echo "部署 $IMAGE_TAG 到生产环境..."
  environment:
    name: production
    url: https://myapp.example.com
  only:
    - main
  when: manual   # 需要手动触发

四、核心语法详解

4.1 stages:定义阶段顺序

stages 定义了 Pipeline 的执行顺序,Job 按照所属 Stage 的顺序依次执行。

yaml 复制代码
stages:
  - build
  - test
  - deploy

未指定 stage 的 Job 默认属于 test 阶段。

4.2 script:执行命令

script 是 Job 的核心,包含要执行的 Shell 命令。

yaml 复制代码
job:
  script:
    - echo "Hello"
    - mvn clean package

4.3 before_script 与 after_script

在所有 Job 之前/之后执行的通用脚本:

yaml 复制代码
before_script:
  - echo "开始执行 Pipeline..."
  - apt-get update -qq

after_script:
  - echo "Pipeline 执行结束"
  - rm -rf /tmp/*

4.4 cache 与 artifacts

yaml 复制代码
cache:
  paths:
    - .m2/repository/

artifacts:
  paths:
    - target/*.jar
  expire_in: 1 week   # 1 周后自动清理
4.5 only / except:控制触发条件
yaml
# 仅在 main 分支触发
job:
  only:
    - main

# 仅在 Tag 触发
job:
  only:
    - tags

# 排除特定分支
job:
  except:
    - develop

4.6 when:控制执行时机

yaml 复制代码
deploy:
  when: manual   # 需要人工点击按钮触发

4.7 environment:部署环境管理

yaml 复制代码
deploy:
  environment:
    name: production
    url: https://myapp.example.com

GitLab 会记录每次部署到该环境的历史版本,支持一键回滚。

4.8 rules:高级条件控制(推荐)

rules 是 only/except 的增强版,支持更复杂的逻辑:

yaml 复制代码
job:
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: on_success
    - if: '$CI_COMMIT_BRANCH == "develop"'
      when: manual
      allow_failure: true
    - when: never   # 其他情况不执行

五、多分支自动构建

GitLab CI/CD 天然支持多分支:每个分支的代码推送都会触发独立的 Pipeline。只需在 .gitlab-ci.yml 中使用 only 或 rules 控制不同分支的行为即可。

yaml 复制代码
# main 分支:完整构建 + 部署到生产
build-and-deploy-main:
  stage: deploy
  script:
    - ./deploy.sh production
  only:
    - main

# develop 分支:构建 + 部署到测试环境
build-and-deploy-develop:
  stage: deploy
  script:
    - ./deploy.sh staging
  only:
    - develop

六、合并请求(Merge Request)流水线

GitLab CI/CD 可以在合并请求触发时自动运行 Pipeline,帮助在合并前验证代码质量。

yaml 复制代码
# 在 MR 中运行测试,但不部署
test-mr:
  stage: test
  script:
    - mvn test
  only:
    - merge_requests
  except:
    - main

七、实战:Spring Boot 项目的完整 CI/CD

yaml 复制代码
# .gitlab-ci.yml
stages:
  - build
  - test
  - package
  - deploy

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
  DOCKER_REGISTRY: "registry.gitlab.com"
  IMAGE_TAG: "$CI_COMMIT_SHORT_SHA"

cache:
  paths:
    - .m2/repository/

image: maven:3.8.4-openjdk-17

# 构建
build:
  stage: build
  script:
    - mvn clean compile
  artifacts:
    paths:
      - target/classes/

# 测试(并行)
test:unit:
  stage: test
  script:
    - mvn test
  artifacts:
    reports:
      junit: target/surefire-reports/*.xml

test:integration:
  stage: test
  script:
    - mvn verify -Pintegration
  allow_failure: true

# 打包镜像(仅 main 分支)
package:
  stage: package
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker build -t $DOCKER_REGISTRY/$CI_PROJECT_PATH:$IMAGE_TAG .
    - docker push $DOCKER_REGISTRY/$CI_PROJECT_PATH:$IMAGE_TAG
  only:
    - main
  dependencies:
    - build

# 部署到测试环境(develop 分支自动部署)
deploy-staging:
  stage: deploy
  script:
    - echo "部署到 Staging 环境..."
    - kubectl set image deployment/myapp myapp=$DOCKER_REGISTRY/$CI_PROJECT_PATH:$IMAGE_TAG -n staging
  environment:
    name: staging
    url: https://staging.myapp.example.com
  only:
    - develop

# 部署到生产环境(main 分支手动触发)
deploy-production:
  stage: deploy
  script:
    - echo "部署到 Production 环境..."
    - kubectl set image deployment/myapp myapp=$DOCKER_REGISTRY/$CI_PROJECT_PATH:$IMAGE_TAG -n production
  environment:
    name: production
    url: https://myapp.example.com
  only:
    - main
  when: manual

八、GitLab CI vs Jenkins:核心差异

九、小结

GitLab CI/CD 将代码仓库与 CI/CD 流水线融为一体,通过简洁的 YAML 语法定义构建、测试、部署流程。Runner 是执行引擎,支持 Docker、Shell、Kubernetes 等多种执行器。对于已经在使用 GitLab 的团队,GitLab CI 是最自然、最低门槛的选择。