[GitLab CI] Monorepo(単一レポジトリ)で複数デプロイ可能なディレクトリがある場合の構成案


マイクロサービスモノレポ(単一レポジトリ)で管理している場合、ルートに置かれた.gitlab-ci.yml のみで記述しているとファイルが肥大化する傾向にあります。 また、フロント/バックエンドのソースを単一レポジトリに含めている場合も同様です。

マイクロサービスなどの独立してデプロイ可能な単位のソースを、別々のレポジトリで管理する場合もあると思いますが、特にプログラムの規模がさほど大きくない場合は、単一のレポジトリで管理したほうが、扱いやすいと思います。

ちなみに Wikipediaには、GoogleやFacebookなどでも非常に大規模なソースを モノレポ 構成で管理しているように書いてあります。1 (英語ではmonorepo=モノレポ)

Google,[5] Facebook,[6] Microsoft,[7] Uber,[8] Airbnb and Twitter[9] all employ very large monorepos with varying strategies to scale build systems and version control software with a large volume of code and daily changes.

今回は、GitLab 12.7 で導入された、親子関係のパイプラインOnlyChanges キーワードを組み合わせた構成をご紹介します。

モノリシックなサービスの場合や、単純に .gitlab-ci.yml が肥大化した場合の対処法としては、 include キーワードでファイルを分けたり、 extends キーワードでリファクタリングする方法があると思います。

構成案

レポジトリのディレクトリ構成例

+ .gitlab-ci.yml  # ルートにあるCI/CD構成スクリプト
+ my_service_a # デプロイ可能なソースディレクトリ
|  + .my_service_a.yml
|  + ...
+ my_service_b # 別のデプロイ可能なソースディレクトリ
|  + .my_service_b.yml
|  + ...
|  ...
  • 仮にサービスのディレクトリが更に深いサブディレクトリにあっても問題なし。

親パイプラインの定義

.gitlab-ci.yml の中身

image: alpine:3.7  # 参考用に軽いalpineに変更

stages:
  - triggers

my_service_a:
  stage: triggers
  only:
    refs: # ブランチを限定する場合
      - develop
      - stage
    changes: # 以下ディレクトリ内に変更があった場合のみトリガーされる
      - my_service_a/**/*
  trigger:
    include: my_service_a/.my_service_a.yml # 子パイプライン定義
    strategy: depend

my_service_b:
  stage: triggers
  only:
    refs:  # ブランチを限定する場合
      - develop
      - stage
    changes: # 以下ディレクトリ内に変更があった場合のみトリガーされる
      - my_service_b/**/*
  trigger:
    include: my_service_b/.my_service_b.yml # 別の子パイプライン定義
    strategy: depend

ポイント

  • ステージはtriggersのみ
  • デプロイ可能な単位に列挙(下記では my_service_a, my_service_b)
  • only > refs は ブランチを限定
  • only > changes は プッシュ時に変更があった場合のみトリガーさせる
  • trigger キーワードで、参照先のスクリプトを指定
  • strategy: depend で子パイプラインがすべて成功するまで親も成功ステータスにしない。

子パイプラインの定義

.my_service_a.yml (中身は自由ですが参考までに一応記載)

image: alpine:3.7

stages:
  - one
  - two
  - three

stage_one_one:
  stage: one
  script:
    - echo "ONE"

stage_two_one:
  stage: two
  script:
    - echo "TWO ONE"

stage_two_two:
  stage: two
  allow_failure: false
  only:
    refs:
      - develop
  script:
    - echo "TWO TWO"

stage_three_two:
  stage: three
  when: on_success
  only:
    refs:
      - develop
  script:
    - echo "THREE TWO"

トリガーさせる

developブランチで、my_service_a/ または my_service_b/ のディレクトリ配下のソースをコミットしてリモートへプッシュ。

まとめ

  • 各種デプロイ可能なディレクトリのルートにCI/CDの構成を書くことで分かりやすくなった。
  • Changes キーワードを利用することで、コミット時に変更がある場合のみに実行し、無駄な実行を省いた。
  • デメリットとして、小パイプラインのスクリプトのコード共通化の範囲は一部限定される。(例: .my_service_a.yml ⇔ .my_service_b.ymlの間) include キーワードで共通のコンフィグを外部ファイル化すれば、サービス間のコンフィグのリファクタリングも可能。

参考リンク