CI/CD コンポーネント(FREE ALL EXPERIMENT)

この機能は実験的な機能であり、将来の作業を追跡するためにエピックが存在します。エピックにコメントを残して、あなたのユースケースを教えてください。

コンポーネントリポジトリ

コンポーネントリポジトリは、1つ以上のパイプラインコンポーネントをホストするリポジトリを持つGitLabプロジェクトです。パイプラインコンポーネントは、再利用可能な単一のパイプライン設定単位です。パイプラインコンポーネントを使用して、パイプライン設定全体を構成したり、より大きなパイプラインの一部を構成したりできます。オプションで入力パラメータを受け取ることができます。

コンポーネントリポジトリの作成

コンポーネントリポジトリを作成するには、以下の手順が必要です:

  1. README.md ファイルで新しいプロジェクトを作成します。

  2. プロジェクトのルート・ディレクトリ内部に、コンポーネントとして提供したい設定を含むtemplate.yml ファイルを作成します。例えば

    spec:
      inputs:
        stage:
          default: test
    ---
    component-job:
      script: echo job 1
      stage: $[[ inputs.stage ]]
    

ディレクトリ構造

コンポーネントリポジトリは1つ以上のコンポーネントをホストすることができ、必須のファイル構造に従う必要があります。

コンポーネントの設定は、以下のようなディレクトリ構造で保存されます:

  • templates コンポーネントリポジトリの最上位にあるディレクトリです。すべてのコンポーネント設定ファイルは、このディレクトリの下に保存する必要があります。
  • .yml で終わるファイルには、コンポーネントの設定が含まれています。
  • リポジトリ内のすべてのコンポーネントの詳細を説明する MarkdownREADME.md ファイル。

たとえば、プロジェクトに単一のコンポーネントとコンポーネントをテストするパイプラインが含まれている場合、ファイル構造は次のようになります:

├── templates/
│   └── only_template.yml
├── README.md
└── .gitlab-ci.yml

この例のコンポーネントは、プロジェクトがgitlab.com/my-username/my-component/only_template@<version> のようなパスで参照できます:

  • GitLab.com の場合
  • 名前my-component
  • という名前の個人ネームスペースではmy-username

テンプレート・ディレクトリと設定ファイルのサフィックスは、参照されるパスから除外する必要があります。

プロジェクトに複数のコンテナが含まれる場合、ファイル構造は以下のようになります:

├── README.md
├── .gitlab-ci.yml
└── templates/
    └── all-scans.yml
    └── secret-detection.yml

これらのコンポーネントはこれらのパスで参照されます:

  • gitlab.com/my-username/my-component/all-scans
  • gitlab.com/my-username/my-component/secret-detection

設定ファイルの名前がtemplate.yml の場合、パスのファイル名を省略することができます。例えば、以下のコンポーネントはgitlab.com/my-username/my-component/dast で参照できます:

├── README.md
├── .gitlab-ci.yml
├── templates/
│   └── dast
│       └── template.yml

任意のディレクトリに保存されたコンポーネント設定 (非推奨)

note
このディレクトリ構造によるコンポーネント設定の保存は非推奨です。

コンポーネントの設定は、以下のディレクトリ構造で保存できます:

  • template.yml:コンポーネント設定、コンポーネントごとに1ファイル。コンポーネントが1つだけの場合、このファイルはプロジェクトのルートに置くことができます。複数のコンポーネントがある場合、それぞれのファイルは別々のサブディレクトリになければなりません。
  • README.md:リポジトリ内のすべてのコンポーネントの詳細を説明するドキュメントファイルです。

例えば、プロジェクトがGitLab.comにあり、my-component という名前で、my-username という個人的な名前空間にある場合:

  • 単一のコンポーネントとコンポーネントをテストするためのシンプルなパイプラインを含む場合、ファイル構造は次のようになります:

     ├── template.yml
     ├── README.md
     └── .gitlab-ci.yml
    

    このコンポーネントはgitlab.com/my-username/my-component@<version> というパスで参照されます。

  • 1つのデフォルトコンポーネントと複数のサブコンポーネントを含む場合、ファイル構造は次のようになります:

     ├── template.yml
     ├── README.md
     ├── .gitlab-ci.yml
     ├── unit/
     │   └── template.yml
     └── integration/
         └── template.yml
    

    これらのコンポーネントは、以下のパスで識別されます:

    • gitlab.com/my-username/my-component
    • gitlab.com/my-username/my-component/unit
    • gitlab.com/my-username/my-component/integration

