100以上のマイクロサービス管理で「頭を抱えない」ために:なぜGit Submoduleを捨ててRepoに移行すべきなのか?

Git tutorial - IT technology blog
Git tutorial - IT technology blog

午前2時の悪夢:Git Submoduleに「裏切られた」瞬間

午前2時、スマートフォンが鳴り止みません。会社のマイクロサービスシステムがダウンしました。15個のサービスを先週の安定版に急いでロールバックする必要があります。当時、チームはメインリポジトリ内でサブリポジトリを管理するためにGit Submoduleを使用していました。

結果はどうだったか?まさに惨劇でした。各サブモジュールのコミットハッシュを管理するのは苦行です。<a href="https://itfromzero.com/ja/git-ja/git%e3%81%ae10%e5%a4%a7%e3%83%88%e3%83%a9%e3%83%96%e3%83%ab%e5%af%be%e5%87%a6%e6%b3%95%ef%bc%9adetached-head%e3%81%8b%e3%82%89%e5%89%8a%e9%99%a4%e3%81%97%e3%81%9f%e3%82%b3%e3%83%9f%e3%83%83%e3%83%88.html">detached HEAD</a>エラーが頻発します。開発者がサブリポジトリでのコードのプッシュを忘れ、親リポジトリのハッシュだけを更新してしまえば、CI/CDパイプラインは即座に停止します。その夜、私はGitポインタの混乱を片付けるだけで4時間を費やしました。

翌朝、私は別の解決策を探すことに決めました。そこで出会ったのがrepo (Git-repo)です。これはGoogleがAndroidプロジェクト(AOSP)で1,000以上のリポジトリを調整するために使用している「屋台骨」となるツールです。

巨大なマイクロサービスプロジェクトにおける選択肢とは?

プロジェクトが10から100のマイクロサービスへと膨れ上がると、コードの管理方法がリリースの速度を左右するようになります。一般的な3つのアプローチを見てみましょう:

1. モノレポ (Monorepo – 全てを一つの箱に)

  • メリット: コード検索が容易、1コミットで複数サービスを変更可能。
  • デメリット: リポジトリが数十GBになり、クローンに半日かかることも。権限管理が非常に難しく、BazelやNxのような高度なツールがないとCI/CDが遅くなります。

2. Git Submodule (リポジトリの中にリポジトリを)

  • メリット: Gitの標準機能。
  • デメリット: UXが最悪。親と子のリポジトリ間のバージョン追跡でミスが起きやすい。サブモジュールが50を超えると、手動管理はほぼ不可能です。

3. Repoツール (ハイブリッドな解決策)

  • メリット: 各リポジトリの独立性を保ちつつ、マニフェストファイル(XML)で集中管理。コマンド一つで200のリポジトリを同期可能。
  • デメリット: 外部のPythonスクリプトをインストールする必要がある。

20〜50人規模のチームにとって、repoは完璧な妥協点です。Polyrepoの柔軟性を維持しつつ、Monorepoのような集中管理機能を提供します。

Repoの核心:マニフェストファイルの威力

repoはコードを直接保存するのではなく、マニフェストファイルを通じてリポジトリのリストを管理します。これは、どのリポジトリがどこにあり、どのブランチを使用し、ローカルのどのディレクトリに保存するかを示す全体マップのようなものです。

実際のdefault.xmlファイルは、通常このようにシンプルです:

<?xml version="1.0" encoding="UTF-8"?>
<manifest>
  <remote name="origin" fetch=".." />
  <default revision="main" remote="origin" sync-j="8" />

  <!-- マイクロサービス一覧 -->
  <project path="services/auth" name="my-org/auth-service" />
  <project path="services/order" name="my-org/order-service" />
  <project path="libs/common" name="my-org/shared-library" />
</manifest>

Repoを導入するための3ステップ

ステップ1:ツールのインストール

repoの実体は、GitをラップしたPythonスクリプトです。LinuxやmacOSなら、一瞬でインストールできます:

mkdir -p ~/.bin
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.bin/repo
chmod a+rx ~/.bin/repo
export PATH=$PATH:~/.bin

ステップ2:マニフェストリポジトリの作成

default.xmlを格納するための専用リポジトリ(例:manifests.git)を作成します。これがプロジェクト構造の唯一の「信頼できる情報源(Source of Truth)」となります。

ステップ3:プロジェクトの初期化

開発者は一つずつgit cloneして疲弊する代わりに、以下を実行するだけです:

# マニフェストに接続
repo init -u [email protected]:my-org/manifests.git -b main

# 100以上の全リポジトリをローカルにダウンロード
repo sync -j16

repo syncコマンドは、全プロジェクトを自動的にクローンまたは更新します。-j16パラメータにより16スレッド並列ダウンロードが可能になり、待ち時間を70%削減できます。

DevOpsエンジニアのための「救世主」コマンド

大規模システムを扱う際、私は迅速な処理のために以下の「秘策」をよく使います:

システム全体のステータス確認: 各フォルダにcdする必要はありません。forallを使って一括スキャンしましょう:

repo forall -c 'git branch | grep "*"'

リリースに向けた一括ブランチ作成: 80個のリポジトリに対して同時にrelease-v2.0ブランチを作成する必要がありますか?非常に簡単です:

repo start release-v2.0 --all

実体験から得た「血肉となる」教訓

85個のリポジトリを抱える直近のプロジェクトでは、repoの導入により、週に20件あった設定ミスのチケットがほぼゼロになりました。ただし、以下の点に注意が必要です:

  • マニフェストは絶対: ディレクトリ構造の変更は、チームにコードの同期を促す前に必ずマニフェストにコミットしてください。
  • マルチコアの力を活用: 同期時は常に-jを使いましょう。高速なオフィス回線なら、-j16-j32を使うことで、コードのダウンロードは「コーヒーを淹れに行く時間」から「数秒」に変わります。
  • 適材適所: プロジェクトが3〜5個のリポジトリしかないなら、通常のGitを使いましょう。repoが真価を発揮するのは、リポジトリの数が人間の管理能力を超えた時です。

このプロセスを8人のチームに適用した後、サービス間のバージョンの不一致は完全に解消されました。何より、共有ライブラリのバージョンが正しいかどうかを確認するために夜更かしをする必要がなくなったのが最大の収穫です。

もしあなたがバラバラなマイクロサービスの管理に苦労しているなら、ある日の午後にでもrepoをセットアップしてみてください。信じてください、ワークフローが劇的にプロフェッショナルなものに変わりますよ。

Share: