持续集成工具(GitLab CI)

一、核心概念

GitLab CI 是 GitLab 提供的内置持续集成 / 持续部署(CI/CD)工具,可自动化软件开发流程中的构建、测试、部署等环节。以下是其核心概念的详细解释:

1. gitlab-ci.yml 文件

1.1作用:项目根目录下的 YAML 配置文件,定义了 CI/CD 流程的结构和规则。

1.2核心组件:

  • stages:定义流程阶段(如 build、test、deploy),按顺序执行。
  • jobs:每个阶段包含多个作业,同一阶段的作业并行执行。
  • keywords:如 script(执行命令)、image(Docker 镜像)、artifacts(传递文件)等。

1.3示例:

  1. yaml 运行
  2. stages:
  3. - build
  4. - test
  5. build\_job:
  6. stage: build
  7. image: node:14
  8. script:
  9. - npm install
  10. - npm run build
  11. artifacts:
  12. paths:
  13. - dist/
  14. test\_job:
  15. stage: test
  16. image: node:14
  17. script:
  18. - npm test
  19. dependencies:
  20. - build\_job

2. Pipeline(流水线)

2.1定义:一次完整的 CI/CD 流程,包含所有阶段和作业。

2.2触发方式:

  • 代码提交:push 到仓库时自动触发。
  • Schedule:定时任务(如每晚运行测试)。
  • API 触发:通过 GitLab API 手动触发。

2.3状态:成功(green)、失败(red)、运行中(yellow)。

3. Job(作业)

3.1定义:Pipeline 中的最小执行单元,属于某个阶段。

3.2关键属性:

  • script:执行的 shell 命令。
  • image:指定 Docker 镜像(如 python:3.9)。
  • only/except:控制触发条件(如仅主分支触发)。
  • artifacts:保存文件供后续作业使用。
  • cache:缓存依赖(如 node_modules)加速构建。

4. Runner(执行器)

4.1定义:执行 Pipeline 中作业的服务器或容器。

4.2类型:

  • 共享 Runner:GitLab 托管的公共执行器。
  • 特定 Runner:项目专属执行器(需自行部署)。
  • 执行环境:支持 Docker、Kubernetes、Shell 等。

4.3注册命令示例:

  1. bash 运行
  2. gitlab-runner register \
  3. --url https://gitlab.com/ \
  4. --registration-token YOUR\_TOKEN \
  5. --executor docker \
  6. --docker-image alpine:latest

5. Stage(阶段)

5.1定义:Pipeline 的逻辑分组,按顺序执行。

5.2特点:

  • 同一阶段的作业并行执行。
  • 前一阶段失败,后续阶段不会执行。
  • 常见阶段:build → test → deploy → cleanup。

6. Artifacts(制品)

6.1定义:作业产生的文件或目录,可传递给后续作业。

6.2用途:

  • 传递构建产物(如编译后的二进制文件)。
  • 保存测试报告(如 JUnit XML)。

6.3配置示例:

  1. yaml 运行
  2. build:
  3. artifacts:
  4. paths:
  5. - dist/app.jar
  6. expire\_in: 1 week

7. Cache(缓存)

7.1定义:加速作业执行的依赖项缓存机制。

7.2与 Artifacts 的区别:

  • Cache:用于同一作业的重复执行(如复用 node_modules)。
  • Artifacts:用于不同作业间的文件传递。

7.3配置示例:

  1. yaml 运行
  2. test:
  3. cache:
  4. paths:
  5. - node\_modules/
  6. key: ${CI\_COMMIT\_REF\_SLUG}

8. Rules(规则)

8.1作用:动态控制作业是否执行,替代 only/except。

8.2条件类型:

  • if:基于变量或分支判断。
  • changes:基于文件变更触发。
  • exists:基于文件存在触发。

8.3示例:

  1. yaml 运行
  2. deploy\_prod:
  3. script:
  4. - deploy-to-prod.sh
  5. rules:
  6. - if: '$CI\_COMMIT\_BRANCH == "main" && $CI\_PIPELINE\_SOURCE == "push"'
  7. when: manual # 手动触发

9. Environment(环境)

9.1定义:部署目标(如 staging、production)。

9.2功能:

  • 记录部署历史和状态。
  • 支持环境回滚。
  • 关联环境 URL。

9.3配置示例:

  1. yaml 运行
  2. deploy\_staging:
  3. script:
  4. - deploy-to-staging.sh
  5. environment:
  6. name: staging
  7. url: https://staging.example.com

