Internal Developer Platformの紹介

私の職場は遅く始まり、日本に来てから仕事を始めました。それ以前はずっと自分で起業していました。恥ずかしいことに、ビジネスの規模は大きくなることがなく、最大でも10人程度だったため、大規模なソフトウェアエンジニアチームを管理した経験はありません。この分野の知識は常に不足していました。この度、新しい会社に転職し、ようやくInternal Developer Platform(IDP)がどういうものかを理解しましたので、ここに記録を残します。以下、IDPと呼びます。

私の見解では、IDPの目的は、大規模(少なくとも100人以上)のソフトウェアエンジニアチームが協力して、信頼性の高いソフトウェアを継続的に提供することです。internaldeveloperplatform.orgを調べたところ、いくつかのアウトオブボックスフレームワークがあるものの、全体としては、各企業がビジネスの違いに応じて技術選定を行っているため、ほぼすべてのIDPは企業のインフラチームによって自社開発されています。そのため、IDPを持つ会社で働かない限り、IDPが実際に何であるか、IDPの利点、なぜIDPを採用するのかを理解するのは非常に難しいです。

internaldeveloperplatform.orgによれば、IDPには5つのコアコンポーネントがあり、それぞれアプリケーション設定管理、インフラストラクチャオーケストレーション、環境管理、デプロイメント管理、役割ベースのアクセス制御です。この説明はあまりにも退屈なので、具体的な例を通じて説明します。理解を容易にするため、情報を脱敏化し、一定の簡略化を行います。

一般的なIDPの実装方法は、アプリケーションコード、インフラストラクチャ設定、デプロイ設定、権限管理をできるだけ統一されたGitOpsプロセスに収束させることです。この記事では、monorepo + Bazel + GitHub + Kubernetes + Argo CDを例に説明します。

Monorepo

IDPが最初に目に入るのは巨大なmonorepoで、すべてのチームのすべてのプロジェクトのすべてのソースコードがこのmonorepoに置かれています。あまりにも巨大なため、bazelを使用してビルドを管理しなければなりません。このmonorepoにはソフトウェアのソースコードだけでなく、terraform設定(すなわちInfrastructure as Code)、k8s設定、そしてGitHubのさまざまな設定も含まれています。bazelはGoogleが開発したビルドツールで、超大規模なmonorepo向けに特化しており、すべての言語、すべてのフレームワーク、すべてのプロジェクトをサポートしています。

ソフトウェアコードの更新

aliceはチームteam0のプログラマーで、彼女のプロジェクトはmonorepoのprojects/fooにあります。彼女はある機能を完成させ、foo/feature-xブランチにプッシュし、PRを提出しました。この時、コードの品質を保証するために、インフラチームが開発したGitHub Actionsがすぐに起動し、bazelスクリプトを自動的に実行してlint、CI、コンパイルチェック、新たに追加された依存関係のCVE脆弱性を検出するなどの作業を行います。これらのタスクのいずれかが失敗した場合、マージはできず、aliceはしっかりとコードを書くことを強いられます。

すべてのGitHub Actionsが通過したとしても、alice自身は勝手にコードをマージすることはできません。IDPを使用するのは大企業であり、大企業には独自のプロセスがあります。PRを発起すると、GitHubは自動的にGitHub組織のチーム、つまりteam0のメンバーにコードレビューを要求します。なぜGitHubがfooにteam0のメンバーによるレビューが必要だと知っているのか?それはmonorepoのルートディレクトリにあるCODEOWNERSが設定されているからです。

bobはGitHubからのメール通知を受け取った後、approveをクリックし、lgtmとコメントを残しました。この時点でPRはマージ可能になります。team0の誰でもマージボタンをクリックできます。