ルートディレクトリにtemplate.yml を置かないことで、デフォルトコンポーネントを持たないコンポーネントリポジトリを持つことができます。

その他の注意事項

コンポーネントの入れ子はできません。例えば

├── unit/
│   └── template.yml
│   └── another_folder/
│       └── nested_template.yml

コンポーネントのテスト

開発ワークフローの一環としてコンポーネントをテストし、品質が高い水準を維持できるようにすることを強く推奨します。

CI/CDパイプラインでの変更点のテストは、他のプロジェクトと同様に、ルートディレクトリに.gitlab-ci.yml

使用例:

include:
  # include the component located in the current project from the current SHA
  - component: gitlab.com/$CI_PROJECT_PATH@$CI_COMMIT_SHA
    inputs:
      stage: build

stages: [build, test, release]

# Expect `component-job` is added.
# This is an example of testing that the included component works as expected.
# You can leverage GitLab API endpoints or 3rd party tools to inspect data generated by the component.
ensure-job-added:
  stage: test
  image: badouralix/curl-jq
  script:
    - |
      route="https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/pipelines/$CI_PIPELINE_ID/jobs"
      count=`curl --silent --header "PRIVATE-TOKEN: $API_TOKEN" $route | jq 'map(select(.name | contains("component-job"))) | length'`
      if [ "$count" != "1" ]; then
        exit 1
      fi

# If we are tagging a release with a specific convention ("v" + number) and all
# previous checks succeeded, we proceed with creating a release automatically.
create-release:
  stage: release
  image: registry.gitlab.com/gitlab-org/release-cli:latest
  rules:
    - if: $CI_COMMIT_TAG =~ /^v\d+/
  script: echo "Creating release $CI_COMMIT_TAG"
  release:
    tag_name: $CI_COMMIT_TAG
    description: "Release $CI_COMMIT_TAG of components repository $CI_PROJECT_PATH"

変更をコミットしてプッシュした後、パイプラインはコンポーネントをテストし、テストに合格したらリリースします。

コンポーネントのリリース

コンポーネントリポジトリは、CIパイプライン内でrelease キーワードを使用してリリースされます。

上の例のように、タグ ref に対して実行されるパイプラインですべてのテストがパスした後、コンポーネントリポジトリの新しいバージョンをリリースすることができます。

コンポーネントリポジトリのすべてのリリースバージョンは、指定したリソースのコンポーネントカタログページに表示され、公式リリースの情報をユーザーに提供します。

CI/CD 設定でのコンポーネントの使用

パイプラインコンポーネントは、<fully-qualified-doman-name>/<component-path>@<version> を含むユニークなアドレスで識別されます:

  • 完全修飾ドメイン名(FQDN): FQDNはGitLabホストと一致しなければなりません。
  • 特定のバージョン:コンポーネントのバージョンは(優先順位の高いものから順に)指定できます:
    • コミット SHA、たとえばgitlab.com/gitlab-org/dast@e3262fdd0914fa823210cdb79a8c421e2cef79d8
    • タグ。例:gitlab.com/gitlab-org/dast@1.0.
    • ~latestこれは、常に最新のリリースタグを指す特別なバージョンで、例えばgitlab.com/gitlab-org/dast@~latest
    • ブランチ名、例えばgitlab.com/gitlab-org/dast@main
  • コンポーネントパス:プロジェクトのフルパスとコンポーネント YAML ファイルtemplate.yml が存在するディレクトリをコンテナで指定します。

たとえば、gitlab.comgitlab-org/dast にあるコンポーネントリポジトリの場合:

  • パスgitlab.com/gitlab-org/dast はルートディレクトリからtemplate.yml をロードしようとします。
  • パスgitlab.com/gitlab-org/dast/api-scan/api-scan ディレクトリからtemplate.yml をロードしようとします。