10. Variables(变量)

10.1作用:存储敏感信息或配置参数。

10.2类型:

  • 全局变量:在 .gitlab-ci.yml 中定义。
  • 项目变量:在 GitLab 项目设置中配置(如 API 密钥)。
  • 预定义变量:GitLab 内置变量(如 $CI_COMMIT_SHA)。

10.3使用示例:

  1. yaml 运行
  2. deploy:
  3. script:
  4. - echo "Deploying ${ENVIRONMENT} with API key ${API\_KEY}"

二、关键功能

1. 多阶段 Pipeline

  • 顺序执行:通过 stages 定义阶段(如 build → test → deploy),前一阶段失败则后续阶段不会执行。
  • 并行作业:同一阶段的作业自动并行,提高效率。
  • 示例配置:

    1. yaml 运行
    2. stages:
    3. - build
    4. - test
    5. - deploy
    6. build:
    7. stage: build
    8. script:
    9. - npm install
    10. - npm run build
    11. test:
    12. stage: test
    13. parallel: 3 # 并行3次执行相同作业
    14. script:
    15. - npm test --shard=$CI\_NODE\_INDEX/$CI\_NODE\_TOTAL

2. 条件执行与规则系统

  • 基于分支 / 标签触发:使用 only/except 或更灵活的 rules。
  • 动态决策:根据变量、文件变更或 Pipeline 来源控制作业执行。
  • 示例:仅在合并请求时运行安全扫描

    1. yaml 运行
    2. security\_scan:
    3. script:
    4. - run-security-check.sh
    5. rules:
    6. - if: '$CI\_PIPELINE\_SOURCE == "merge\_request\_event"'
    7. when: always
    8. - when: never

3. 缓存与制品管理

  • Cache:加速依赖安装(如 npm install),支持跨作业共享。
  • Artifacts:保存构建产物(如二进制文件、测试报告),支持过期策略。
  • 示例:缓存 npm 依赖并传递构建产物

    1. yaml 运行
    2. build:
    3. cache:
    4. key: ${CI\_COMMIT\_REF\_SLUG}
    5. paths:
    6. - node\_modules/
    7. artifacts:
    8. paths:
    9. - dist/
    10. expire\_in: 1 hour
    11. test:
    12. dependencies:
    13. - build # 依赖 build 作业的 artifacts

4. 矩阵构建

  • 并行测试不同环境:使用 parallel 或 rules:when:matrix 针对多个环境执行相同作业。
  • 示例:测试多个 Node.js 版本

    1. yaml 运行
    2. test:
    3. script:
    4. - npm test
    5. strategy:
    6. matrix:
    7. NODE\_VERSION: \[14, 16, 18\]
    8. image: node:${NODE\_VERSION}

5. 环境与部署管理

  • 环境追踪:记录部署历史,支持回滚和环境可视化。
  • 手动操作:通过 when: manual 设置审批卡点。
  • 示例:生产环境部署需手动确认

    1. yam 运行
    2. deploy\_prod:
    3. script:
    4. - deploy-to-prod.sh
    5. environment:
    6. name: production
    7. url: https://example.com
    8. rules:
    9. - if: '$CI\_COMMIT\_BRANCH == "main"'
    10. when: manual

6. 变量与秘密管理

  • 预定义变量:如 $CI_COMMIT_SHA、$CI_PIPELINE_ID 等系统变量。
  • 自定义变量:在 .gitlab-ci.yml 或项目设置中定义,支持加密存储敏感信息。
  • 示例:使用加密变量连接数据库

    1. yaml 运行
    2. test:
    3. script:
    4. - psql "$DATABASE\_URL" -c "SELECT 1"

7. 定时 Pipeline

Schedule:通过 Cron 表达式定期触发 Pipeline(如每晚运行集成测试)。

配置步骤:

  • 进入项目 Settings → CI/CD → Schedules
  • 设置 Cron 表达式(如 0 0 * * *)和目标分支

8. 自动合并请求(Auto DevOps)

  • 静态代码分析:自动检测代码质量并在 MR 中显示结果。
  • 自动部署预览:为每个 MR 创建临时环境,支持可视化审查。

9. API 与触发器

  • 外部触发:通过 API 触发 Pipeline 并传递参数。
  • Webhook:基于外部事件(如代码推送、Issue 更新)触发操作。
  • API 触发示例:

    1. bash 运行
    2. curl -X POST \\
    3. -F token=$TRIGGER\_TOKEN \
    4. -F "variables\[ENV\]=staging" \
    5. https://gitlab.com/api/v4/projects/12345/trigger/pipeline