mainブランチにマージされた後、インフラチームが開発したGitHubアプリがすぐに起動し、新しいdocker/OCIイメージをパッケージする必要があるかどうかを確認し、必要であればbazelを使用してパッケージを開始します。パッケージが完了すると、自動的に内部のdockerレジストリ(例えばGCPのArtifact Registry)にプッシュされ、monorepoのinfra/k8s/foo/xxx.yaml内のk8sデプロイメントのimage tagを変更するための2つのPRが自動的に発起されます。なぜ2つなのかというと、一つはdev/staging環境のyamlを変更し、もう一つはprod環境のyamlを変更するからです。各PRには、今回のイメージビルドがどのコミットに基づいているかが含まれており、追跡が容易です。

CODEOWNERSに基づき、GitHubはこの時点でteam0にメールを送信します。aliceまたはbobがメールを見た後、approveをクリックしてマージを実行できます。彼らはクリックしても、クリックしなくても構いません。dev/staging環境のPRだけをマージすることも、prod環境のPRだけをマージすることも、何もマージしないこともできます。これは彼らのチームの問題であり、インフラチームは干渉しません。

もしimage tagを変更するPRがmainにマージされた場合、argocdはすぐに同期し、自動的にデプロイを試みます。

依存関係の更新

インフラチームは、あるnpmパッケージが毒されていることを知り、すぐに対応します。monorepoがすべての依存関係を一元管理しているおかげで、彼らはpackage.jsonを更新し、infra/update-x-depsにプッシュしてmainにマージするだけで済みます。このプロセスは上記の流れと同じです。mainが更新されると、プロジェクトfooがこのnpmパッケージに依存しているため、前述のGitHubアプリが自動的にfooのイメージを再度パッケージし、イメージレジストリにプッシュし、monorepoのinfra/k8s/foo/xxx.yaml内のk8sデプロイメントのimage tagを変更するための2つのPRを自動的に発起し、team0の人々にメールを送信します。aliceとbobはマージをクリックし、argocdデプロイをトリガーします。fooだけでなく、このnpmパッケージに依存している他のすべてのプロジェクトも同様のプロセスを自動的に実行します。

インフラチームは、特定の言語/フレームワークのOCIイメージの基盤依存関係(例えばdebianのバージョン)をアップグレードすることを決定した場合、bazelの設定を更新し、再度上記のプロセスを実行するだけです。mainにマージされた後、aliceとbobはimage tagを更新するPRの通知を受け取り、デプロイするかどうかを決定します。

こうして、基盤依存関係のメンテナンスは完全にセキュリティ運用チームに任せられ、アプリケーション開発チームはビジネス実現に専念できます。

ソフトウェアの新規作成

team1のcarolは新しいプロジェクトbarを作成する必要があり、pgデータベースを使用する必要があります。carolは以下を行う必要があります:

  • monorepoのprojectsディレクトリに新しいプロジェクトディレクトリを作成し、bazelが必要とするBUILDファイルを維持する
  • monorepoのterraform関連ディレクトリにdb関連のファイルを作成する
  • monorepoのinfra/k8sディレクトリにbar関連のデプロイメントを作成し、envを入力する。envがsecretの場合、hashicorp vaultを通じて管理する必要があります
  • monorepoのterraformおよびinfra/k8s関連ディレクトリにドメイン名関連の設定を作成する

これらすべての準備が整ったら、carolはPRを発起し、mainにマージします。これらのPRは必ずしもcarolが処理する必要はなく、インフラの人々がterraformの部分を支援することもあります。理想的な状況では、backstageのようなWeb UIがこれらのGitOpsをカプセル化し、社内の開発者にとって、会社のIDPを使用することがSaaSソフトウェアを使用するのと同じくらい簡単になるでしょう。

上記と同様に、PRが発起されると、GitHub ActionsはすぐにCI、bazelスクリプト、lintなどのチェックを実行します。terraformを変更したため、CIはtf-planもチェックします。これらのCIのいずれかが失敗した場合、マージはできません。CODEOWNERSに基づき、terraform関連ディレクトリの変更にはインフラチームの人々によるコードレビューが必要です。メンテナンス責任の分担を明確にするためです。

ソフトウェアアクセス制限

