モノレポの呪縛を解き放て:GitLab Parent-Child PipelinesによるCI高速化の極意
モノレポを運用していると、避けて通れないのが「CIの肥大化」だ。数百万行のコード、数千のテスト。たった1行の変更のために、なぜ全モジュールのビルドとテストを待たなければならないのか?
多くのチームが「モノレポはCIが遅い」という諦めと共に、開発体験(DX)を犠牲にしている。だが、それはGitLabのポテンシャルを半分も引き出せていない証拠だ。
今日は、Parent-Child Pipelinesを駆使して、CIの実行時間を数十分から数分へと圧縮する、プロの最適化術を伝授する。
—
1. なぜ「Parent-Child」なのか?(概念的突破口)
従来の `include` や `trigger` は、パイプラインの構成を分割するだけの「静的」なものだった。しかし、Parent-Child Pipelinesは、実行時に動的にサブパイプラインを生成・実行する。
この「動的」というのが肝だ。モノレポにおいて「変更されたディレクトリのみを検知し、そのサブツリーだけを走らせる」という理想的なCIを実現するための最短経路がここにある。
2. 【実践】変更差分によるパイプラインの動的生成
まずは、親パイプライン(`.gitlab-ci.yml`)で「どのモジュールが変更されたか」を判定し、必要な子パイプラインだけを呼び出す構成を作る。
.gitlab-ci.yml (親パイプライン)
stages:
- trigger
変更検知用のジョブ
generate-pipelines:
stage: trigger
script:
- |
# 変更があったディレクトリをリストアップ
changed_dirs=$(git diff –name-only $CI_COMMIT_BEFORE_SHA $CI_COMMIT_SHA | cut -d/ -f1 | uniq)
for dir in $changed_dirs; do
if [ -f “$dir/.gitlab-ci.yml” ]; then
echo “Triggering pipeline for $dir”
# ここで動的に子パイプラインをトリガーするアーティファクトを生成
echo “$dir:pipeline” >> generated-config.yml
fi
done
artifacts:
paths:
- generated-config.yml
動的生成された設定ファイルに基づいて子パイプラインを起動
trigger-sub-pipelines:
stage: trigger
trigger:
include:
- artifact: generated-config.yml
job: generate-pipelines
strategy: depend
この設定により、`service-a/` だけを変更した際、`service-b/` や `lib-core/` のテストは一切走らない。ビルド時間は直感的に、かつ劇的に短縮される。
—
3. 現場で震えるほど役立つ「プロのハック」
A. `needs` と `dependencies` の使い分け
Parent-Child Pipelineの罠は、アーティファクトの受け渡しだ。`needs` を使えば、ステージ間の依存関係を無視してジョブを並列実行できる。大規模モノレポでは、ビルドステージが終わるのを待たずに、単体テストを即座に走らせるのが鉄則だ。
B. ローカル開発を劇的に加速させる「GitLab CLI (glab)」
GUIをポチポチするのは時間の無駄だ。`glab` コマンドを使いこなせ。
- `glab ci view`: 現在のパイプラインの状況をターミナルで即座に確認。
- `glab ci trace`: 失敗したジョブのログを即座にストリーミング表示。
ブラウザを開く回数を減らすだけで、集中力の持続時間が変わる。
C. キャッシュ戦略の神髄:`distributed cache`
モノレポでは `node_modules` や `target/` を共有したくなるが、ロック競合でCIが遅くなる。
- 対策: `CACHE_KEY` にブランチ名だけでなく、`checksum` (e.g., `package-lock.json`) を含めよ。
- さらに、`FF_USE_FASTZIP` フラグを有効化せよ。これだけでアーティファクトの圧縮・展開時間が30%以上削減される。
—
4. チーム開発における設定の共有化ルール
モノレポにおいて「設定ファイルが各ディレクトリに散らばる」のは管理の悪夢だ。これを解決する「ベストプラクティス」を提示する。
1. テンプレートの外部化: `ci-templates/` リポジトリを別に作り、`include: remote` で管理する。各モジュールは「何をするか」というビジネスロジックだけに集中させる。
2. `rules` の統一: どのブランチでどのジョブを動かすかのロジックを各モジュールに書くな。`extends` を使い、CIのポリシーをコード(YAML)で強制せよ。
3. `rules:changes` を過信しない: Gitの差分検知は強力だが、マージリクエストの状況によっては誤判定する。必ず「手動トリガー(when: manual)」をバックアップとして忍ばせておけ。
—
最後に:エンジニアの誇りとして
CI/CDパイプラインは、単なる「自動化スクリプト」ではない。それはチームの生産性を左右する「エンジニアリングの心臓部」だ。
パイプラインが遅いということは、開発者がコーヒーを飲みに行っている時間が増え、集中力が削がれ、デプロイに対する心理的障壁が高くなることを意味する。
今日紹介したParent-Child Pipelinesを導入し、パイプラインを「動的」かつ「俊敏」に変えろ。待たされるCIから、開発者の思考速度に追従するCIへ。それが、世界最高峰のDevOpsエンジニアが目指すべき地平だ。
さあ、今すぐYAMLを書き換えに行こう。その1行の最適化が、チームの未来を救うことになる。