10. 与第三方工具集成

  • 测试报告:集成 JUnit、Codecov 等工具,可视化测试覆盖率。
  • 容器注册表:与 GitLab Container Registry 无缝对接,实现镜像构建与推送。
  • 示例:发布 Docker 镜像

    1. yaml 运行
    2. docker\_build:
    3. image: docker:latest
    4. services:
    5. - docker:dind
    6. script:
    7. - docker login -u $CI\_REGISTRY\_USER -p $CI\_REGISTRY\_PASSWORD $CI\_REGISTRY
    8. - docker build -t $CI\_REGISTRY\_IMAGE:$CI\_COMMIT\_TAG .
    9. - docker push $CI\_REGISTRY\_IMAGE:$CI\_COMMIT\_TAG

11. 资源限制与并行控制

  • 并发限制:通过 resource_group 控制共享资源的作业并发数。
  • 资源分配:为不同作业分配 CPU/Memory 权重(Runner 支持)。
  • 示例:限制数据库迁移作业的并发

    1. yaml 运行
    2. db\_migrate:
    3. script:
    4. - run-migrations.sh
    5. resource\_group: database

12. 模板与复用

  • CI/CD 模板:使用 include 引用公共模板(如 .NET, Python 官方模板)。
  • 作业继承:通过 extends 复用配置,减少重复代码。
  • 示例:继承官方 Python 模板

    1. yaml 运行
    2. include:
    3. - template: Python.gitlab-ci.yml
    4. stages:
    5. - build
    6. - test
    7. - deploy
    8. \# 自定义测试命令
    9. test
    10. extends: .python-test
    11. script:
    12. - pytest --cov=myapp

三、Runner 配置

GitLab Runner 是执行 CI/CD 作业的引擎,其配置直接影响 Pipeline 的性能和稳定性。以下是关键配置步骤和最佳实践:

1. Runner 安装与注册

1.1 安装 Runner

根据操作系统选择安装方式(以 Linux 为例):

  1. bash 运行
  2. \# 下载二进制文件
  3. sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
  4. \# 赋予执行权限
  5. sudo chmod +x /usr/local/bin/gitlab-runner
  6. \# 创建用户
  7. sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
  8. \# 安装并启动服务
  9. sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
  10. sudo gitlab-runner start

1.2 注册 Runner

获取项目或组的注册令牌(Settings → CI/CD → Runners)后执行:

  1. bash 运行
  2. sudo gitlab-runner register \
  3. --url https://gitlab.com/ \
  4. --registration-token YOUR\_REGISTRATION\_TOKEN \
  5. --executor docker \
  6. --docker-image alpine:latest \
  7. --description "my-docker-runner" \
  8. --tag-list "docker,linux" \
  9. --run-untagged \
  10. --locked="false"

2.核心配置文件

Runner 的全局配置位于 /etc/gitlab-runner/config.toml,常见参数:

  1. toml 运行
  2. concurrent = 4 # 并发执行的 Pipeline 数量
  3. check\_interval = 30 # 检查新作业的间隔(秒)
  4. [
  5. session\_server
  6. ]
  7. session_timeout = 1800 # 会话超时时间
  8. [[
  9. runners
  10. ]]
  11. name = "my-docker-runner"
  12. url = "https://gitlab.com/"
  13. token = "YOUR\_RUNNER\_TOKEN"
  14. executor = "docker"
  15. [
  16. runners.docker
  17. ]
  18. tls_verify = false
  19. image = "alpine:latest"
  20. privileged = false
  21. disable_entrypoint\_overwrite = false
  22. oom_kill_disable = false
  23. disable_cache = false
  24. volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock"\] # 挂载 Docker 套接字支持 dind
  25. shm_size = 2147483648 # 共享内存大小(2GB)
  26. [
  27. runners.cache
  28. ]
  29. Type = "s3"
  30. Path = "cache"
  31. Shared = true
  32. [
  33. runners.cache.s3
  34. ]
  35. ServerAddress = "s3.amazonaws.com"
  36. AccessKey = "YOUR_ACCESS_KEY"
  37. SecretKey = "YOUR_SECRET_KEY"
  38. BucketName = "gitlab-runner-cache"
  39. Insecure = false

3. 执行器配置

3.1 Docker 执行器