すべてのチームのすべてのソフトウェアは、1つの(dev/staging/prod) k8sにデプロイされており、異なるプロジェクトは単にnamespaceが異なるだけなので、理論的には互いにアクセス可能です。しかし、セキュリティ上の理由から、このようなアクセスはデフォルトで禁止される必要があります。monorepoのk8s部分では、istioルールのセットを定義し、各チームが自分のk8s定義ディレクトリでオーバーライドできるようにします。CODEOWNERSには、同様の変更がmainにマージされる際にインフラチームによるコードレビューが必要であると設定できます。

インターフェース再利用

一部のソフトウェアは社内使用を目的としています。例えば、内部SDKです。これらのSDKのサーバーがk8sにデプロイされると、独自のクラスター内および外部ネットワークのアクセスアドレスが生成されます。前述のbackstageは、アプリケーションの新規作成プロセスを簡素化するだけでなく、チーム内部の人々に明確な内部文書やアーキテクチャの概要を提供し、重複開発を効果的に回避します。

この中で最も重要なのは可観測性であり、dev/prodクラスター内部にはさまざまなコレクターが存在し、grafana cloudのようなプラットフォームに転送されます。

もう一つ重要なのは内部のSSOであり、会社内部ではkeycloakのようなOIDCプロバイダーがデプロイされる可能性があり、他のサービスは登録やログインを再度行う必要がなく、クラスター内のインターフェースに統一的に接続できます。

もう一度5つのコアコンポーネントを見てみる

上記の具体的な例を考慮し、IDPがさまざまな業界ツールを統合して以下の問題を解決する方法を見てみましょう。

アプリケーション設定管理

主にk8sのenv設定を通じて解決されます。secret部分はhashicorp vaultを通じて管理できますが、彼らは本当に高価です。調べたところ、dotenvxenvsecretsなどの代替案もあります。絶対にどんな秘密鍵もプロジェクトのソースコードに直接導入してはいけません。

インフラストラクチャオーケストレーション

主にterraformとk8sのresources requests/limits、node affinity、さらにはkedaなどを通じて解決されます。

環境管理

異なるdev/staging/prod k8sクラスターを準備し、argocdを通じてmonorepoの異なる部分にバインドすることで解決されます。

デプロイメント管理

argocdを通じて解決されます。

役割ベースのアクセス制御

コード変更の管理は主にGitHub Teams、ブランチ保護、ルールセット、CODEOWNERS、必要なステータスチェックを通じて実現されます。ランタイムアクセス制御はKubernetes RBAC、namespaceの隔離、サービスアカウント、ネットワークポリシー、またはIstio AuthorizationPolicyなどのメカニズムを通じて実現されます。

結論

この記事は単なるきっかけに過ぎません。現在、私はインフラチームの一員ではなく、IDPのユーザーに過ぎないため、外部の視点から自分の経験を基にいくつかの推測を行いました。情報の脱敏化のために多くの簡略化と変更を行いました。例えば、実際には私が働いている場所のIDPにはWeb UIがありませんが、私は本当にそれが必要だと思います。コーディングエージェントがGitOpsにWebシェルを提供するのはすぐにできるはずです。IDPはビジネスに強く関連しており、普遍的な標準は存在しません。異なる企業の異なる組織構造、さらにはオフィスの政治がIDPの最終的な姿に影響を与えます。

私自身のいくつかの起業プロジェクトについて言えば、私は現在ソロプレナーであり、自分自身に責任を持つだけで済むため、GitOpsを大幅に簡略化しました。レビューは必要なく、自分自身をレビューすることにも意味はありません。結局、私は自分自身に責任を持つだけです。プッシュするだけで、GitHub Actionsが自動的にCIを実行し、CIが通過すればパッケージ化され、パッケージが完了すれば自動的にimage tagが更新され、argocdが自動的にデプロイします。また、私はbazelのような大規模なツールを使用する必要もなく、npmパッケージで十分です。rustやpythonプロジェクトでもnpmスクリプトを使用できます。

@2026-07-07 16:19