随着应用程序及其存储库结构的复杂性增加,存储库中.gitlab-ci.yml
文件变得难以管理。对于越来越流行的“ monorepo ”模式,此问题尤其重要,在该模式下,团队将用于多个相关服务的代码保存在一个存储库中。当前,当使用这种模式时,开发人员都使用同一.gitlab-ci.yml
文件来为不同的应用程序组件触发不同的自动化过程,这可能会导致合并冲突和生产率下降,而团队则在等待管道“其一部分”的运行和完成。
为了帮助大型和复杂的项目管理其自动化的工作流程,Gitlab添加了两个新功能以使管道更加强大:父子管道以及动态生成管道配置文件的功能。
认识父子管道
那么,您如何解决许多团队在同一个存储库中协作许多相互关联的服务的痛苦?让我向您介绍与GitLab 12.7一起发布的父子管道。通过允许子管道同时运行,将复杂的管道拆分为具有父子关系的多个管道可以提高性能。这种关系还使您能够将配置和可视化划分为不同的文件和视图。
项目结构如下
创建子管道
您可以通过include
将父项包含子项作为密钥的参数,trigger
来触发其子管道配置文件。您可以根据需要命名子管道文件,但是它仍然必须是有效的YAML。
我们来写一个简单的C 程序:
代码语言:javascript复制#include <iostream>
int main()
{
std::cout << "Hello GitLab!" << std::endl;
return 0;
}
下面配置触发另外两个子管道,这些子管道用于构建Windows和Linux版本的C 应用程序。该设置非常简单。
代码语言:javascript复制stages:
- triggers
build_windows:
stage: triggers
trigger:
include: ci/.win-gitlab-ci.yml
rules:
- changes:
- cpp_app
build_linux:
stage: triggers
trigger:
include: ci/.linux-gitlab-ci.yml
rules:
- changes:
- cpp_app
这条流水线包含一个stage名称为triggers
, 该stage具有两个并行运行的作业,分别为build_windows
,build_linux
。每个作业都设置了rules
限制只有cap_app目录文件发生变化才会运行作业。重要的是trigger
用于定义要触发运行的子配置文件,父管道在触发后将继续运行。您可以使用的所有常规方法include
来使用本地,远程或模板配置文件,最多三个子管道。
父子管道的另一个有用模式是rules
在某些条件下触发子管道的密钥。在上面的示例中,子管道仅在对cpp_app文件夹中的文件进行更改时触发。
Windows构建子管道(.win-gitlab-ci.yml
)具有以下配置,除非要触发其他子管道,否则它遵循标准的配置格式:
image: gcc
build:
stage: build
before_script:
- apt update && apt-get install -y mingw-w64
script:
- x86_64-w64-mingw32-g cpp_app/hello-gitlab.cpp -o helloGitLab.exe
artifacts:
paths:
- helloGitLab.exe
不要忘记将-y
参数作为apt-get install
命令的一部分,否则您的作业将被卡住,等待用户输入。
Linux构建子管道(.linux-gitlab-ci.yml
)具有以下配置,除非您要触发其他子管道,否则它遵循标准的配置格式:
image: gcc
build:
stage: build
script:
- g cpp_app/hello-gitlab.cpp -o helloGitLab
artifacts:
paths:
- helloGitLab
在这两种情况下,子管道都会生成一个工件,您可以在“作业结果”屏幕的“ *作业工件”*部分下进行下载。
将您创建的所有文件推送到新分支,对于管道结果,您应该看到两个作业及其后续的子作业。
默认情况下,一旦创建下游管道,trigger
作业就会以success
状态完成。父管道不会在子管道运行成功后再显示流水线成功,而是子管道只要被触发成功了则父管道成功。strategy: depend
将自身状态从触发的管道合并到源作业。
stages:
- triggers
build_windows:
stage: triggers
trigger:
include: ci/.win-gitlab-ci.yml
strategy: depend
rules:
- changes:
- cpp_app
build_linux:
stage: triggers
trigger:
include: ci/.linux-gitlab-ci.yml
strategy: depend
rules:
- changes:
- cpp_app
动态生成管道
进一步扩展父子管道,您还可以从父管道动态生成子配置文件。这样做可以使存储库清除分散的管道配置文件,并允许您在应用程序中生成配置,将变量传递给这些文件等等。
让我们从父管道配置文件开始:
代码语言:javascript复制stages:
- setup
- triggers
generate-config:
stage: setup
image: ruby
script:
- ruby write-config.rb
- git status
- cat .linux-gitlab-ci.yml
- cat .win-gitlab-ci.yml
artifacts:
paths:
- .linux-gitlab-ci.yml
- .win-gitlab-ci.yml
trigger-linux-build:
stage: triggers
trigger:
include:
- artifact: .linux-gitlab-ci.yml
job: generate-config
trigger-win-build:
stage: triggers
trigger:
include:
- artifact: .win-gitlab-ci.yml
job: generate-config
在我们的自定义setup
阶段,管道将运行write-config.rb
脚本。在本文中,这是一个Ruby脚本,用于编写子管道配置文件,但是您可以使用任何脚本语言。子管道配置文件与上述非动态示例中的子管道配置文件相同。我们用于artifacts
保存为该CI运行生成的子配置文件,以使它们可用于子管道阶段。
当Ruby脚本生成YAML时,请确保缩进正确,否则管道作业将失败。
代码语言:javascript复制#!/usr/bin/env ruby
linux_build = <<~YML
image: gcc
build:
stage: build
script:
- g cpp_app/hello-gitlab.cpp -o helloGitLab
artifacts:
paths:
- helloGitLabYML
win_build = <<~YML
image: gcc
build:
stage: build
before_script:
- apt update && apt-get install -y mingw-w64
script:
- x86_64-w64-mingw32-g cpp_app/hello-gitlab.cpp -o
helloGitLab.exe
artifacts:
paths:
- helloGitLab.exe
YML
File.open('.linux-gitlab-ci.yml', 'w'){ |f| f.write(linux_build)}
File.open('.win-gitlab-ci.yml', 'w'){ |f| f.write(win_build)}
然后,在该triggers
阶段中,父管道运行生成的子管道,与本示例的非动态版本中的运行方式非常相似,但是使用保存的artifact
文件和指定的job
。
将您创建的所有文件推送到新分支,对于管道结果,您应该看到三个作业(一个作业连接到其他两个作业)以及随后的两个子作业。
这篇博客文章显示了一些简单的示例,使您大致了解管道现在可以完成的工作。我们希望有一个父,多个子并能够动态生成配置,我们希望您找到构建所需的CI/CD工作流所需的所有工具。
关于作者
泽阳,DevOps领域实践者。专注于企业级DevOps运维开发技术实践分享,主要以新Linux运维技术、DevOps技术课程为主。丰富的一线实战经验,课程追求实用性获得多数学员认可。课程内容均来源于企业应用,在这里既学习技术又能获取热门技能,欢迎您的到来!