适用于容器化环境,需安装 Docker:

  1. toml 运作
  2. [[
  3. runners
  4. ]]
  5. executor = "docker"
  6. [
  7. runners.docker
  8. ]
  9. image = "python:3.9" \# 默认镜像
  10. pull_policy = "if-not-present" \# 镜像拉取策略
  11. network_mode = "host" \# 网络模式

3.2 Kubernetes 执行器

适用于大规模集群,动态创建 Pod 执行作业:

  1. toml 运作
  2. [[
  3. runners
  4. ]]
  5. executor = "kubernetes"
  6. [
  7. runners.kubernetes
  8. ]
  9. host = "https://kubernetes-api:443"
  10. namespace = "gitlab-runner"
  11. image = "alpine:latest"
  12. cpu_limit = "1"
  13. memory_limit = "512Mi"
  14. service_cpu_limit = "500m"
  15. service_memory_limit = "128Mi"

3.3 Shell 执行器

直接在 Runner 主机上执行命令(需谨慎配置权限):

  1. toml 运行
  2. [[
  3. runners
  4. ]]
  5. executor = "shell"

4. 高级配置

4.1 缓存优化

使用 S3 或 MinIO 作为分布式缓存:

  1. toml 运作
  2. [
  3. runners.cache
  4. ]
  5. Type = "s3"
  6. Path = "my-project-cache"
  7. Shared = true
  8. [
  9. runners.cache.s3
  10. ]
  11. ServerAddress = "minio.example.com:9000"
  12. AccessKey = "minio_access_key"
  13. SecretKey = "minio_secret_key"
  14. BucketName = "runner-cache"
  15. Insecure = true \# 使用 HTTP

4.2 镜像拉取加速

配置 Docker 镜像加速器:

  1. toml 运行
  2. [
  3. runners.docker
  4. ]
  5. image = "alpine:latest"
  6. registry_mirrors = ["https://registry.docker-cn.com"]

4.3 自定义 Hooks

在作业前后执行自定义脚本:

  1. toml 运行
  2. [[
  3. runners
  4. ]]
  5. pre_build_script = "echo 'Preparing environment...'"
  6. post_build_script = "echo 'Cleaning up...'"

5. Runner 管理命令

  1. bash 运行
  2. \# 查看状态
  3. sudo gitlab-runner status
  4. \# 重启 Runner
  5. sudo gitlab-runner restart
  6. \# 查看已注册的 Runner
  7. sudo gitlab-runner list
  8. \# 验证 Runner 配置
  9. sudo gitlab-runner verify
  10. \# 升级 Runner
  11. sudo gitlab-runner upgrade

6. 安全与权限

  • 最小权限原则:避免使用 privileged = true,确有需要时使用 cap_add 细化权限。
  • 隔离 Runner:为敏感项目创建专用 Runner,避免共享环境。
  • 定期更新:及时升级 Runner 以修复安全漏洞。
  • 加密通信:确保 Runner 与 GitLab 服务器通过 HTTPS 通信。

7. 监控与故障排除

  • 日志查看:

    1. bash 运行
    2. sudo journalctl -u gitlab-runner -f # 查看系统日志
  • 性能监控:

    • 使用 Prometheus 收集 Runner 指标

    • 配置 concurrent 参数避免资源过载

  • 本地调试:

    1. bash 运行
    2. gitlab-runner exec docker test\_job # 本地执行作业

8. 最佳实践

  • 按需扩展:使用 Auto Scaling Runner(如 AWS EC2、GKE)应对峰值负载。
  • 标签分类:为 Runner 添加标签(如 docker, gpu, heavy),通过 tags 字段在 .gitlab-ci.yml 中指定使用特定 Runner。
  • 版本对齐:保持 Runner 与 GitLab 版本一致(至少相差不超过 1 个 major 版本)。
  • 资源限制:为每个作业设置合理的 CPU/Memory 限制,避免相互影响。

四、故障排除

1. Pipeline 未触发

1.1可能原因

  • .gitlab-ci.yml 文件存在语法错误
  • 分支 / 标签不匹配触发规则(only/except 或 rules)
  • Runner 未在线或无可用执行器
  • 项目设置中禁用了 CI/CD

1.2排查步骤

  • 验证 YAML 语法
    • 在 GitLab 项目的 CI/CD 设置页面使用 CI Lint 工具检查语法
    • 本地安装 yamllint 进行静态检查
  • 检查触发规则

    1. yaml 运行
    2. \# 示例:仅在 main 分支和合并请求触发
    3. rules:
    4. - if: '$CI_COMMIT_BRANCH == "main" || $CI_PIPELINE_SOURCE == "merge_request_event"'
    5. when: always
  • 确认 Runner 状态

    • 在项目的 CI/CD 设置中查看 Runner 是否在线

    • 检查 Runner 日志:sudo journalctl -u gitlab-runner -f

