适用层级:Free、Premium、Ultimate。适用部署:GitLab.com、GitLab Self-Managed、GitLab Dedicated。
本教程通过小步迭代,逐渐配置一条更复杂的 CI/CD 流水线。每一步的流水线都可完整运行,只是在前一步基础上增加能力。最终目标是构建、测试并部署一个文档网站。
完成后,你会拥有一个新的 GitLab.com 项目,以及一个基于 Docusaurus 的可运行文档站点。
教程包括以下步骤:
- 创建存放 Docusaurus 文件的项目。
- 创建初始流水线配置文件。
- 添加构建站点的作业。
- 添加部署站点的作业。
- 添加测试作业。
- 开始使用合并请求流水线。
- 减少重复配置。
前提条件
- 拥有 GitLab.com 账户。
- 熟悉 Git。
- 本机已经安装 Node.js。例如在 macOS 上,可运行
brew install node安装。
创建存放 Docusaurus 文件的项目
添加流水线配置前,先在 GitLab.com 上准备 Docusaurus 项目:
- 在自己的用户名下创建新项目,而不是在群组中创建。点击右上角“新建”(Create new,加号图标),选择“新建项目/仓库”(New project/repository)。
- 选择“创建空白项目”(Create blank project)。
- 填写项目详情。在 Project name 中输入名称,例如
My Pipeline Tutorial Project;勾选“使用 README 初始化仓库”(Initialize repository with a README);点击“创建项目”(Create project)。 - 在项目概览页面右上角点击“代码”(Code),复制 SSH 或 HTTP 克隆地址,并将项目克隆到本地。例如,下面使用 SSH 克隆到本机的
pipeline-tutorial目录:
git clone git@gitlab.com:my-username/my-pipeline-tutorial-project.git pipeline-tutorial
进入项目目录,生成一个新的 Docusaurus 网站:
cd pipeline-tutorial
npm init docusaurus
Docusaurus 初始化向导会询问站点配置,此处全部使用默认选项。
向导将网站放在 website/ 中,但本教程需要网站位于项目根目录。把文件上移一级,然后删除旧目录:
mv website/* .
rm -r website
在 docusaurus.config.js 中填写 GitLab 项目信息:
- 将
url:设为https://<my-username>.gitlab.io/形式。 - 将
baseUrl:设为项目名称对应的路径,例如/my-pipeline-tutorial-project/。
提交修改并推送到 GitLab:
git add .
git commit -m "Add simple generated Docusaurus site"
git push origin
创建初始 CI/CD 配置文件
先使用尽可能简单的流水线配置,确认项目启用了 CI/CD,且存在可运行作业的 runner。
本步骤引入两个概念:
- 作业(Jobs):流水线中相互独立、负责执行命令的单元。作业运行在 runner 上,runner 与 GitLab 实例分离。
script:定义作业要执行的命令。以数组形式提供多个命令时,会按顺序执行,每条命令都像在命令行中执行一样。默认情况下,如果某条命令失败或返回错误,作业会标记为失败,剩余命令不再运行。
在项目根目录创建 .gitlab-ci.yml,内容如下:
test-job:
script:
- echo "This is my first job!"
- date
提交并推送到 GitLab,然后:
- 进入“构建 → 流水线”(Build → Pipelines),确认只有这一个作业的流水线开始运行。
- 打开流水线,再打开作业日志,应该能看到
This is my first job!,随后是日期。
项目已有 .gitlab-ci.yml 后,后续流水线配置修改都可以通过流水线编辑器进行。
添加构建站点的作业
CI/CD 的常见工作是先构建代码,再部署。首先添加用于构建网站的作业。
本步骤引入:
image:告诉 runner 用哪个 Docker 镜像运行作业。runner 会下载并启动容器,把 GitLab 项目克隆进容器,然后依次执行script命令。artifacts:作业彼此独立,不共享资源。如果希望在一个作业中生成的文件被另一个作业使用,必须先将其保存为构件,后续作业才能下载这些文件。
把 test-job 替换为 build-job:
- 通过
image使用最新的node镜像。Docusaurus 是 Node.js 项目,该镜像已经包含所需的 npm 命令。 - 运行
npm install,在正在运行的 node 容器中安装 Docusaurus 依赖;随后运行npm run build构建站点。 - Docusaurus 将输出保存到
build/,将此目录保存为 artifacts。
build-job:
image: node
script:
- npm install
- npm run build
artifacts:
paths:
- "build/"
使用流水线编辑器把配置提交到默认分支,然后查看作业日志。你可以看到 npm 命令执行及网站构建过程,确认结束时构件已保存,并在作业完成后点击日志右侧的“浏览”(Browse),查看构件文件内容。
添加部署站点的作业
确认 build-job 能构建 Docusaurus 站点后,再添加部署作业。
本步骤引入:
stage和stages:常见流水线配置会将作业划分到不同阶段。同一阶段的作业可以并行运行,后面的阶段必须等前面的阶段完成。如果一个作业失败,整个阶段会被视为失败,后续阶段不再开始。- GitLab Pages:用于托管静态网站。
添加一个获取构建结果并部署的作业。原文示例使用名为 pages 的 GitLab Pages 作业。build-job 的构件会自动被下载并解压到该作业中。由于 Pages 从 public/ 读取网站,脚本需要将构建结果移动到此目录。
添加 stages 并为作业指定阶段:build-job 先在 build 阶段运行,pages 随后在 deploy 阶段运行。
stages: # List of stages for jobs and their order of execution
- build
- deploy
build-job:
stage: build # Set this job to run in the `build` stage
image: node
script:
- npm install
- npm run build
artifacts:
paths:
- "build/"
pages:
stage: deploy # Set this new job to run in the `deploy` stage
script:
- mv build/ public/
artifacts:
paths:
- "public/"
通过流水线编辑器将配置提交到默认分支,再从流水线列表打开详情,确认:
- 两个作业分别在
build和deploy阶段运行。 pages完成后出现pages:deploy作业,这是 GitLab 部署 Pages 站点的内部过程。该作业完成后,就可以访问新的 Docusaurus 网站。
访问网站:
- 在左侧边栏进入“部署 → Pages”(Deploy → Pages)。
- 确保“使用唯一域名”(Use unique domain)已关闭。
- 在“访问 Pages”(Access pages)下点击链接。地址形式应类似
https://<my-username>.gitlab.io/<project-name>。更多说明见 GitLab Pages 默认域名文档。
如果必须使用唯一域名,则在 docusaurus.config.js 中把 baseUrl: 设为 /。
添加测试作业
网站构建和部署正常后,可以增加测试与 lint 检查。例如 Ruby 项目可能运行 RSpec;Docusaurus 主要使用 Markdown 和生成的 HTML,因此本教程检查这两类文件。
本步骤引入:
allow_failure:间歇性失败或预期会失败的作业,可能降低效率或难以排查。设置该项可以允许作业失败,同时不停止整个流水线。dependencies:列出要从哪些作业下载构件,从而控制每个作业的构件下载行为。
按以下方式扩展流水线:
- 在
build和deploy之间添加test阶段。如果配置未定义stages,这三个阶段就是默认阶段。 - 添加
lint-markdown,运行 markdownlint 检查 Markdown 格式。Docusaurus 生成的示例 Markdown 位于blog/和docs/。该工具只扫描原始 Markdown,不需要build-job生成的 HTML,因此使用dependencies: []避免下载构件,加快作业。部分示例文件违反默认规则,所以先设置allow_failure: true,让流水线仍能继续。 - 添加
test-html,运行 HTMLHint 检查生成的 HTML 是否存在已知问题。 test-html和pages都需要build-job的 HTML 构件。默认会下载所有前置阶段作业的构件,但这里显式设置dependencies,避免后续修改流水线时意外下载其他构件。
stages:
- build
- test # Add a `test` stage for the test jobs
- deploy
build-job:
stage: build
image: node
script:
- npm install
- npm run build
artifacts:
paths:
- "build/"
lint-markdown:
stage: test
image: node
dependencies: [] # Don't fetch any artifacts
script:
- npm install markdownlint-cli2 --global # Install markdownlint into the container
- markdownlint-cli2 -v # Verify the version, useful for troubleshooting
- markdownlint-cli2 "blog/**/*.md" "docs/**/*.md" # Lint all markdown files in blog/ and docs/
allow_failure: true # This job fails right now, but don't let it stop the pipeline.
test-html:
stage: test
image: node
dependencies:
- build-job # Only fetch artifacts from `build-job`
script:
- npm install --save-dev htmlhint # Install HTMLHint into the container
- npx htmlhint --version # Verify the version, useful for troubleshooting
- npx htmlhint build/ # Lint all markdown files in blog/ and docs/
pages:
stage: deploy
dependencies:
- build-job # Only fetch artifacts from `build-job`
script:
- mv build/ public/
artifacts:
paths:
- "public/"
把配置提交到默认分支并查看流水线详情。lint-markdown 会因示例 Markdown 违反默认规则而失败,但这是被允许的。对此可以:
- 暂时忽略,这些格式问题不要求在教程中修复。
- 修复 Markdown 格式,再将
allow_failure改为false,或者直接删掉,因为未定义时默认就是false。 - 添加 markdownlint 配置文件,限制需要报告哪些规则。
也可以修改 Markdown 内容,并在下一次部署后查看网站变化。
开始使用合并请求流水线
此前配置会在每次流水线成功后部署网站,这并不是理想的开发流程。更合适的方式是使用功能分支和合并请求,只在变更合并到默认分支时部署。
本步骤引入:
rules:为每个作业规定在哪些流水线中运行,例如合并请求、计划任务或其他情形。规则自上而下匹配,匹配后就将作业加入流水线。- CI/CD 变量:可在配置文件和脚本命令中使用环境变量控制行为。预定义变量由流水线自动注入,无需手动创建。变量通常写为
$VARIABLE_NAME,预定义变量通常以$CI_开头。
新建一个功能分支,在该分支而不是默认分支上修改配置。为各个作业添加规则:网站仅针对默认分支的变更部署;其他作业则在合并请求或默认分支有变更时运行。
这样,在功能分支上工作时可以不运行作业,节省资源。准备验证变更时创建合并请求,即会启动相应作业。合并请求被接受并合并到默认分支后,再启动包含 pages 的新流水线;只要没有阻止执行的失败,就会部署站点。
stages:
- build
- test
- deploy
build-job:
stage: build
image: node
script:
- npm install
- npm run build
artifacts:
paths:
- "build/"
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event' # Run for all changes to a merge request's source branch
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run for all changes to the default branch
lint-markdown:
stage: test
image: node
dependencies: []
script:
- npm install markdownlint-cli2 --global
- markdownlint-cli2 -v
- markdownlint-cli2 "blog/**/*.md" "docs/**/*.md"
allow_failure: true
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event' # Run for all changes to a merge request's source branch
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run for all changes to the default branch
test-html:
stage: test
image: node
dependencies:
- build-job
script:
- npm install --save-dev htmlhint
- npx htmlhint --version
- npx htmlhint build/
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event' # Run for all changes to a merge request's source branch
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run for all changes to the default branch
pages:
stage: deploy
dependencies:
- build-job
script:
- mv build/ public/
artifacts:
paths:
- "public/"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run for all changes to the default branch only
合并该合并请求,以更新默认分支,然后确认新流水线包含部署网站的 pages 作业。
之后修改流水线配置时,都应使用功能分支和合并请求。创建 Git 标签、添加定时流水线等其他项目操作,不会触发这里的流水线,除非再为这些情形添加规则。
减少重复配置
目前有三个作业使用完全相同的 rules 和 image 配置。可以通过 extends 和 default 集中定义,避免重复。
本步骤引入:
- 隐藏作业:名称以
.开头的作业不会加入流水线,可用来保存希望复用的配置。 extends:在多个位置复用配置,通常复用隐藏作业。隐藏作业更新后,所有继承它的作业都会使用新配置。default:为未显式定义相应关键字的作业设置默认值。- YAML 覆盖:复用配置时,可以在具体作业中显式设置关键字,覆盖
extends或default的值。
具体调整如下:
- 添加隐藏作业
.standard-rules,存放build-job、lint-markdown和test-html重复使用的规则。 - 在这三个作业中通过
extends继承.standard-rules。 - 添加
default,将默认image设为node。 pages不需要默认 node 镜像,因此显式使用体积很小、启动快速的busybox。
stages:
- build
- test
- deploy
default: # Add a default section to define the `image` keyword's default value
image: node
.standard-rules: # Make a hidden job to hold the common rules
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
build-job:
extends:
- .standard-rules # Reuse the configuration in `.standard-rules` here
stage: build
script:
- npm install
- npm run build
artifacts:
paths:
- "build/"
lint-markdown:
stage: test
extends:
- .standard-rules # Reuse the configuration in `.standard-rules` here
dependencies: []
script:
- npm install markdownlint-cli2 --global
- markdownlint-cli2 -v
- markdownlint-cli2 "blog/**/*.md" "docs/**/*.md"
allow_failure: true
test-html:
stage: test
extends:
- .standard-rules # Reuse the configuration in `.standard-rules` here
dependencies:
- build-job
script:
- npm install --save-dev htmlhint
- npx htmlhint --version
- npx htmlhint build/
pages:
stage: deploy
image: busybox # Override the default `image` value with `busybox`
dependencies:
- build-job
script:
- mv build/ public/
artifacts:
paths:
- "public/"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
通过合并请求将配置提交到默认分支。文件变得更简洁,但行为应与前一步相同。
至此,你已经建立了一条完整流水线,并对其配置做了精简。接下来可阅读 CI/CD YAML 语法参考,了解 .gitlab-ci.yml 的其他关键字,构建自己的流水线。
原文:Tutorial: Create a complex pipeline。本文为该文档的中文译文,示例代码保留原文。











暂无评论内容