GitLab CI/CD¶
一句话概述:GitLab CI/CD 是 GitLab 内置的持续集成/持续部署工具,通过
.gitlab-ci.yml定义流水线,从代码提交到部署上线一条龙自动化。
核心知识点¶
| 概念 | 白话解释 |
|---|---|
| Pipeline | 流水线 = 一次完整的 CI/CD 执行过程 |
| Stage | 阶段 = 流水线中的大步骤(如 build → test → deploy),按顺序执行 |
| Job | 作业 = 每个阶段里的具体任务,同阶段的作业并行运行 |
| Runner | 运行器 = 真正干活的机器,可以用 GitLab 共享的或自己搭 |
| Artifact | 产物 = 作业生成的文件,可传递给下游作业 |
| Cache | 缓存 = 跨作业复用的依赖文件(如 node_modules) |
| Variable | 变量 = 在流水线中传递配置信息 |
| Environment | 环境 = 部署目标(dev/staging/production) |
| Include | 引入 = 复用其他 YAML 配置片段 |
| DAG | 有向无环图 = 用 needs 打破阶段顺序,实现更灵活的依赖关系 |
安装配置¶
GitLab Runner 安装(自托管)¶
# Ubuntu/Debian 安装 GitLab Runner
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash # 添加仓库
sudo apt-get install gitlab-runner # 安装 Runner
# 注册 Runner(将 Runner 连接到你的 GitLab 项目)
sudo gitlab-runner register # 交互式注册
# 输入 GitLab 实例 URL(如 https://gitlab.com)
# 输入注册令牌(项目 Settings → CI/CD → Runners 中获取)
# 输入描述和标签
# 选择执行器(推荐 docker)
# Docker 方式运行 Runner
docker run -d \
--name gitlab-runner \ # 容器名
--restart always \ # 自动重启
-v /srv/gitlab-runner/config:/etc/gitlab-runner \ # 配置持久化
-v /var/run/docker.sock:/var/run/docker.sock \ # Docker-in-Docker
gitlab/gitlab-runner:latest # 使用最新镜像
基本 .gitlab-ci.yml¶
# .gitlab-ci.yml(放在项目根目录)
stages: # 定义阶段顺序
- build # 第1阶段:构建
- test # 第2阶段:测试
- deploy # 第3阶段:部署
variables: # 全局变量
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.pip-cache" # pip 缓存目录
build_job: # 构建作业
stage: build # 属于 build 阶段
image: python:3.12 # 使用 Python 3.12 Docker 镜像
script:
- pip install -r requirements.txt # 安装依赖
- python setup.py build # 构建项目
artifacts:
paths:
- dist/ # 保存构建产物
expire_in: 1 week # 产物保留1周
test_job: # 测试作业
stage: test # 属于 test 阶段
image: python:3.12
script:
- pip install -r requirements.txt
- pytest --cov=src # 运行测试
coverage: '/TOTAL.*\s+(\d+%)/' # 正则提取覆盖率
deploy_job: # 部署作业
stage: deploy
script:
- echo "Deploying..."
only:
- main # 只在 main 分支执行
when: manual # 手动触发部署
environment:
name: production # 部署到生产环境
url: https://example.com
基本使用¶
1. Python 项目完整流水线¶
stages:
- lint # 代码检查
- test # 单元测试
- build # 构建
- deploy # 部署
default:
image: python:3.12-slim # 默认镜像
cache:
key: ${CI_COMMIT_REF_SLUG} # 缓存键用分支名
paths:
- .pip-cache/ # 缓存 pip 下载
before_script: # 所有作业前执行
- pip install --cache-dir .pip-cache -r requirements.txt # 安装依赖
lint:
stage: lint
script:
- pip install ruff # 安装代码检查工具
- ruff check . # 检查代码风格
unit_test:
stage: test
script:
- pip install pytest pytest-cov # 安装测试工具
- pytest tests/ --cov=src --cov-report=html # 运行测试
artifacts:
reports:
coverage_report:
coverage_format: cobertura # GitLab 能识别的覆盖率格式
path: coverage.xml
paths:
- htmlcov/ # 保存 HTML 覆盖率报告
coverage: '/TOTAL.*\s+(\d+%)/'
build_package:
stage: build
script:
- python -m build # 构建 Python 包
artifacts:
paths:
- dist/*.whl # 保存 wheel 包
expire_in: 30 days
deploy_prod:
stage: deploy
script:
- pip install twine # 安装上传工具
- twine upload dist/* # 上传到 PyPI
only:
- tags # 只在打 tag 时部署
when: manual # 手动触发
2. 多环境部署¶
.deploy_template: &deploy # YAML 锚点,定义模板
stage: deploy
script:
- echo "Deploying to $ENV_NAME"
- ./deploy.sh $ENV_NAME # 执行部署脚本
deploy_dev:
<<: *deploy # 继承模板
variables:
ENV_NAME: development # 开发环境
environment:
name: development
only:
- develop # develop 分支自动部署
deploy_prod:
<<: *deploy
variables:
ENV_NAME: production
environment:
name: production
only:
- main
when: manual # 生产环境手动触发
高级用法¶
1. DAG 依赖(打破阶段限制)¶
stages:
- build
- test
- deploy
build_frontend:
stage: build
script: npm run build
build_backend:
stage: build
script: python -m build
test_frontend:
stage: test
needs: [build_frontend] # 只依赖前端构建,不等后端
script: npm test
test_backend:
stage: test
needs: [build_backend] # 只依赖后端构建,不等前端
script: pytest
deploy:
stage: deploy
needs: [test_frontend, test_backend] # 两个测试都过了才部署
script: ./deploy.sh
2. 引入外部配置(Include)¶
# 主 .gitlab-ci.yml
include:
- local: '.gitlab/ci/test.yml' # 引入本地文件
- project: 'group/shared-ci' # 引入其他项目的配置
file: '/templates/python.yml'
- template: Auto-DevOps.gitlab-ci.yml # 引入 GitLab 官方模板
3. 规则控制(Rules)¶
test_job:
script: pytest
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" # MR 时运行
- if: $CI_COMMIT_BRANCH == "main" # main 分支 push 时运行
- if: $CI_COMMIT_TAG # 打 tag 时运行
- changes: # 这些文件变了才运行
- src/**/*
- tests/**/*
常见报错¶
| 报错信息 | 原因 | 解决方法 |
|---|---|---|
This job is stuck | 没有可用的 Runner | 检查 Runner 是否在线,标签是否匹配 |
yaml invalid | YAML 语法错误 | 用 GitLab 的 CI Lint 工具检查 |
artifacts too large | 产物文件超限 | 减小产物大小或调整 expire_in |
ERROR: Job failed: exit code 1 | 脚本执行失败 | 查看日志定位具体报错 |
Cache not found | 缓存未命中 | 检查 key 是否匹配,路径是否正确 |
Permission denied | 权限不足 | 检查 Runner 执行器权限和变量权限 |
速查表¶
# === 关键字 ===
stages: [build, test, deploy] # 定义阶段
image: python:3.12 # Docker 镜像
script: [command1, command2] # 执行命令
before_script: [setup_cmd] # 作业前执行
after_script: [cleanup_cmd] # 作业后执行(即使失败也执行)
only: [main, tags] # 只在这些条件执行(旧语法)
except: [develop] # 排除这些条件(旧语法)
rules: [{if: '$CI == "true"'}] # 条件规则(新语法,推荐)
when: manual | always | on_failure # 触发方式
needs: [job_name] # DAG 依赖
allow_failure: true # 允许失败
retry: 2 # 失败重试次数
timeout: 30m # 超时时间
tags: [docker, linux] # Runner 标签筛选
# === 预定义变量 ===
$CI_COMMIT_SHA # 提交 SHA
$CI_COMMIT_BRANCH # 当前分支
$CI_COMMIT_TAG # 当前 tag
$CI_PROJECT_DIR # 项目目录
$CI_PIPELINE_ID # 流水线 ID
$CI_JOB_TOKEN # 作业令牌
$CI_MERGE_REQUEST_IID # MR 编号
# === 常用模式 ===
# 缓存
cache:
key: ${CI_COMMIT_REF_SLUG}
paths: [.pip-cache/]
# 产物
artifacts:
paths: [dist/]
expire_in: 1 week
# 环境
environment:
name: production
url: https://example.com
参考:GitLab CI/CD 文档 | 更新于 2026 年