CI設定内部

ワークフロールール

GitLab プロジェクトのパイプラインは、GitLab CI/CD のworkflow:rules キーワード 機能を使って作成します。

パイプラインは常に以下のシナリオのために作成されます:

  • main ブランチ(スケジュール、プッシュ、マージなど)。
  • マージリクエスト
  • タグ
  • 安定、auto-deploy 、セキュリティブランチ。

パイプラインの作成は、以下の CI/CD 変数の影響も受けます:

  • $FORCE_GITLAB_CI が設定されている場合、パイプラインが作成されます。使用は推奨されません。 $FORCE_GITLAB_CIを参照してください。
  • $GITLAB_INTERNAL が設定されていない場合、パイプラインは作成されません。

それ以外の場合、パイプラインは作成されません (たとえば、MR のないブランチをプッシュする場合など)。

これらのワークフロールールのソースオブトゥルースは、.gitlab-ci.yml で定義されています。

避ける$FORCE_GITLAB_CI

パイプラインは非常に複雑で、どのようなパイプラインをトリガーしたいのかを明確に理解する必要があります。どのジョブを実行すべきで、どのジョブを実行すべきでないかを知る必要があります。

パイプラインを強制的にトリガーするために$FORCE_GITLAB_CI を使用した場合、どのようなパイプラインなのかがよくわかりません。その結果、必要なジョブが実行されなかったり、どうでもいいジョブがたくさん実行されたりします。

より詳細な背景については、以下を参照してください:予期せぬ実行を避けるために、包括的な変更は避けましょう

以下は、私たちが今現在これを使用している場所のリストです。$FORCE_GITLAB_CI.

デフォルトの画像

デフォルトの画像は.gitlab-ci.yml で定義されています。

Ruby、Go、Git、Git LFS、Chrome、Node、Yarn、PostgreSQL、Graphics Magickが含まれています。

パイプラインで使用されるイメージはgitlab-org/gitlab-build-images プロジェクトで設定され、冗長性のためにgitlab/gitlab-build-images にプッシュミラーされています。

現在のビルドイメージのバージョンは、“Used by GitLab section “にあります。

デフォルト変数

定義済みのCI/CD変数に加えて、各パイプラインには.gitlab-ci.ymlで定義されたデフォルト変数が含まれています。

ステージ

