教程:创建复杂流水线
- Tier: Free, Premium, Ultimate
- Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
本教程将通过小而渐进的步骤,指导您配置一个逐渐复杂的 CI/CD 流水线。流水线始终保持完全可用,但每一步都会增加更多功能。目标是构建、测试和部署一个文档站点。
完成本教程后,您将在 GitLab.com 上拥有一个新项目,并有一个使用 Docusaurus 的工作文档站点。
要完成本教程,您需要:
- 创建一个项目来存放 Docusaurus 文件
- 创建初始的流水线配置文件
- 添加一个构建站点的任务
- 添加一个部署站点的任务
- 添加测试任务
- 开始使用合并请求流水线
- 减少重复的配置
前置条件
- 您需要一个 GitLab.com 账户。
- 您应该熟悉 Git。
- 您的本地机器必须安装 Node.js。例如,在 macOS 上,您可以使用
brew install node安装 node。
创建一个项目来存放 Docusaurus 文件
在添加流水线配置之前,您必须先在 GitLab.com 上设置一个 Docusaurus 项目:
-
在您的用户名下创建一个新项目(不是组):
- 在左侧边栏顶部,选择 创建新( )和 新项目/仓库。
- 选择 创建空白项目。
- 输入项目详情:
- 在 项目名称 字段中,输入您的项目名称,例如
My Pipeline Tutorial Project。 - 选择 使用 README 初始化仓库。
- 在 项目名称 字段中,输入您的项目名称,例如
- 选择 创建项目。
-
在项目概览页面的右上角,选择 代码 来查找您项目的克隆路径。复制 SSH 或 HTTP 路径,并使用该路径在本地克隆项目。
例如,使用 SSH 克隆到您计算机上的
pipeline-tutorial目录:git clone [email protected]:my-username/my-pipeline-tutorial-project.git pipeline-tutorial -
切换到项目目录,然后生成一个新的 Docusaurus 站点:
cd pipeline-tutorial npm init docusaurusDocusaurus 初始化向导会提示您有关站点的问题。使用所有默认选项。
-
初始化向导在
website/中设置站点,但站点应该在项目根目录。将文件移动到根目录并删除旧目录:mv website/* . rm -r website -
使用您的 GitLab 项目详细信息更新 Docusaurus 配置文件。在
docusaurus.config.js中:- 将
url:设置为此格式的路径:https://<my-username>.gitlab.io/。 - 将
baseUrl:设置为您的项目名称,如/my-pipeline-tutorial-project/。
- 将
-
提交更改,并将其推送到 GitLab:
git add . git commit -m "添加简单的生成 Docusaurus 站点" git push origin
创建初始的 CI/CD 配置文件
从最简单的流水线配置文件开始,确保项目启用了 CI/CD 并且有可用的 runner 来运行任务。
这一步介绍:
- Jobs:这些是流水线的独立部分,运行您的命令。任务在 runners 上运行,与 GitLab 实例分开。
script:这是任务配置的一部分,您在这里定义任务的命令。如果有多个命令(在数组中),它们按顺序运行。每个命令都像作为 CLI 命令运行一样执行。默认情况下,如果命令失败或返回错误,任务将被标记为失败,并且不再运行更多命令。
在这一步中,在项目根目录创建一个 .gitlab-ci.yml 文件,包含以下配置:
test-job:
script:
- echo "这是我的第一个任务!"
- date将此更改提交并推送到 GitLab,然后:
- 转到 构建 > 流水线,并确保在 GitLab 中运行了一个包含此单个任务的流水线。
- 选择流水线,然后选择任务以查看任务日志,并看到
这是我的第一个任务!消息,后跟日期。
现在您的项目中有了 .gitlab-ci.yml 文件,您可以使用 流水线编辑器 对所有未来的流水线配置更改。
添加一个构建站点的任务
CI/CD 流水线的常见任务是构建项目中的代码,然后部署它。首先添加一个构建站点的任务。
这一步介绍:
image:告诉 runner 使用哪个 Docker 容器来运行任务。runner:- 下载容器镜像并启动它。
- 将您的 GitLab 项目克隆到正在运行的容器中。
- 逐个运行
script命令。
artifacts:任务是独立的,彼此不共享资源。如果您希望在一个任务中生成的文件在另一个任务中使用,必须先将它们保存为 artifacts。然后后续任务可以检索 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命令运行并构建站点。 - 验证 artifacts 在末尾是否被保存。
- 通过在任务完成后选择日志右侧的 浏览 来浏览 artifacts 文件的内容。
添加一个部署站点的任务
在验证 Docusaurus 站点在 build-job 中构建后,您可以添加一个部署它的任务。
这一步介绍:
stage和stages:最常见的流水线配置将任务分组到阶段中。同一阶段中的任务可以并行运行,而后续阶段的任务会等待前一阶段的任务完成。如果任务失败,整个阶段被视为失败,后续阶段的任务不会开始运行。- GitLab Pages:要托管您的静态站点,您将使用 GitLab Pages。
在这一步中:
- 添加一个获取构建站点并部署它的任务。使用 GitLab Pages 时,任务始终命名为
pages。build-job的 artifacts 会自动获取并解压到任务中。但是 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任务,这是部署 Pages 站点的 GitLab 进程。当该任务完成后,您可以访问您的新 Docusaurus 站点。
要查看您的站点:
- 在左侧边栏,选择 部署 > Pages。
- 确保 使用唯一域名 已关闭。
- 在 访问页面 下,选择链接。URL 格式应类似于:
https://<my-username>.gitlab.io/<project-name>。更多信息,请参见 GitLab Pages 默认域名。
如果您需要 使用唯一域名,在 docusaurus.config.js 中,将 baseUrl: 设置为 /。
添加测试任务
现在站点按预期构建和部署,您可以添加测试和代码检查。例如,Ruby 项目可能会运行 RSpec 测试任务。Docusaurus 是一个使用 Markdown 和生成 HTML 的静态站点,因此本教程添加了测试 Markdown 和 HTML 的任务。
这一步介绍:
allow_failure:间歇性失败或预期失败的任务可能会降低生产力或难以排查。使用allow_failure让任务失败而不停止流水线执行。dependencies:使用dependencies通过列出要从哪些任务获取 artifacts 来控制单个任务中的 artifact 下载。
在这一步中:
- 添加一个新的
test阶段,在build和deploy之间运行。当配置中未定义stages时,这三个阶段是默认阶段。 - 添加一个
lint-markdown任务来运行 markdownlint 并检查您项目中的 Markdown。markdownlint 是一个静态分析工具,检查您的 Markdown 文件是否符合格式标准。- Docusaurus 生成的示例 Markdown 文件在
blog/和docs/中。 - 此工具仅扫描原始 Markdown 文件,不需要
build-jobartifacts 中保存的生成 HTML。使用dependencies: []加速任务,使其不获取任何 artifacts。 - 一些示例 Markdown 文件违反了默认 markdownlint 规则,因此添加
allow_failure: true让流水线继续执行,尽管存在规则违规。
- Docusaurus 生成的示例 Markdown 文件在
- 添加一个
test-html任务来运行 HTMLHint 并检查生成的 HTML。HTMLHint 是一个静态分析工具,扫描生成的 HTML 以查找已知问题。 test-html和pages都需要build-jobartifacts 中找到的生成 HTML。默认情况下,任务从之前阶段的所有任务获取 artifacts,但添加dependencies:确保任务不会在未来流水线更改后意外下载其他 artifacts。
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: [] # 不获取任何 artifacts
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` 获取 artifacts
script:
- npm install --save-dev htmlhint # 将 HTMLHint 安装到容器中
- npx htmlhint --version # 验证版本,有助于故障排除
- npx htmlhint build/ # 检查 blog/ 和 docs/ 中的所有 markdown 文件
pages:
stage: deploy
dependencies:
- build-job # 仅从 `build-job` 获取 artifacts
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: # 添加一个 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使用合并请求将此流水线配置提交到默认分支。文件更简单,但应该与上一步具有相同的行为。
您刚刚创建了一个完整的流水线并将其简化以提高效率。做得很好!现在您可以利用这些知识,了解 CI/CD YAML 语法参考 中的其余 .gitlab-ci.yml 关键字,并构建您自己的流水线。