2. 作业执行失败

2.1 命令执行错误

  • 现象:作业日志显示命令不存在或权限不足
  • 解决方案:

    • 确认镜像中是否包含所需工具(如 npm, python)
    • 使用 before_script 安装依赖:

      1. yaml 运行
      2. before_script:
      3. - apt-get update && apt-get install -y curl

2.2 依赖缓存问题

  • 现象:每次构建都重新下载依赖,耗时过长
  • 解决方案:

    1. yaml 运行
    2. cache:
    3. key: ${CI_COMMIT_REF_SLUG}
    4. paths:
    5. - node_modules/

2.3 网络连接超时

  • 现象:无法访问外部资源(如 GitHub、npm 仓库)
  • 解决方案:

    • 配置镜像源(如 npm、pip):

      1. yaml 运行
      2. before_script:
      3. - npm config set registry https://registry.npmmirror.com
    • 检查 Runner 网络配置,确保能访问公网

3. Runner 相关问题

3.1 Runner 未注册或离线

  • 解决方案:

    1. bash 运行
    2. \# 注册新 Runner
    3. sudo gitlab-runner register
    4. \# 检查状态
    5. sudo gitlab-runner status
    6. \# 重启 Runner
    7. sudo gitlab-runner restart

3.2 权限不足

  • 现象:作业无法访问文件或执行命令
  • 解决方案:
    • 确保 Runner 用户有足够权限
    • 避免使用 root 用户,通过 chmod 调整文件权限

3.3 磁盘空间不足

  • 解决方案:

    1. bash 运行
    2. \# 清理 Docker 镜像
    3. docker system prune -a
    4. \# 调整缓存过期时间
    5. artifacts:
    6. expire_in: 1 hour

4. Artifacts/Cache 问题

4.1 Artifacts 未传递

  • 现象:后续作业无法访问之前作业的 artifacts
  • 解决方案:

    • 确保 artifacts.paths 路径正确

    • 使用 dependencies 明确指定依赖的作业:

      1. yaml 运行
      2. test:
      3. dependencies:
      4. - build

4.2 Cache 失效

  • 现象:缓存未命中,重新下载依赖
  • 解决方案:

    • 使用稳定的缓存键(如 key: ${CI_PROJECT_ID}-npm)

    • 检查 cache.paths 是否与依赖路径匹配

5. Docker 执行器问题

5.1 镜像拉取失败

  • 现象:Failed to pull image 错误
  • 解决方案:

    1. yaml 运行
    2. \# 使用国内镜像源
    3. [runners.docker]
    4. registry_mirrors = ["https://registry.docker-cn.com"]

5.2 Docker-in-Docker (DinD) 问题

  • 现象:作业内无法运行 Docker 命令
  • 解决方案:

    1. yaml 运行
    2. \# 挂载 Docker 套接字
    3. services:
    4. - docker:dind
    5. variables:
    6. DOCKER_HOST: tcp://docker:2375
    7. DOCKER_TLS_CERTDIR: ""

6. Kubernetes 执行器问题

6.1 Pod 创建失败

  • 现象:Runner 无法创建 Pod 执行作业
  • 解决方案:

    1. bash 运行
    2. \# 检查集群连接
    3. kubectl get nodes
    4. \# 查看 Runner 权限配置
    5. kubectl get rolebindings -n gitlab-runner

6.2 资源不足

  • 现象:Pod 因资源不足被驱逐
  • 解决方案:

    1. yaml 运行
    2. \# 调整资源请求
    3. [runners.kubernetes]
    4. cpu_request = "500m"
    5. memory_request = "512Mi"

7. 高级调试技巧

7.1 本地执行作业

  1. bash 运行
  2. \# 使用 gitlab-runner 本地执行作业
  3. gitlab-runner exec docker test_job

7.2 使用 debug 模式

  1. yaml 运行
  2. \# .gitlab-ci.yml 中添加调试信息
  3. variables:
  4. CI_DEBUG_TRACE: "true"

7.3 分步调试

  1. yaml 运行
  2. \# 使用 allow\_failure 允许作业失败但不影响 Pipeline 状态
  3. test:
  4. script:
  5. - run-tests.sh
  6. allow_failure: true