現在のステージは以下の通りです:

  • sync:このステージはgitlab-org/gitlab からgitlab-org/gitlab-foss への変更の同期に使用されます。
  • prepare:このステージには、後続ステージのジョブが必要とするアーティファクトを準備するジョブが含まれます。
  • build-images:このステージには、後続ステージやダウンストリームパイプラインのジョブが必要とするDockerイメージを準備するジョブが含まれます。
  • fixtures:このステージには、フロントエンドのテストに必要なフィクスチャを準備するジョブが含まれます。
  • lint:このステージはリントと静的解析のジョブを含みます。
  • test:このステージにはほとんどのテストとDB/マイグレーションジョブが含まれます。
  • post-test:このステージには、レポーターを作成したり、test ステージのジョブからデータを収集したりするジョブが含まれます (カバレッジ、Knapsack メタデータなど)。
  • review:このステージには、CNG イメージをビルドし、デプロイし、レビューアプリに対してエンドツーエンドのテストを実行するジョブが含まれます (詳細はレビューアプリを参照してください)。Docs レビューアプリのジョブも含まれます。
  • qa:このステージには、ステージreview でデプロイされたレビューアプリに対して QA タスクを実行するジョブが含まれます。
  • post-qa:このステージには、レポートを作成したり、qa ステージのジョブからデータを収集したりするジョブが含まれます (レビューアプリのパフォーマンスレポートなど)。
  • pages:このステージには、様々なレポートをGitLab Pagesとしてデプロイするジョブが含まれます(例えば、coverage-rubywebpack-reporthttps://gitlab-org.gitlab.io/gitlab/webpack-report/で見つかりましたが、デプロイにイシューがあります)。
  • notify:このステージには、様々な失敗をSlackに通知するジョブが含まれます。

依存関係プロキシ

ジョブの中にはDocker Hubのイメージを使用しているものがあります。この場合、依存プロキシからイメージを取得するために、イメージパスのプレフィックスとして${GITLAB_DEPENDENCY_PROXY_ADDRESS} を使用します。デフォルトでは、この変数は${GITLAB_DEPENDENCY_PROXY}の値から設定されます。

${GITLAB_DEPENDENCY_PROXY}gitlab-org${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/として定義されているグループ CI/CD 変数です。と定義されています:

image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}alpine:edge

gitlab-org グループ内のプロジェクトは依存プロキシからプルしますが、他の個人ネームスペースやグループに存在するフォークは、${GITLAB_DEPENDENCY_PROXY} が定義されていない限りDocker Hubにフォールバックします。

プロジェクトアクセストークンユーザーによってパイプラインが開始された場合の回避策

パイプラインがプロジェクトアクセストークンユーザー(例えば、メインプロジェクトで使用されるGitalyバージョンを自動的に更新するrelease-tools approver bot ユーザー)によって開始されると、依存プロキシにアクセスできず、Preparing the "docker+machine" executor ステップでジョブが失敗します。これを回避するために、${GITLAB_DEPENDENCY_PROXY_ADDRESS} 変数をオーバーライドする特別なワークフロールールを用意し、依存プロキシが使用されないようにしています:

- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $GITLAB_USER_LOGIN =~ /project_\d+_bot\d*/'
  variables:
    GITLAB_DEPENDENCY_PROXY_ADDRESS: ""
note
グループレベルの変数は.gitlab-ci.yml 変数よりも優先順位が高いため、${GITLAB_DEPENDENCY_PROXY} 変数を直接上書きすることはありません。

一般的なジョブ定義

ほとんどのジョブは、.gitlab/ci/global.gitlab-ci.yml で定義された、単一の設定キーワードにスコープされたいくつかのCI定義から拡張されます。

ジョブの定義説明
.default-retry unknown_failure,api_failure,runner_system_failure,job_execution_timeout,stuck_or_timeout_failure のときにジョブの再試行を許可します。
.default-before_scriptデータベースの実行が必要なRuby/Railsタスク (たとえばテスト) に適したデフォルトのbefore_script 定義をジョブで使用できるようにします。
.setup-test-env-cacheジョブに、後続のRuby/Railsタスクのテスト環境を設定するのに適したデフォルトのcache 定義を使えるようにします。
.ruby-cacheRuby タスクに適したデフォルトのcache 定義をジョブに使わせます。
.static-analysis-cacheジョブが静的解析タスクに適したデフォルトのcache 定義を使えるようにします。
.ruby-gems-coverage-cacheジョブがカバレッジタスクに適したデフォルトのcache 定義を使用できるようにします。
.qa-cacheジョブがQAタスクに適したデフォルトのcache 定義を使用できるようにします。
.yarn-cache yarn install を行うフロントエンドジョブに適したデフォルトのcache 定義をジョブに使用できるようにします。
.assets-compile-cacheアセットをコンパイルするフロントエンドジョブに適したデフォルトのcache 定義をジョブが使用できるようにします。
.use-pg13ジョブがpostgres 13、redis 、およびrediscluster サービスを使用できるようにします (サービスの特定のバージョンについては.gitlab/ci/global.gitlab-ci.yml を参照してください)。
.use-pg13-ee .use-pg13 と同じですが、elasticsearch サービスも使用します (サービスの具体的なバージョンは.gitlab/ci/global.gitlab-ci.yml を参照)。
.use-pg14ジョブがpostgres 14、redis 、およびrediscluster サービスを使用できるようにします (サービスの具体的なバージョンは.gitlab/ci/global.gitlab-ci.yml を参照)。
.use-pg14-ee .use-pg14 と同じですが、elasticsearch サービスも使用します (サービスの具体的なバージョンは.gitlab/ci/global.gitlab-ci.yml を参照)。
.use-pg15ジョブがpostgres 15、redis 、およびrediscluster サービスを使用できるようにします (サービスの具体的なバージョンは.gitlab/ci/global.gitlab-ci.yml を参照)。
.use-pg15-ee .use-pg15 と同じですが、elasticsearch サービスも使用します (サービスの具体的なバージョンは.gitlab/ci/global.gitlab-ci.yml を参照)。
.use-kanikoジョブがkaniko ツールを使って Docker イメージをビルドできるようにします。
.as-if-foss FOSS_ONLY='1' CI/CD変数を設定してFOSSプロジェクトをシミュレートします。
.use-docker-in-dockerジョブがDockerでDockerを使えるようにします。詳細はCI/CD設定についてのハンドブックを参照してください。

rules,if: 条件とchanges: パターン

rules キーワード を多用しています。

すべてのrules 定義はrules.gitlab-ci.ymlで定義され、extends を介して個々のジョブに含まれます。

rules 定義はif: 条件とchanges: パターンで Composer されます。これらはrules.gitlab-ci.yml でも定義され、YAML アンカーを介してrules 定義に含まれます。

if: 条件

if: 条件説明備考
if-not-canonical-namespaceプロジェクトが正規 (gitlab-org/gitlab-cn/) またはセキュリティ (gitlab-org/security) 名前空間にない場合にマッチします。フォーク用のジョブを作成する場合 (when: on_success またはwhen: manual を使用)、またはフォーク用のジョブを作成しない場合 (when: never を使用) に使用します。
if-not-eeプロジェクトがEEでない場合(つまり、プロジェクト名がgitlab またはgitlab-ee でない場合)にマッチします。FOSSプロジェクトでのみジョブを作成する場合(when: on_success またはwhen: manual を使用)、プロジェクトがEEの場合はジョブを作成しない場合(when: never を使用)に使用します。
if-not-fossプロジェクトがFOSSでない場合(つまり、プロジェクト名がgitlab-fossgitlab-cegitlabhq でない場合)にマッチします。EEプロジェクトでのみジョブを作成する場合(when: on_success またはwhen: manual を使用)、プロジェクトがFOSSの場合はジョブを作成しない場合(when: never を使用)に使用します。
if-default-refsパイプラインがmastermain/^[\d-]+-stable(-ee)?$/ (安定ブランチ)、/^\d+-\d+-auto-deploy-\d+$/ (自動デプロイブランチ)、/^security\// (セキュリティブランチ)、マージリクエスト、タグの場合にマッチします。このデフォルト設定のブランチでは、ジョブは作成されないことに注意してください。
if-master-refs現在のブランチがmaster またはmain の場合にマッチします。 
if-master-push現在のブランチがmaster またはmain で、パイプラインソースがpush の場合にマッチします。 
if-master-schedule-maintenance現在のブランチがmaster またはmain で、パイプラインが 2 時間ごとのスケジュールで実行されている場合にマッチします。 
if-master-schedule-nightly現在のブランチがmaster またはmain で、パイプラインが夜間スケジュールで実行されている場合にマッチします。 
if-auto-deploy-branches現在のブランチが自動デプロイされている場合にマッチします。 
if-master-or-tagパイプラインがmaster ブランチかmain ブランチ、またはタグのものである場合にマッチします。 
if-merge-requestパイプラインがマージリクエストの場合にマッチします。 
if-merge-request-title-as-if-fossパイプラインがマージリクエストで、MR のラベルが ~"pipeline:run-as-if-foss" の場合にマッチします。 
if-merge-request-title-update-cachesパイプラインがマージリクエストで、MR のラベルが ~"pipeline:update-cache" の場合にマッチします。 
if-merge-request-labels-run-all-rspecパイプラインがマージリクエストで、MR のラベルが ~"pipeline:run-all-rspec" の場合に一致します。 
if-security-merge-requestパイプラインがセキュリティマージリクエストの場合にマッチします。 
if-security-scheduleパイプラインがセキュリティスケジュールパイプラインの場合にマッチします。 
if-nightly-master-scheduleパイプラインが$NIGHTLY が設定されたmaster スケジュールパイプラインの場合にマッチします。 
if-dot-com-gitlab-org-scheduleGitLab.com のgitlab-org グループのスケジュールされたパイプラインにジョブの作成を制限します。 
if-dot-com-gitlab-org-masterGitLab.comのgitlab-org グループに対して、ジョブの作成をmaster またはmain ブランチに制限します。 
if-dot-com-gitlab-org-merge-requestGitLab.com のgitlab-org グループに対して、ジョブの作成をマージリクエストに制限します。 
if-dot-com-gitlab-org-and-security-tagGitLab.com のgitlab-orggitlab-org/security グループに対して、ジョブの作成をタグに制限します。 
if-dot-com-gitlab-org-and-security-merge-requestGitLab.com のgitlab-orggitlab-org/security グループに対して、ジョブの作成をマージリクエストに制限します。 
if-dot-com-gitlab-org-and-security-tagGitLab.com のgitlab-orggitlab-org/security グループに対して、ジョブ作成をタグに制限。 
if-dot-com-ee-scheduleGitLab.com のgitlab-org/gitlab プロジェクトのスケジュールされたパイプラインにジョブを制限します。 

changes: パターン

changes: パターン説明
ci-patternsCI設定関連の変更にのみジョブを作成します。
ci-build-images-patterns build-images ステージに関連する CI 設定関連の変更にのみジョブを作成します。
ci-review-patterns review ステージに関連する CI 設定関連の変更にのみジョブを作成します。
ci-qa-patterns qa ステージに関連する CI 設定関連の変更にのみジョブを作成します。
yaml-lint-patternsYAML関連の変更に対してのみジョブを作成します。
docs-patternsdocs関連の変更にのみジョブを作成します。
frontend-dependency-patternsフロントエンドの依存関係が更新されたときのみジョブを作成します (たとえば、package.jsonyarn.lock)。
frontend-patterns-for-as-if-fossFOSSに影響を与えるフロントエンド関連の変更に対してのみジョブを作成します。
backend-patternsバックエンド関連の変更にのみジョブを作成します。
db-patternsDB関連の変更にのみジョブを作成します。
backstage-patternsバックステージ関連の変更 (つまり、Danger、フィクスチャ、RuboCop、specs) に対してのみジョブを作成します。
code-patternsコード関連の変更にのみジョブを作成します。
qa-patternsQA関連の変更にのみジョブを作成してください。
code-backstage-patterns code-patternsbackstage-patterns の組み合わせ。
code-qa-patterns code-patternsqa-patterns の組み合わせ。
code-backstage-qa-patterns code-patternsbackstage-patternsqa-patterns の組み合わせ。
static-analysis-patternsジョブの作成は、Static Analytics設定関連の変更に限定してください。

ベストプラクティス

extends:<<: *xyz (YAMLアンカー)、あるいは!reference

リファレンス

キーポイント

  • ハッシュを拡張する必要がある場合はextends
  • 配列を拡張する必要がある場合は、!reference を使うか、最後の手段としてYAML anchors を使う必要があります。
  • より複雑な場合 (たとえば、配列の内部でハッシュを拡張する、ハッシュの内部で配列を拡張する…) には、!reference またはYAML anchors

extendsYAML anchors は何ができますか?

extends
  • ハッシュのディープマージ
  • 配列に対するマージはありません。上書きします
YAML アンカー
  • ハッシュのディープマージはできませんが、ハッシュを拡張するために使用することはできます (以下の例を参照ください)。
  • 配列のマージは行いませんが、配列を拡張するために使用することはできます (以下の例を参照ください)。

すばらしい例

この例では、複雑な YAML データ構造を!referenceYAML anchors で拡張する方法を示します:

.strict-ee-only-rules:
  # `rules` is an array of hashes
  rules:
    - if: '$CI_PROJECT_NAME !~ /^gitlab(-ee)?$/ '
      when: never

# `if-security-merge-request` is a hash
.if-security-merge-request: &if-security-merge-request
  if: '$CI_PROJECT_NAMESPACE == "gitlab-org/security"'

# `code-qa-patterns` is an array
.code-qa-patterns: &code-qa-patterns
  - "{package.json,yarn.lock}"
  - ".browserslistrc"
  - "babel.config.js"
  - "jest.config.{base,integration,unit}.js"

.qa:rules:as-if-foss:
  rules:
    # We extend the `rules` array with an array of hashes directly
    - !reference [".strict-ee-only-rules", rules]
    # We extend a single array entry with a hash
    - <<: *if-security-merge-request
      # `changes` is an array, so we pass it an entire array
      changes: *code-qa-patterns

qa:selectors-as-if-foss:
  # We include the rules from .qa:rules:as-if-foss in this job
  extends:
    - .qa:rules:as-if-foss

.fast-no-clone-job ジョブの拡張

正規プロジェクトのブランチをダウンロードするのに20秒から30秒かかります。

GitLab API を使ってダウンロードできる限られた数のファイルしか必要としないジョブもあります。

以下のパターンをジョブに追加することで、ジョブgit clone/git fetch をスキップすることができます。

シナリオ 1: ジョブにbefore_script が定義されていない場合。

これはジョブが拡張する親セクションにもあてはまります。

.fast-no-clone-job を拡張するだけです:

を拡張するだけです:

  # Note: No `extends:` is present in the job
  a-job:
    script:
      - source scripts/rspec_helpers.sh scripts/slack
      - echo "No need for a git clone!"

After:

  # Note: No `extends:` is present in the job
  a-job:
    extends:
      - .fast-no-clone-job
    variables:
      FILES_TO_DOWNLOAD: >
        scripts/rspec_helpers.sh
        scripts/slack
    script:
      - source scripts/rspec_helpers.sh scripts/slack
      - echo "No need for a git clone!"

シナリオ2:before_script ブロックがジョブ(もしくはジョブが拡張するジョブ)内ですでに定義されている場合

このシナリオでは、あなたは

  1. 最初のシナリオと同様に、.fast-no-clone-job を拡張します(これにより、FILES_TO_DOWNLOAD 変数が他の変数とマージされます)。
  2. .fast-no-clone-jobbefore_script セクションが、このジョブで使用するbefore_script で参照されていることを確認してください。

を拡張するだけです:

  .base-job:
    before_script:
      echo "Hello from .base-job"

  a-job:
    extends:
      - .base-job
    script:
      - source scripts/rspec_helpers.sh scripts/slack
      - echo "No need for a git clone!"

After:

  .base-job:
    before_script:
      echo "Hello from .base-job"

  a-job:
    extends:
      - .base-job
      - .fast-no-clone-job
    variables:
      FILES_TO_DOWNLOAD: >
        scripts/rspec_helpers.sh
        scripts/slack
    before_script:
      - !reference [".fast-no-clone-job", before_script]
      - !reference [".base-job", before_script]
    script:
      - source scripts/rspec_helpers.sh scripts/slack
      - echo "No need for a git clone!"

注意点

  • このパターンは、リポジトリへのアクセスをgit に依存しているスクリプトでは動作しません。なぜなら、クローンやフェッチなしではリポジトリを持っていないからです。
  • このパターンを使用するジョブはcurl を利用できる必要があります。
  • ジョブ内でbundle install を実行する必要がある場合 (BUNDLE_ONLY を使用する場合でも)、必要です:
    • gitlab-org/gitlab プロジェクトに格納されている gems をダウンロードします。
      • そのためにはdownload_local_gems shell コマンドを使用します。
    • GemfileGemfile.lockGemfile.checksum (該当する場合)を含めます。

このパターンはどこで使われていますか?

  • 今のところ、私たちはこのパターンを以下のようなジョブに使っており、これらは非公開リポジトリをブロックしません:
    • review-build-cng-env のためです:
      • GITALY_SERVER_VERSION
      • GITLAB_ELASTICSEARCH_INDEXER_VERSION
      • GITLAB_KAS_VERSION
      • GITLAB_METRICS_EXPORTER_VERSION
      • GITLAB_PAGES_VERSION
      • GITLAB_SHELL_VERSION
      • scripts/trigger-build.rb
      • VERSION
    • review-deploy のためです:
      • GITALY_SERVER_VERSION
      • GITLAB_SHELL_VERSION
      • scripts/review_apps/review-apps.sh
      • scripts/review_apps/seed-dast-test-data.sh
      • VERSION
    • rspec:coverage のためです:
      • config/bundler_setup.rb
      • Gemfile
      • Gemfile.checksum
      • Gemfile.lock
      • scripts/merge-simplecov
      • spec/simplecov_env_core.rb
      • spec/simplecov_env.rb

さらに、このパターンが使用されると、scripts/utils.sh が常にAPIからダウンロードされます(このファイルには、.fast-no-clone-job のコードが含まれています)。

ランナーのタグ

GitLab.com では、非特権ランナーと特権ランナーの両方が利用できます。gitlab-org グループのプロジェクトとそのフォークでは、以下のタグのうち一つだけをジョブに追加してください:

  • gitlab-org:ジョブは特権ランナーと非特権ランナーをランダムに使用します。
  • gitlab-org-docker:ジョブは特権ランナーを使用する必要があります。Docker-in-Dockerのサポートが必要な場合は、 gitlab-org-docker gitlab-org の代わりにgitlab-org-docker使用して gitlab-org-dockerください。

gitlab-org-docker タグは、上記の.use-docker-in-docker ジョブ定義によって追加されます。

フォークとの互換性を確保するために、gitlab-orggitlab-org-docker の両方を同時に使用することは避けてください。gitlab-orggitlab-org-docker の両方のタグを持つインスタンスランナーはいません。gitlab-org プロジェクトのフォークの場合、マッチする Runner がないため、両方のタグが指定されると、ジョブはスタックします。

詳しくはGitLab Repositories handbook ページをご覧ください。