{{< details >}}
- Tier: 基础版, 专业版, 旗舰版
- Offering: JihuLab.com, 私有化部署
{{< /details >}}
这篇教程将指导你通过小而迭代的步骤配置一个越来越复杂的 CI/CD 流水线。流水线始终是完全功能的,但它在每个步骤中获得更多的功能。目标是构建、测试和部署一个文档站点。
完成本教程后,你将在 JihuLab.com 上有一个新项目,并使用 Docusaurus 运行一个文档站点。
要完成本教程,你需要:
- 创建一个项目来保存 Docusaurus 文件
- 创建初始的流水线配置文件
- 添加一个任务来构建站点
- 添加一个任务来部署站点
- 添加测试任务
- 开始使用合并请求流水线
- 减少重复的配置
前提条件
- 你需要在 JihuLab.com 上有一个账户。
- 你应该熟悉 Git。
- Node.js 必须安装在你的本地机器上。例如,在 macOS 上,你可以使用
brew install node
安装 Node。
创建一个项目来保存 Docusaurus 文件
在添加流水线配置之前,必须首先在 JihuLab.com 上设置一个 Docusaurus 项目:
- 在你的用户名下创建一个新项目(而不是群组):
- 在左侧边栏顶部,选择 创建新项目 ({{< icon name=”plus” >}}) 和 新项目/仓库。
- 选择 创建空白项目。
- 输入项目详情:
- 在 项目名称 字段中,输入你的项目名称,例如
My Pipeline Tutorial Project
。 - 选择 用 README 初始化仓库。
- 在 项目名称 字段中,输入你的项目名称,例如
- 选择 创建项目。
-
在项目的概览页面右上角,选择 代码 以找到项目的克隆路径。复制 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 配置文件以包含你的极狐GitLab 项目的详细信息。在
docusaurus.config.js
中:- 设置
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 可用于运行任务。
此步骤介绍:
- 任务:这些是流水线中运行命令的独立部分。任务在极狐GitLab 实例之外的 runner 上运行。
-
script
:这是任务配置的一个部分,在这里你定义任务的命令。如果有多个命令(在数组中),它们会按顺序运行。每个命令的执行就像在 CLI 命令中运行一样。默认情况下,如果命令失败或返回错误,任务会标记为失败并且不会再运行更多命令。
在此步骤中,在项目的根目录创建一个 .gitlab-ci.yml
文件,配置如下:
test-job:
script:
- echo "This is my first job!"
- date
提交并推送此更改到极狐GitLab,然后:
- 转到 构建 > 流水线 并确保在极狐GitLab 中运行一个包含该单一任务的流水线。
- 选择流水线,然后选择任务以查看任务日志,并看到
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 项目,并且node
镜像内置了所需的npm
命令。 - 运行
npm install
以将 Docusaurus 安装到正在运行的node
容器中,然后运行npm run build
以构建站点。 - Docusaurus 将构建的站点保存在
build/
中,因此用artifacts
保存这些文件。
build-job:
image: node
script:
- npm install
- npm run build
artifacts:
paths:
- "build/"
使用流水线编辑器将此流水线配置提交到默认分支,并检查任务日志。你可以:
- 查看运行的
npm
命令并构建站点。 - 验证产物是否在最后保存。
- 在任务日志完成后,通过选择任务日志右侧的 浏览 来浏览产物文件的内容。
添加一个任务来部署站点
在验证 Docusaurus 站点在 build-job
中构建后,你可以添加一个任务来部署它。
此步骤介绍:
-
stage
和stages
:最常见的流水线配置将任务分组到阶段中。处于同一阶段的任务可以并行运行,而后续阶段的任务则等待前一阶段的任务完成。如果一个任务失败,则整个阶段被视为失败,并且后续阶段的任务不会开始运行。 - 极狐GitLab Pages:要托管你的静态站点,你将使用极狐GitLab Pages。
在此步骤中:
- 添加一个任务来获取已构建的站点并部署它。使用极狐GitLab Pages 时,任务总是命名为
pages
。来自build-job
的产物会自动提取并解压缩到任务中。Pages 在public/
目录中寻找站点,因此添加一个script
命令以将站点移动到该目录。 - 添加一个
stages
部分,并为每个任务定义阶段。build-job
首先在build
阶段运行,而pages
在之后的deploy
阶段运行。
stages: # 为任务和它们的执行顺序列出阶段
- build
- deploy
build-job:
stage: build # 将该任务设置为在 `build` 阶段运行
image: node
script:
- npm install
- npm run build
artifacts:
paths:
- "build/"
pages:
stage: deploy # 将这个新任务设置为在 `deploy` 阶段运行
script:
- mv build/ public/
artifacts:
paths:
- "public/"
使用流水线编辑器将此流水线配置提交到默认分支,并从 流水线 列表中查看流水线详细信息。验证:
- 两个任务在不同阶段运行,分别是
build
和deploy
。 - 在
pages
任务完成后出现一个pages:deploy
任务,这是极狐GitLab 部署 Pages 站点的过程。当该任务完成时,你可以访问你的新 Docusaurus 站点。
要查看你的站点:
- 在左侧边栏,选择 部署 > Pages。
- 确保 使用唯一域名 处于关闭状态。
- 在 访问页面 下,选择链接。URL 格式应类似于:
https://<my-username>.gitlab.io/<project-name>
。有关更多信息,请参见 极狐GitLab Pages 默认域名。
{{< alert type=”note” >}}
如果你需要 使用唯一域名,在 docusaurus.config.js
中,将 baseUrl:
设置为 /
。
{{< /alert >}}
添加测试任务
现在站点已经按照预期构建和部署,你可以添加测试和代码检查。例如,一个 Ruby 项目可能会运行 RSpec 测试任务。Docusaurus 是一个使用 Markdown 和生成 HTML 的静态站点,因此本教程添加了测试 Markdown 和 HTML 的任务。
此步骤介绍:
-
allow_failure
:间歇性失败或预计会失败的任务可能会降低生产率或难以排除故障。使用allow_failure
来让任务失败而不停止流水线执行。 -
dependencies
:使用dependencies
控制单个任务中的产物下载,通过列出要从中获取产物的任务。
在此步骤中:
- 添加一个在
build
和deploy
之间运行的新test
阶段。这三个阶段是配置中未定义stages
时的默认阶段。 - 添加一个
lint-markdown
任务来运行 markdownlint 并检查项目中的 Markdown。markdownlint 是一个静态分析工具,检查你的 Markdown 文件是否遵循格式标准。- Docusaurus 生成的示例 Markdown 文件位于
blog/
和docs/
中。 - 此工具仅扫描原始 Markdown 文件,不需要在
build-job
产物中保存的生成 HTML。通过dependencies: []
加快任务速度,以便它不获取任何产物。 - 一些示例 Markdown 文件违反了默认的 markdownlint 规则,因此添加
allow_failure: true
以便流水线继续执行尽管规则违反。
- Docusaurus 生成的示例 Markdown 文件位于
- 添加一个
test-html
任务来运行 HTMLHint 并检查生成的 HTML。HTMLHint 是一个静态分析工具,扫描生成的 HTML 以查找已知问题。 -
test-html
和pages
都需要在build-job
产物中找到的生成 HTML。任务默认从所有早期阶段的任务中获取产物,但添加dependencies:
以确保任务在后续流水线更改后不会意外下载其他产物。
stages:
- build
- test # 添加一个 `test` 阶段用于测试任务
- deploy
build-job:
stage: build
image: node
script:
- npm install
- npm run build
artifacts:
paths:
- "build/"
lint-markdown:
stage: test
image: node
dependencies: [] # 不获取任何产物
script:
- npm install markdownlint-cli2 --global # 将 markdownlint 安装到容器中
- markdownlint-cli2 -v # 验证版本,对于故障排除很有用
- markdownlint-cli2 "blog/**/*.md" "docs/**/*.md" # 检查 blog/ 和 docs/ 中的所有 markdown 文件
allow_failure: true # 该任务目前失败,但不要让它停止流水线。
test-html:
stage: test
image: node
dependencies:
- build-job # 仅从 `build-job` 获取产物
script:
- npm install --save-dev htmlhint # 将 HTMLHint 安装到容器中
- npx htmlhint --version # 验证版本,对于故障排除很有用
- npx htmlhint build/ # 检查 blog/ 和 docs/ 中的所有 markdown 文件
pages:
stage: deploy
dependencies:
- build-job # 仅从 `build-job` 获取产物
script:
- mv build/ public/
artifacts:
paths:
- "public/"
将此流水线配置提交到默认分支,并查看流水线详细信息。
-
lint-markdown
任务失败,因为示例 Markdown 违反了默认的 markdownlint 规则,但允许失败。你可以:- 暂时忽略违规行为。它们不需要在教程中修复。
- 修复 Markdown 文件违规行为。然后你可以将
allow_failure
更改为false
,或者完全删除allow_failure
,因为allow_failure: false
是未定义时的默认行为。 - 添加一个 markdownlint 配置文件以限制哪些规则违规需要警报。
- 你还可以对 Markdown 文件内容进行更改,并在下次部署后在站点上查看更改。
开始使用合并请求流水线
使用上述的流水线配置,站点每次流水线成功完成时都会部署,但这不是理想的开发工作流程。更好的方法是使用功能分支和合并请求,只有在更改合并到默认分支时才部署站点。
此步骤介绍:
-
rules
:为每个任务添加规则以配置其运行的流水线。你可以配置任务在 合并请求流水线、计划流水线 或其他特定情况下运行。规则从上到下进行评估,如果规则匹配,任务就会被添加到流水线。 -
CI/CD 变量:使用这些环境变量在配置文件和脚本命令中配置任务行为。预定义的 CI/CD 变量 是你不需要手动定义的变量。它们会自动注入到流水线中,因此你可以使用它们来配置你的流水线。变量通常格式化为
$VARIABLE_NAME
,预定义变量通常以$CI_
为前缀。
在此步骤中:
- 创建一个新的功能分支,并在该分支中进行更改而不是在默认分支中。
- 为每个任务添加
rules
:- 站点应仅为默认分支的更改部署。
- 其他任务应在合并请求或默认分支的所有更改上运行。
- 使用此流水线配置,你可以从功能分支工作而不运行任何任务,从而节省资源。当你准备验证更改时,创建一个合并请求,流水线会运行配置为在合并请求中运行的任务。
- 当你的合并请求被接受并且更改合并到默认分支时,会运行一个新的流水线,其中还包含
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' # 为合并请求的源分支的所有更改运行
- if: $CI_COMMIT_BRANCH == $CI_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' # 为合并请求的源分支的所有更改运行
- if: $CI_COMMIT_BRANCH == $CI_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' # 为合并请求的源分支的所有更改运行
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # 为默认分支的所有更改运行
pages:
stage: deploy
dependencies:
- build-job
script:
- mv build/ public/
artifacts:
paths:
- "public/"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # 仅为默认分支的所有更改运行
合并你的合并请求中的更改。此操作更新默认分支。验证新流水线包含部署站点的 pages
任务。
请确保为流水线配置的所有未来更改使用功能分支和合并请求。其他项目更改,例如创建 Git 标签或添加流水线计划,不会触发流水线,除非你为这些情况也添加规则。
减少重复的配置
流水线现在包含三个任务,它们都有相同的 rules
和 image
配置。与其重复这些规则,不如使用 extends
和 default
创建单一的事实来源。
此步骤介绍:
-
隐藏任务:以
.
开头的任务永远不会被添加到流水线中。使用它们来保存你想重复使用的配置。 -
extends
:使用 extends 在多个地方重复配置,通常从隐藏任务中获取。如果你更新隐藏任务的配置,所有扩展隐藏任务的任务都会使用更新后的配置。 -
default
:设置默认关键字,这些关键字适用于所有未定义的任务。 - YAML 覆盖:在使用
extends
或default
重用配置时,你可以在任务中显式定义一个关键字来覆盖extends
或default
配置。
在此步骤中:
- 添加一个
.standard-rules
隐藏任务来保存在build-job
、lint-markdown
和test-html
中重复的规则。 - 使用
extends
在三个任务中重用.standard-rules
配置。 - 添加一个
default
部分以将image
默认值定义为node
。 -
pages
部署任务不需要默认的node
镜像,因此显式使用busybox
,一个极其小巧且快速的镜像。
stages:
- build
- test
- deploy
default: # 添加一个默认部分以定义 `image` 关键字的默认值
image: node
.standard-rules: # 创建一个隐藏任务以保存通用规则
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
build-job:
extends:
- .standard-rules # 在这里重用 `.standard-rules` 中的配置
stage: build
script:
- npm install
- npm run build
artifacts:
paths:
- "build/"
lint-markdown:
stage: test
extends:
- .standard-rules # 在这里重用 `.standard-rules` 中的配置
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 # 在这里重用 `.standard-rules` 中的配置
dependencies:
- build-job
script:
- npm install --save-dev htmlhint
- npx htmlhint --version
- npx htmlhint build/
pages:
stage: deploy
image: busybox # 用 `busybox` 覆盖默认的 `image` 值
dependencies:
- build-job
script:
- mv build/ public/
artifacts:
paths:
- "public/"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
使用合并请求将此流水线配置提交到默认分支。文件更简单,但它应该与前一步具有相同的行为。
你刚刚创建了一个完整的流水线并使其更加高效。做得好!现在你可以利用这些知识,了解 .gitlab-ci.yml
关键字的其余部分,在 CI/CD YAML 语法参考 中构建自己的流水线。