在项目之间共享gitlab-ci.yml文件

38
我们考虑将CI从Jenkins迁移到GitLab。我们有几个项目具有相同的构建工作流程。现在我们使用共享库定义流水线,在项目内的Jenkinsfile只调用共享库中定义的方法来定义实际的流水线,因此只需要在单个点上进行更改,就可以影响多个项目。
我想知道是否可以在GitLab CI中实现相同的功能?据我所知,不能在存储库之外定义gitlab-ci.yml。是否有其他方法来定义流水线并与多个项目共享此配置以简化维护?
7个回答

39

GitLab 11.7 推出了新的 include 方法,例如 include:filehttps://docs.gitlab.com/ee/ci/yaml/#includefile

include:
  - project: 'my-group/my-project'
    ref: master
    file: '/templates/.gitlab-ci-template.yml'

这将允许您在同一GitLab实例上创建一个新项目,其中包含一个共享的.gitlab-ci.yml文件。


30

首先,让我说一声:谢谢您提出这个问题!这激励我再次寻找解决方案,因为我经常在想这是否可能。我们还有20-30个项目非常相似,并且每个项目都有大约400-500行代码的.gitlab-ci.yml文件,如果有变更,则必须更改这些文件。

因此,我找到了一个可行的解决方案:

受Gitlab本身创建的自动 DevOps .gitlab-ci.yml 模板的启发,他们使用一个模板作业定义所有使用的函数调用每个before_script来加载它们,我想出了以下设置。

  • 多个项目仓库(project-1project-2)需要一个共享的CI作业/函数集合
  • 函数脚本,包含所有共享函数,在单独的仓库中

文件

因此,使用共享的CI作业脚本

#!/bin/bash

function list_files {
  ls -lah
}

function current_job_info {
  echo "Running job $CI_JOB_ID on runner $CI_RUNNER_ID ($CI_RUNNER_DESCRIPTION) for pipeline $CI_PIPELINE_ID"
}

一个常见且通用的.gitlab-ci.yml文件:

image: ubuntu:latest

before_script:
  # Install curl
  - apt-get update -qqq && apt-get install -qqqy curl
  # Get shared functions script
  - curl -s -o functions.sh https://gitlab.com/giix/demo-shared-ci-functions/raw/master/functions.sh
  # Set permissions
  - chmod +x functions.sh
  # Run script and load functions
  - . ./functions.sh

job1:
  script:
    - current_job_info
    - list_files