その他の注意事項

  • プロジェクトと同じGitLabインスタンス内のコンポーネントしか参照できません。
  • タグとブランチが同じ名前で存在する場合、タグがブランチより優先されます。
  • タグがe3262fdd0914fa823210cdb79a8c421e2cef79d8 のように、存在するコミット SHA と同じ名前の場合、コミット SHA がタグより優先されます。

ベストプラクティス

グローバルキーワードの使用を避ける

グローバルキーワードを使用すると、パイプライン内のすべてのジョブが影響を受けます。コンポーネントでこれらのキーワードを使用すると、メイン.gitlab-ci.yml で直接定義されているか、含まれるコンポーネントで定義されているかにかかわらず、パイプライン内のすべてのジョブに影響します。

パイプラインの構成をより決定論的にするには、次のいずれかを実行します:

  • 各ジョブのデフォルト設定を複製します。
  • コンポーネント内部でextends 機能を使用します。
##
# BAD
default:
  image: ruby:3.0

rspec:
  script: bundle exec rspec
##
# GOOD
rspec:
  image: ruby:3.0
  script: bundle exec rspec

ハードコードされた値を入力に置き換えます

CIテンプレートで見られる典型的なハードコードされた値は、stage: 。このようなハードコードされた値は、コンポーネントのユーザーに、このような実装の詳細を知ってパイプラインを適応させることを強いるかもしれません。

例えば、stage: test があるコンポーネントのジョブに対してハードコードされている場合、そのコンポーネントを使用するパイプラインはtest のステージを定義しなければなりません。さらに、コンポーネントのユーザーがステージ値をカスタマイズしたい場合、設定をオーバーライドする必要があります:

##
# BAD: In order to use different stage name you need to override all the jobs
# included by the component.
include:
  - component: gitlab.com/gitlab-org/ruby-test@1.0

stages: [verify, deploy]

unit-test:
  stage: verify

integration-test:
  stage: verify
##
# BAD: In order to use the component correctly you need to define the stage
# that is hard-coded in it.
include:
  - component: gitlab.com/gitlab-org/ruby-test@1.0

stages: [test, deploy]

これを改善するために、コンポーネントのユーザーがカスタマイズ可能な値を注入できるように、入力パラメータを使用することができます:

##
# GOOD: We don't need to know the implementation details of a component and instead we can
# rely on the inputs.
include:
  - component: gitlab.com/gitlab-org/ruby-test@1.0
    inputs:
      stage: verify

stages: [verify, deploy]

##
# inside the component YAML:
spec:
  inputs:
    stage:
      default: test
---
unit-test:
  stage: $[[ inputs.stage ]]
  script: echo unit tests

integration-test:
  stage: $[[ inputs.stage ]]
  script: echo integration tests

変数よりも入力を優先

変数が YAML の評価 (たとえばrules) でのみ使用され、Runner の実行では使用されない場合、代わりに入力を使用することをお勧めします。入力はコンポーネントのコントラクトで明示的に定義され、変数よりも検証されます。

例えば、必須入力が渡されない場合、コンポーネントが使用されるとすぐにエラーが返されます。対照的に、変数が定義されていない場合、その値は空になります。

##
# BAD: you need to configure an environment variable for a custom value that doesn't need
# to be used on the Runner 
unit-test:
  image: $MY_COMPONENT_X_IMAGE
  script: echo unit tests

integration-test:
  image: $MY_COMPONENT_X_IMAGE
  script: echo integration tests

##
# Usage:
include:
  - component: gitlab.com/gitlab-org/ruby-test@1.0

variables:
  MY_COMPONENT_X_IMAGE: ruby:3.2
##
# GOOD: we define a customizable value and accept it as input
spec:
  inputs:
    image:
      default: ruby:3.0
---
unit-test:
  image: $[[ inputs.image ]]
  script: echo unit tests

integration-test:
  image: $[[ inputs.image ]]
  script: echo integration tests

##
# Usage:
include:
  - component: gitlab.com/gitlab-org/ruby-test@1.0
    inputs:
      image: ruby:3.2

セマンティック・バージョニングの使用

コンポーネントの新しいバージョンをタグ付けしてリリースする際には、セマンティックバージョニングを使用することをお勧めします。

少なくともMAJOR.MINOR フォーマットを採用することをお勧めします。

例えば2.1 1.0.0,1.0.0-alpha,2.1.3,3.0.0-rc.1.