成長するエンジニアリング組織が直面するスプロール(肥大化)の課題
エンジニアリング組織が50人規模を超えると、マイクロサービスアーキテクチャは急速に複雑化しがちです。私たちの現場でも、マイクロサービスが80個を突破したあたりから深刻な運用摩擦が生じ始めました。
開発者は毎スプリント、単純な疑問の答えを探すために何時間も浪費していました。「auth-billing サービスのオーナーは誰か?」「決済 Webhook を担当している Slack チャンネルはどこか?」「gRPC のインターフェース定義(契約)はどこにあるのか?」新入社員のオンボーディングには丸2週間かかり、その大半はローカル環境のセットアップや IAM 権限の申請、あちこちに散らばったリポジトリのクローン作業に費やされていました。
この toil(雑務)のしわ寄せを最も受けたのが DevOps エンジニアでした。プラットフォームチームは、インフラの信頼性向上に注力する代わりに、スプリントの約30%をヘルプデスクのような対応に費やしていました。GitHub リポジトリの手動作成、Terraform のボイラープレートの整備、ステージングや本番クラスタへの Kubernetes デプロイマニフェストのコピペ作業に追われていたのです。その一方で、ドキュメントは放置された Confluence スペース、陳腐化した README、個人の Notion ワークスペースという3箇所に分散し、内容が矛盾していました。
こうした認知負荷を軽減するためには、すべての情報を一元化する「single pane of glass(統合ダッシュボード)」が必要でした。そこで大きな価値を発揮したのが Spotify Backstage です。2016年に Spotify が開発し、2020年に CNCF に寄贈された Backstage は、内部開発者ポータル(Internal Developer Portal: IDP)を構築するためのオープンソースフレームワークです。サービスのオーナーシップ管理、Docs-as-Code、プロジェクトのスキャフォールディング(雛形生成)を一元化されたハブに集約します。
Spotify Backstage の基本コンセプト
Backstage は、React フロントエンドと Express 上で動作する Node.js バックエンドで構成されています。既存のインフラツールを置き換えるのではなく、モジュール式プラグインを介して GitHub、GitLab、Kubernetes、SonarQube、ArgoCD などのツールとシームレスに連携します。システムの中核を成すのは以下の3つの柱です。
- Software Catalog: サービス、ライブラリ、データベース、パイプラインを一元的に追跡する台帳。軽量な YAML ファイルを用い、ソースコード内でオーナーシップ、システムの境界、API の依存関係を直接宣言します。
- TechDocs: Spotify が提唱する Docs-as-Code ソリューション。エンジニアはソースコードと同じリポジトリの
/docsディレクトリ配下に Markdown でドキュメントを記述します。Backstage は MkDocs を利用してポータル UI 内に検索可能な HTML ページをビルド・描画します。 - Software Templates(Scaffolder): アーキテクチャ標準をセルフサービス型のフォームへと変換する自動化エンジン。開発者がいくつかの入力項目を入力するだけで、CI/CD パイプライン、リンター、監視設定があらかじめ組み込まれた検証済みのリポジトリが自動生成されます。
実践ハンズオン:Backstage のデプロイと設定
ステップ 1: Backstage インスタンスの初期化
Node.js(Active LTS バージョン 18 または 20)と Yarn がインストールされていることを確認してください。Backstage は Yarn ワークスペースに依存しているため、そのモノレポ構造を管理する上で npm の使用は推奨されません。公式のブートストラップコマンドを実行します。
npx @backstage/create-app@latest --skip-install
cd my-developer-portal
yarn install
yarn dev
フロントエンドは http://localhost:3000 で起動し、バックエンド API はポート 7007 でリクエストを処理します。ローカル開発ではインメモリの SQLite データベースが使用されますが、本番環境へのデプロイでは通常 PostgreSQL 14 以降に接続します。
ステップ 2: Software Catalog でコンポーネントを定義する
各サービスはコードを通じて自身のメタデータを公開します。サービスリポジトリのルートに catalog-info.yaml ファイルを追加します。
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: payments-api
description: StripeのWebhookを処理するコア決済オーケストレーションサービス
annotations:
github.com/project-slug: itfromzero/payments-api
backstage.io/techdocs-ref: dir:.
tags:
- payments
- go
- grpc
spec:
type: service
lifecycle: production
owner: group:payment-platform-team
system: core-finance
providesApis:
- payments-grpc-api
このエンティティをポータルのグローバル設定ファイル(app-config.yaml)に登録します。
catalog:
locations:
- type: url
target: https://github.com/itfromzero/payments-api/blob/main/catalog-info.yaml
rules:
- allow: [Component, System, API]
Backstage はこの場所を定期的にクロールしてエンティティを登録し、チーム間のサービス依存関係グラフを自動的にマッピングします。
ステップ 3: TechDocs(Docs-as-Code)の有効化
一元管理型の Wiki は、日々のプルリクエストから遠く離れた場所にあるため陳腐化しがちです。TechDocs は、技術ドキュメントをそれが説明するコードのすぐ隣に配置することでこの問題を解決します。リポジトリのルートに mkdocs.yml ファイルを作成します。
site_name: Payments API ドキュメント
plugins:
- techdocs-core
nav:
- 概要: index.md
- アーキテクチャ: architecture.md
- トラブルシューティング: troubleshooting.md
docs/ ディレクトリを作成し、その中に index.md ファイルを用意してガイドを執筆します。
# Payments API
Payments サービスの開発者向けドキュメントへようこそ。
## クイックスタート
Docker Compose を使用してローカルの依存関係を起動します:
```bash
docker-compose up -d redis postgres
go run cmd/server/main.go
```
エンジニアが Backstage 上で該当コンポーネントを開くと、プラットフォームは backstage.io/techdocs-ref アノテーションを検出し、バックグラウンドコンテナまたはビルドワーカーで MkDocs コンパイラを実行して、検索可能なドキュメントをポータル内に直接表示します。
ステップ 4: Software Templates によるゴールデンパスのスキャフォールディング自動化
セルフサービステンプレートは、Backstage が最も迅速に投資対効果を発揮できる機能です。インフラ申請チケットの DevOps によるレビューを何日も待つ代わりに、プロダクト開発者は Web フォームに入力するだけで済みます。テンプレートエンジンがパラメータをバリデーションし、スケルトンリポジトリを複製して変数を置換し、リモートの Git リポジトリを作成してデフォルトの CI/CD ワークフローを注入します。
以下は、実際に動作するテンプレート定義(template.yaml)の例です。
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: create-standard-microservice
title: 標準 Node.js サービス
description: DockerとGitHub Actionsを備えた本番環境対応のNode.js REST APIを自動生成します
spec:
owner: group:platform-core
type: service
parameters:
- title: サービス詳細
required:
- component_id
- description
- owner
properties:
component_id:
title: サービス名
type: string
description: コンポーネントの一意なkebab-case名
description:
title: 説明
type: string
owner:
title: オーナーチーム
type: string
ui:field: OwnerPicker
ui:options:
catalogFilter:
kind: Group
- title: リポジトリ設定
required:
- repoUrl
properties:
repoUrl:
title: リポジトリの場所
type: string
ui:field: RepoUrlPicker
ui:options:
allowedHosts:
- github.com
steps:
- id: fetch-base
name: スケルトンの取得
action: fetch:template
input:
url: ./skeleton
values:
component_id: ${{ parameters.component_id }}
description: ${{ parameters.description }}
owner: ${{ parameters.owner }}
- id: publish-github
name: GitHubへ公開
action: publish:github
input:
allowedHosts: ['github.com']
description: ${{ parameters.description }}
repoUrl: ${{ parameters.repoUrl }}
defaultBranch: main
- id: register-catalog
name: Software Catalogに登録
action: catalog:register
input:
repoContentsUrl: ${{ steps['publish-github'].output.repoContentsUrl }}
catalogInfoPath: '/catalog-info.yaml'
output:
links:
- title: GitHubで開く
url: ${{ steps['publish-github'].output.remoteUrl }}
- title: カタログで表示
icon: catalog
entityRef: ${{ steps['register-catalog'].output.entityRef }}
テンプレートに対応する skeleton/ ディレクトリ内には、${{ values.component_id }} のような変数を含んだ定型ソースコードを配置します。実行時、Backstage はこれらのアクションを順次処理し、GitHub リポジトリを初期化して、新しいサービスを Software Catalog に即座に登録します。
私たちの本番環境では、このワークフローによってチーム間の調整を含めて約36時間かかっていたサービスプロビジョニング時間を、わずか8分に短縮しました。さらに、設定のドリフト(乖離)を根本から防止できるようになりました。新規リポジトリには、ヘルスチェックエンドポイント、Datadog によるトレーシング、脆弱性スキャナーがあらかじめ有効化された状態でプロビジョニングされます。
持続可能なプラットフォームマインドセットの確立
内部開発者ポータルの導入は単なるソフトウェアのインストールではなく、組織文化の変革です。Backstage を独自のロードマップを持つ社内プロダクトとして扱いましょう。プロダクトチームからのフィードバックを収集し、明確なカタログ所有権ルールを策定し、安全でコンプライアンスに準拠した選択肢が「最も進みやすい道」となるようなゴールデンパスを設計していくことが成功の鍵となります。