你可以将从项目1复制粘贴文件到项目2,这样就可以使用相同的Gitlab CI函数了。 所得经验 因此,在大规模应用此结构后(40个以上的项目),我想分享一些所得经验,这样您就不必费力地去尝试:
  • 为你共享的CI函数脚本(tag/release)版本化。任何更改都可能使所有管道失败。
  • 使用不同的Docker镜像可能会引起问题,需要bash加载函数(例如,我使用一些基于Alpine的镜像进行CLI工具任务,它们默认带有sh
  • 使用基于项目的CI/CD机密变量来为项目个性化构建作业,如环境URL等。

感谢你分享你的想法。目前看来这似乎是唯一的可能性。虽然我们仍无法批量添加新作业到管道中,但这已经是我们能够获得的最好解决方案了。谢谢! - pyriand3r
有一个类似的想法,很高兴找到已经投入生产的人。在我的设置中,我有几个 bash 脚本在 git 子模块中,所以我的工作描述读取 publish-java: {script: 'ci/publish-java.sh'},例如。而且我没有 'before_script',而是在顶部定义了 variables: { GIT_SUBMODULE_STRATEGY: 'recursive' }。https://gist.github.com/lordvlad/1ad18dc44479f2b90735bdb96b1d5338 - lordvlad

11
自从 GitLab 12.6 版本以后,可以定义一个外部的 .gitlab-ci.yml 文件。

自定义该文件路径:

  1. 进入项目设置 > CI/CD。
  2. 展开“通用流水线”部分。
  3. 在“自定义 CI 配置路径”字段中提供值。
  4. 单击“保存更改”。 ...

如果 CI 配置将托管在外部站点上,则 URL 必须以 .yml 结尾:

http://example.com/generate/ci/config.yml

如果 CI 配置将托管在 GitLab 的其他项目中,则该路径必须相对于其他项目中的根目录,并在末尾添加组和项目名称:

.gitlab-ci.yml@mygroup/another-project

my/path/.my-custom-file.yml@mygroup/another-project


7

所以,我想现在分享一下我的想法:

目前我们采用了@stefan-van-gastel的共享ci库和gitlab 11.7相对较新的include功能的混合方法。我们非常满意这种方法,因为现在我们可以在单个存储库中管理40多个存储库的构建流水线。

我创建了一个名为ci_shared_library的存储库,其中包含:

  1. 每个构建作业的shell脚本,包含执行步骤的逻辑。
  2. pipeline.yml文件包含整个流水线配置,在脚本之前我们将ci_shared_library加载到/tmp/shared中以便执行脚本。
stages:
  - test
  - build
  - deploy
  - validate

services:
  - docker:dind

before_script:
  # Clear existing shared library
  - rm -rf /tmp/shared
  # Get shared library
  - git clone https://oauth2:${GITLAB_TOKEN}@${SHARED_LIBRARY} /tmp/shared
  - cd /tmp/shared && git checkout master && cd $CI_PROJECT_DIR
  # Set permissions
  - chmod -R +x /tmp/shared
  # open access to registry
  - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY

test:
  stage: test
  script:
    - /tmp/shared/test.sh

build:
  stage: build
  script:
    - /tmp/shared/build.sh
  artifacts:
    paths:
      - $CI_PROJECT_DIR/target/RPMS/x86_64/*.rpm
    expire_in: 3h
  only:
    - develop
    - /release/.*/

deploy:
  stage: deploy
  script:
    - /tmp/shared/deploy.sh
  artifacts:
    paths:
      - $CI_PROJECT_DIR/tmp/*
    expire_in: 12h
  only:
    - develop
    - /release/.*/

validate:
  stage: validate
  script:
    - /tmp/shared/validate.sh
  only:
    - develop
    - /release\/.*/

每个想要使用此管道配置的项目都必须有一个.gitlab-ci.yml文件。在这个文件中,唯一需要做的是从ci_shared_library仓库导入共享的pipeline.yml文件。

# .gitlab-ci.yml

include:
  - project: 'ci_shared_library'
    ref: master
    file: 'pipeline.yml'

通过这种方法,与管道相关的所有内容都放在一个单一的存储库中,并且可以重复使用。我们把整个管道模板都放在一个文件中,但我认为甚至可以将其拆分成每个作业都有一个yml文件。这样,它将更加灵活,人们可以创建默认作业,以不同方式合并具有相似作业但并非每个项目都需要所有作业的项目...


有趣!但是你在pipeline.yml中检查了develop分支,而在gitlab-ci.yml中包含了master分支? - Rouliboy
1
谢谢你指出这个问题。我已经修复了这个错误。但另一方面,它似乎很奇怪,但是它确实有效。Gitlab从主分支的pipeline.yml中获取整个流水线。如果该文件告诉它拉取ci_shared_library存储库的develop分支,那就完全没问题。但可能有点令人困惑 ;) - pyriand3r

6

4
GitLab 13.5 (2020年10月) 开始,include 功能更加实用:

使用API验证扩展的GitLab CI/CD配置

编写和调试复杂的流水线并非易事。您可以使用include关键字来帮助减少流水线配置文件的长度。

但是,如果您以前想要通过API验证整个流水线,则必须单独验证每个包含的配置文件,这很复杂且耗时。

现在您有能力通过API验证完全展开的流水线配置,包括所有include配置。
调试大型配置现在更加容易和高效。

请参见文档问题

以及:

查看 GitLab 13.6 (2020年11月):

将多个CI/CD配置文件作为列表包含

以前,当使用 include:file语法向您的CI/CD配置添加多个文件时,您必须为每个文件指定项目和ref。在此版本中,您现在可以一次性指定项目、ref,并提供文件列表。这样可以避免重复操作,使流水线配置更简洁。

https://about.gitlab.com/images/13_6/list.png -- Include multiple CI/CD configuration files as a list

请参见文档)和问题


0
您可以了解一下动态子管道的概念。
它已经随着GitLab 13.2 (2020年7月)的发布而发展:

使用Jsonnet动态生成子管道配置

我们在GitLab 12.9中发布了 Dynamic Child Pipelines,这使您能够在运行时生成整个.gitlab-ci.yml文件。
例如,对于单体库(monorepos),当您希望运行时行为更加动态时,这是一个很好的解决方案。

现在,我们通过包含一个项目模板来演示如何使用Jsonnet生成YAML,使得在运行时创建CI/CD YAML变得更加容易。
Jsonnet是一种数据模板语言,提供了函数、变量、循环和条件语句,允许完全参数化的YAML配置。

https://about.gitlab.com/images/13_2/jsonnet-template.png

请参阅文档问题


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接