- Published on
Platform EngineeringとBackstageによるInternal Developer Platform構築実践ガイド
- Authors
- Name
- はじめに - Platform Engineeringが従来のDevOpsに取って代わる理由
- Internal Developer Platformの概念と構成要素
- Backstageアーキテクチャとコア機能
- Backstageインストールと初期設定
- Software Catalog構成
- Golden Path Templateの作成
- プラグイン開発と統合
- IDPツール比較
- 運用時の注意事項
- 失敗事例と復旧手順
- チェックリスト
- 参考資料

はじめに - Platform Engineeringが従来のDevOpsに取って代わる理由
「You build it, you run it」というDevOpsの原則は開発者に自律性を与えましたが、同時に膨大な認知負荷(Cognitive Load)をもたらしました。開発者がKubernetesマニフェストを直接作成し、CI/CDパイプラインを設定し、監視ダッシュボードを構成し、インフラプロビジョニングまで担当する状況が生まれたのです。Gartnerは2026年までにソフトウェアエンジニアリング組織の80%がPlatform Engineeringチームを組織すると予測しており、実際にこの流れは現実になっています。
Platform Engineeringは、セルフサービス機能を備えたInternal Developer Platform(IDP)を構築して開発者の認知負荷を軽減し、組織全体のソフトウェアデリバリー速度を向上させるディシプリンです。DevOpsが「文化と実践」に焦点を当てたのに対し、Platform Engineeringは「プロダクトとしてのプラットフォーム」に焦点を当てます。開発者はIDPの顧客であり、プラットフォームチームはこのプロダクトを開発・運用するチームです。
本記事では、CNCF IncubatingプロジェクトであるBackstageを基盤としたIDP構築の全プロセスを解説します。Software Catalog構成、Golden Path Template設計、プラグイン開発、そして運用時に直面する失敗事例と復旧手順まで、実践中心にまとめました。
Internal Developer Platformの概念と構成要素
IDPとは何か
Internal Developer Platform(IDP)は、開発者がインフラや運用の複雑さを気にせずコードに集中できるよう、セルフサービスインターフェースを通じてインフラプロビジョニング、デプロイ、監視、ドキュメントなどを統合提供するプラットフォームです。
IDPの主要な構成要素は以下の通りです:
- Service Catalog:組織内のすべてのサービス、API、リソース、チームのメタデータを一元管理
- Self-Service Portal:開発者がインフラ要求なしに直接環境をプロビジョニング
- Golden Path Template:組織標準に準拠したプロジェクトスキャフォールディングテンプレート
- Documentation Hub:サービスごとの技術ドキュメントをコードリポジトリと連携して自動レンダリング
- Integration Layer:CI/CD、監視、インシデント管理ツールとの連携
IDP vs Developer Portal
IDPとDeveloper Portalはしばしば混同されますが、厳密には区別されます。Developer PortalはIDPのフロントエンドレイヤーです。IDPは、Portalの背後にある自動化層、インフラ抽象化、ポリシーエンジン、ワークフローオーケストレーションまで含むより広い概念です。
┌──────────────────────────────────────────────────────┐
│ Developer Portal (UI) │
│ ┌───────────┐ ┌───────────┐ ┌───────────────────┐ │
│ │ Catalog │ │ Scaffolder│ │ TechDocs │ │
│ └───────────┘ └───────────┘ └───────────────────┘ │
├──────────────────────────────────────────────────────┤
│ Internal Developer Platform │
│ ┌───────────┐ ┌───────────┐ ┌───────────────────┐ │
│ │ IaC Engine│ │ CI/CD │ │ Policy Engine │ │
│ │ (Terraform│ │ (GitHub │ │ (OPA/Kyverno) │ │
│ │ Crossplane│ │ Actions) │ │ │ │
│ └───────────┘ └───────────┘ └───────────────────┘ │
│ ┌───────────┐ ┌───────────┐ ┌───────────────────┐ │
│ │ K8s │ │ Observ- │ │ Secret Mgmt │ │
│ │ Clusters │ │ ability │ │ (Vault) │ │
│ └───────────┘ └───────────┘ └───────────────────┘ │
└──────────────────────────────────────────────────────┘
Backstageアーキテクチャとコア機能
Backstageとは
Backstageは、Spotifyが社内で使用していたDeveloper Portalを2020年にオープンソースとして公開したプロジェクトです。2024年にCNCF Incubatingプロジェクトに昇格し、2026年現在、コミュニティで最も活発に利用されているIDPフレームワークです。
4つのコア機能
Software Catalog:組織のすべてのソフトウェア資産(サービス、ライブラリ、パイプライン、インフラなど)をYAMLベースのメタデータで登録・検索します。サービス間の依存関係、所有権、API仕様を一目で把握できます。
Software Templates(Scaffolder):Golden Pathをコード化します。開発者がUIでいくつかのパラメータを入力するだけで、組織標準に準拠したプロジェクトが自動生成され、Gitリポジトリ作成、CI/CDパイプライン設定、K8sネームスペースプロビジョニングまで一括で実行されます。
TechDocs:docs-as-code方式でMkDocsベースの技術ドキュメントをサービスリポジトリから自動ビルドし、Backstage UIでレンダリングします。ドキュメントがコードと一緒に管理されるため、常に最新の状態が維持されます。
Plugins:Backstageの拡張性の核心です。200以上のコミュニティプラグインが存在し、GitHub、GitLab、PagerDuty、Datadog、ArgoCD、Kubernetesなどと連携できます。独自のプラグインを開発することも可能です。
アーキテクチャ構造
┌─────────────────────────────────────────────────┐
│ Backstage App (React) │
│ ┌─────────┐ ┌──────────┐ ┌─────────────────┐ │
│ │ Catalog │ │ Scaffolder│ │ TechDocs │ │
│ │ Plugin │ │ Plugin │ │ Plugin │ │
│ └─────────┘ └──────────┘ └─────────────────┘ │
│ ┌─────────┐ ┌──────────┐ ┌─────────────────┐ │
│ │ K8s │ │ CI/CD │ │ Custom Plugins │ │
│ │ Plugin │ │ Plugin │ │ │ │
│ └─────────┘ └──────────┘ └─────────────────┘ │
├─────────────────────────────────────────────────┤
│ Backstage Backend (Node.js) │
│ ┌──────────┐ ┌───────────┐ ┌────────────────┐ │
│ │ Catalog │ │ Scaffolder│ │ Auth Provider │ │
│ │ Backend │ │ Backend │ │ (GitHub/Okta) │ │
│ └──────────┘ └───────────┘ └────────────────┘ │
├─────────────────────────────────────────────────┤
│ Database (PostgreSQL) / Search │
└─────────────────────────────────────────────────┘
Backstageは**フロントエンド(React SPA)とバックエンド(Node.js)**に分離された構造です。フロントエンドプラグインはReactコンポーネントとして、バックエンドプラグインはExpressルーターの形で実装されます。データストアにはPostgreSQL(本番)またはSQLite(開発用)を使用します。
Backstageインストールと初期設定
プロジェクト作成
Backstageアプリを作成する最初のステップです。Node.js 18以上とYarn Classic(1.x)が必要です。
# Backstageアプリの作成
npx @backstage/create-app@latest
# プロジェクトディレクトリ構造
# my-backstage-app/
# ├── app-config.yaml # メイン設定ファイル
# ├── app-config.production.yaml # 本番オーバーライド
# ├── catalog-info.yaml # Backstage自体のカタログエントリ
# ├── packages/
# │ ├── app/ # フロントエンド(React)
# │ └── backend/ # バックエンド(Node.js)
# ├── plugins/ # カスタムプラグイン
# └── package.json
# ローカル開発サーバーの起動
cd my-backstage-app
yarn dev
コア設定 - app-config.yaml
app-config.yamlはBackstageの中央設定ファイルです。データベース、認証、カタログソース、統合(Integration)などを定義します。
# app-config.yaml
app:
title: 'ACME Developer Platform'
baseUrl: http://localhost:3000
organization:
name: 'ACME Corp'
backend:
baseUrl: http://localhost:7007
listen:
port: 7007
database:
client: pg
connection:
host: ${POSTGRES_HOST}
port: ${POSTGRES_PORT}
user: ${POSTGRES_USER}
password: ${POSTGRES_PASSWORD}
# GitHub統合設定
integrations:
github:
- host: github.com
token: ${GITHUB_TOKEN}
# 認証プロバイダー設定
auth:
environment: production
providers:
github:
production:
clientId: ${AUTH_GITHUB_CLIENT_ID}
clientSecret: ${AUTH_GITHUB_CLIENT_SECRET}
# カタログソース登録
catalog:
import:
entityFilename: catalog-info.yaml
pullRequestBranchName: backstage-integration
rules:
- allow: [Component, System, API, Resource, Location, Template, Group, User]
locations:
# 組織全体のGitHubリポジトリ自動探索
- type: github-discovery
target: https://github.com/acme-corp/*/blob/main/catalog-info.yaml
# テンプレート登録
- type: file
target: ../../templates/all-templates.yaml
# 組織構造の同期
- type: github-org
target: https://github.com/acme-corp
注意:
GITHUB_TOKENにはrepo、read:org、read:user権限が必要です。Fine-grained Tokenを使用する場合、対象リポジトリに対するContents、Metadata読み取り権限を明示的に付与する必要があります。トークン権限が不足するとカタログ登録時にNotFoundErrorが発生します。
本番デプロイ設定
# app-config.production.yaml
app:
baseUrl: https://developer.acme.com
backend:
baseUrl: https://developer-api.acme.com
cors:
origin: https://developer.acme.com
# TechDocsを外部ストレージに設定
techdocs:
builder: 'external'
generator:
runIn: 'local'
publisher:
type: 'awsS3'
awsS3:
bucketName: 'acme-techdocs'
region: 'ap-northeast-2'
Software Catalog構成
catalog-info.yamlの作成
すべてのソフトウェアエンティティはcatalog-info.yamlファイルを通じてBackstageに登録されます。このファイルはサービスリポジトリのルートに配置され、サービスのメタデータ、所有権、依存関係、API仕様を定義します。
# catalog-info.yaml - マイクロサービス登録の例
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: order-service
title: '注文サービス'
description: '注文作成、決済処理、在庫引き当てを担当するコアドメインサービス'
annotations:
# GitHub連携
github.com/project-slug: acme-corp/order-service
# CI/CD連携
backstage.io/techdocs-ref: dir:.
github.com/workflows: build-and-deploy.yaml
# Kubernetes連携
backstage.io/kubernetes-id: order-service
backstage.io/kubernetes-namespace: order
# PagerDutyインシデント連携
pagerduty.com/service-id: PXXXXXX
# Datadogダッシュボード
datadoghq.com/dashboard-url: https://app.datadoghq.com/dashboard/xxx
tags:
- java
- spring-boot
- grpc
links:
- url: https://grafana.acme.com/d/order-svc
title: 'Grafana Dashboard'
icon: dashboard
- url: https://wiki.acme.com/order-domain
title: 'Domain Wiki'
icon: docs
spec:
type: service
lifecycle: production
owner: team-order
system: ecommerce-platform
providesApis:
- order-api
consumesApis:
- inventory-api
- payment-api
dependsOn:
- resource:order-database
- resource:order-redis
---
# API仕様の登録
apiVersion: backstage.io/v1alpha1
kind: API
metadata:
name: order-api
description: '注文処理gRPC API'
spec:
type: grpc
lifecycle: production
owner: team-order
system: ecommerce-platform
definition:
$text: ./proto/order.proto
---
# データベースリソースの登録
apiVersion: backstage.io/v1alpha1
kind: Resource
metadata:
name: order-database
description: '注文サービスPostgreSQLデータベース'
spec:
type: database
owner: team-order
system: ecommerce-platform
エンティティ関係構造
Backstageのエンティティモデルは階層構造を持ちます:
| エンティティKind | 役割 | 例 |
|---|---|---|
| Domain | ビジネスドメイン領域 | commerce、logistics |
| System | 関連コンポーネントの論理グループ | ecommerce-platform |
| Component | 個別ソフトウェア単位(サービス、ライブラリ、ウェブサイト) | order-service |
| API | コンポーネントが提供するインターフェース | order-api(gRPC/REST/GraphQL) |
| Resource | インフラリソース | order-database、order-redis |
| Group | チーム・組織単位 | team-order |
| User | 個別ユーザー | jane.doe |
この関係構造により、「このサービスは誰が所有し、どのAPIを提供し、どのインフラに依存し、障害時に誰に連絡すべきか」を即座に把握できます。サービスが数百に増えるマイクロサービス環境では、この可視性が決定的に重要です。
Golden Path Templateの作成
Golden Pathは、組織が推奨する「正しい始め方」をコード化したものです。開発者が新しいサービスを開始する際に、CI/CD、テスト、監視、セキュリティ設定がデフォルトで組み込まれたプロジェクトを自動生成できます。
Scaffolder Templateの作成
# templates/spring-boot-service/template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: spring-boot-grpc-service
title: 'Spring Boot gRPCマイクロサービス'
description: |
Spring Boot 3.x + gRPCベースのマイクロサービスプロジェクトを作成します。
含まれるもの:Dockerfile、Helm Chart、GitHub Actions CI/CD、
Prometheusメトリクス、Health Check、catalog-info.yaml
tags:
- java
- spring-boot
- grpc
- recommended
spec:
owner: platform-team
type: service
# ユーザー入力パラメータの定義
parameters:
- title: 'サービス基本情報'
required:
- serviceName
- owner
- system
properties:
serviceName:
title: 'サービス名'
type: string
description: '英小文字とハイフンのみ使用(例:order-service)'
pattern: '^[a-z][a-z0-9-]*$'
ui:autofocus: true
description:
title: 'サービス説明'
type: string
owner:
title: '所有チーム'
type: string
ui:field: OwnerPicker
ui:options:
catalogFilter:
kind: Group
system:
title: '所属システム'
type: string
ui:field: EntityPicker
ui:options:
catalogFilter:
kind: System
- title: '技術オプション'
properties:
javaVersion:
title: 'Javaバージョン'
type: string
enum: ['17', '21']
default: '21'
database:
title: 'データベース'
type: string
enum: ['postgresql', 'mysql', 'none']
default: 'postgresql'
enableKafka:
title: 'Kafka連携'
type: boolean
default: false
- title: 'インフラ設定'
properties:
namespace:
title: 'K8sネームスペース'
type: string
default: 'default'
cluster:
title: 'デプロイクラスター'
type: string
enum: ['dev', 'staging', 'production']
default: 'dev'
# 実行ステップの定義
steps:
# 1. テンプレートからプロジェクトコードを生成
- id: fetch-template
name: 'プロジェクトコード生成'
action: fetch:template
input:
url: ./skeleton
values:
serviceName: ${{ parameters.serviceName }}
description: ${{ parameters.description }}
owner: ${{ parameters.owner }}
system: ${{ parameters.system }}
javaVersion: ${{ parameters.javaVersion }}
database: ${{ parameters.database }}
enableKafka: ${{ parameters.enableKafka }}
namespace: ${{ parameters.namespace }}
# 2. GitHubリポジトリの作成
- id: publish-github
name: 'GitHubリポジトリ作成'
action: publish:github
input:
allowedHosts: ['github.com']
repoUrl: github.com?owner=acme-corp&repo=${{ parameters.serviceName }}
description: ${{ parameters.description }}
defaultBranch: main
protectDefaultBranch: true
requireCodeOwnerReviews: true
repoVisibility: internal
# 3. Backstageカタログに登録
- id: register-catalog
name: 'カタログ登録'
action: catalog:register
input:
repoContentsUrl: ${{ steps['publish-github'].output.repoContentsUrl }}
catalogInfoPath: /catalog-info.yaml
# 4. ArgoCD Application作成
- id: create-argocd-app
name: 'ArgoCDデプロイ設定'
action: argocd:create-resources
input:
appName: ${{ parameters.serviceName }}
argoInstance: main
namespace: ${{ parameters.namespace }}
repoUrl: ${{ steps['publish-github'].output.remoteUrl }}
path: deploy/helm
# 完了後の案内
output:
links:
- title: 'GitHubリポジトリ'
url: ${{ steps['publish-github'].output.remoteUrl }}
- title: 'カタログで確認'
icon: catalog
entityRef: ${{ steps['register-catalog'].output.entityRef }}
このテンプレート1つで、開発者はUIからサービス名といくつかのオプションを選択するだけで、GitHubリポジトリ作成からCI/CDパイプライン設定、K8sデプロイ、カタログ登録まで5分以内に完了します。従来平均3日かかっていた新規サービスのオンボーディングが劇的に短縮されます。
プラグイン開発と統合
カスタムプラグインの作成
Backstage CLIを使用してフロントエンドまたはバックエンドプラグインのスキャフォールディングを行えます。
# フロントエンドプラグインの作成
cd my-backstage-app
yarn new --select plugin
# バックエンドプラグインの作成
yarn new --select backend-plugin
# 生成されたプラグイン構造
# plugins/
# └── my-custom-plugin/
# ├── src/
# │ ├── components/
# │ │ └── ExampleComponent/
# │ ├── plugin.ts # プラグイン定義
# │ ├── routes.ts # ルーティング設定
# │ └── index.ts
# ├── dev/ # 独立開発環境
# │ └── index.tsx
# └── package.json
フロントエンドプラグインの実装例
チーム別サービスヘルス状況をダッシュボードで表示するプラグインの例です。
// plugins/team-health-dashboard/src/plugin.ts
import { createPlugin, createRoutableExtension } from '@backstage/core-plugin-api'
export const teamHealthDashboardPlugin = createPlugin({
id: 'team-health-dashboard',
routes: {
root: rootRouteRef,
},
})
export const TeamHealthDashboardPage = teamHealthDashboardPlugin.provide(
createRoutableExtension({
name: 'TeamHealthDashboardPage',
component: () => import('./components/DashboardPage').then((m) => m.DashboardPage),
mountPoint: rootRouteRef,
})
)
// plugins/team-health-dashboard/src/components/DashboardPage.tsx
import React, { useEffect, useState } from 'react';
import {
Table,
TableColumn,
StatusOK,
StatusError,
StatusWarning,
Progress,
ResponseErrorPanel,
} from '@backstage/core-components';
import { useApi, configApiRef } from '@backstage/core-plugin-api';
import { catalogApiRef } from '@backstage/plugin-catalog-react';
interface ServiceHealth {
name: string;
owner: string;
status: 'healthy' | 'degraded' | 'down';
uptime: number;
lastIncident: string;
errorRate: number;
}
const columns: TableColumn<ServiceHealth>[] = [
{ title: 'サービス', field: 'name' },
{ title: '所有チーム', field: 'owner' },
{
title: 'ステータス',
field: 'status',
render: (row: ServiceHealth) => {
switch (row.status) {
case 'healthy':
return <StatusOK>正常</StatusOK>;
case 'degraded':
return <StatusWarning>パフォーマンス低下</StatusWarning>;
case 'down':
return <StatusError>障害</StatusError>;
default:
return null;
}
},
},
{ title: 'Uptime (%)', field: 'uptime', type: 'numeric' },
{ title: 'エラー率 (%)', field: 'errorRate', type: 'numeric' },
{ title: '最後のインシデント', field: 'lastIncident' },
];
export const DashboardPage = () => {
const catalogApi = useApi(catalogApiRef);
const [services, setServices] = useState<ServiceHealth[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error>();
useEffect(() => {
const fetchData = async () => {
try {
const entities = await catalogApi.getEntities({
filter: { kind: 'Component', 'spec.type': 'service' },
});
// 各サービスのヘルスデータをPrometheus/Datadog APIから取得
const healthData = await Promise.all(
entities.items.map(async entity => {
const metrics = await fetchServiceMetrics(
entity.metadata.name,
);
return {
name: entity.metadata.name,
owner:
entity.spec?.owner?.toString() ?? 'unknown',
status: metrics.status,
uptime: metrics.uptime,
lastIncident: metrics.lastIncident,
errorRate: metrics.errorRate,
};
}),
);
setServices(healthData);
} catch (e) {
setError(e as Error);
} finally {
setLoading(false);
}
};
fetchData();
}, [catalogApi]);
if (loading) return <Progress />;
if (error) return <ResponseErrorPanel error={error} />;
return (
<Table
title="サービスヘルスダッシュボード"
columns={columns}
data={services}
options={{
sorting: true,
paging: true,
pageSize: 20,
search: true,
}}
/>
);
};
主要プラグイン統合一覧
本番IDPで頻繁に統合されるプラグインとその役割:
| プラグイン | 用途 | 設定ポイント |
|---|---|---|
@backstage/plugin-kubernetes | Pod状態、ログ、イベントのリアルタイム表示 | ServiceAccount、RBAC設定 |
@backstage/plugin-techdocs | docs-as-codeベースのドキュメントレンダリング | MkDocs設定、S3/GCSパブリッシャー |
@roadiehq/backstage-plugin-github-insights | PR状況、コントリビューター統計 | GitHub Appトークン |
@backstage/plugin-catalog-import | UIからcatalog-info.yamlを登録 | カタログルール |
@backstage-community/plugin-cost-insights | クラウドコスト可視化 | コストAPI連携 |
@pagerduty/backstage-plugin | オンコール状況、インシデント一覧 | PagerDuty APIキー |
@backstage/plugin-scaffolder-backend-module-github | GitHubリポジトリ自動作成 | GitHub App権限 |
IDPツール比較
Backstage以外にも複数のIDPツールが市場に存在します。組織の規模、技術力、予算によって適切なツールは異なります。
| 項目 | Backstage | Port | Cortex | OpsLevel |
|---|---|---|---|---|
| ライセンス | Apache 2.0(オープンソース) | SaaS(無料ティアあり) | SaaS | SaaS |
| ホスティング | セルフホスティング | クラウドマネージド | クラウドマネージド | クラウドマネージド |
| カスタマイズ性 | 非常に高い(プラグイン開発) | 中程度(ウィジェット/ブループリント) | 低い | 中程度 |
| 初期設定コスト | 高い(専任チーム必要) | 低い | 低い | 低い |
| 運用負担 | 高い(アップグレード、セキュリティ) | なし(SaaS) | なし | なし |
| Service Catalog | YAMLベース、強力 | UIベース、直感的 | 自動ディスカバリー | 自動ディスカバリー |
| スキャフォールディング | 内蔵(Scaffolder) | セルフサービスアクション | 限定的 | サービステンプレート |
| 技術ドキュメント | TechDocs内蔵 | 外部連携 | 外部連携 | 外部連携 |
| スコアカード | プラグインで追加 | 内蔵 | コア機能 | 内蔵 |
| 適合組織 | 大規模、技術力の高いチーム | 中小規模、迅速な導入 | サービス成熟度重視 | 中規模 |
| 価格(50名基準) | 無料(インフラ/人件費別途) | ~$2,000/月 | ~$5,000/月 | ~$3,000/月 |
選択基準のまとめ:専任のPlatform Engineeringチームがあり高いカスタマイズが必要ならBackstage、迅速な導入と低い運用負担を求めるならPort、サービス成熟度の測定と標準準拠に注力したいならCortexが適しています。
運用時の注意事項
導入メトリクスの追跡
IDPを構築するよりも開発者に実際に使ってもらうことの方が難しいです。以下のメトリクスを追跡して導入状況を測定しましょう:
| メトリクス | 測定方法 | 目標 |
|---|---|---|
| カタログカバレッジ | 登録済みサービス数 / 全サービス数 | 95%以上 |
| テンプレート使用率 | テンプレートで作成されたサービス / 全新規サービス | 80%以上 |
| DAU/WAU | Backstage日次/週次アクティブユーザー | 開発者の60%以上 |
| オンボーディング時間 | 新規サービス作成〜初回デプロイまでの所要時間 | 1時間以内 |
| MTTR改善 | 障害発生〜担当チーム認知までの時間 | 既存比50%削減 |
| TechDocs最新性 | 30日以内に更新されたドキュメントの割合 | 70%以上 |
避けるべきアンチパターン
ビッグバンリリース:すべての機能を一度にリリースしようとすると失敗します。MVPから始めましょう。最初のステップはSoftware Catalogだけで十分です。カタログに組織のすべてのサービスを登録し、所有権と依存関係を可視化するだけでも大きな価値を提供します。
プラットフォーム=ポータルの勘違い:UIだけきれいに作って裏に自動化がなければ、開発者はすぐに離れます。「ワンクリックでK8sネームスペースとCI/CDが設定される」実質的な自動化が核心です。
開発者フィードバックの無視:プラットフォームはプロダクトです。開発者アンケート、使用データ分析、定期的なフィードバックセッションなしにプラットフォームチームが「良さそうな」機能だけを作ると導入率が下がります。
Backstageバージョンアップグレードの放置:Backstageはリリースサイクルが速いです(月1〜2回)。6ヶ月以上アップグレードを先延ばしにすると、マイグレーションが極めて困難になります。
backstage-cli versions:bumpコマンドを定期的に実行しましょう。強制的な導入:管理ツールに成り下がると開発者の反感を買います。IDPは開発者体験(DX)を向上させるツールであるべきです。「これを使わなければ処分」ではなく、「これを使えば3日かかっていたことが5分で終わる」がメッセージであるべきです。
Backstageアップグレード手順
# 1. 現在のバージョン確認
yarn backstage-cli info
# 2. バージョンバンプ(依存関係の自動更新)
yarn backstage-cli versions:bump
# 3. 変更内容の確認
git diff
# 4. 型チェック
yarn tsc
# 5. テスト実行
yarn test
# 6. ビルド確認
yarn build
# 7. マイグレーションガイドの確認
# https://backstage.io/docs/getting-started/keeping-backstage-updated
# 推奨:CIで自動的にアップグレードPRを生成
# .github/workflows/backstage-upgrade.yaml
# 毎週月曜日に自動実行してバージョンバンプ後にPRを作成
警告:
versions:bump実行前に必ず現在の変更内容をコミットしてください。アップグレード時にpackage.json、yarn.lock、そして時にはコードマイグレーションが必要なbreaking changeが含まれることがあります。ステージング環境で先に検証してから本番に適用することを推奨します。
失敗事例と復旧手順
事例1:カタログエンティティの同期失敗
症状:GitHubにcatalog-info.yamlが存在するがBackstage UIに表示されない
原因分析:
- GitHubトークンの期限切れまたは権限不足(最も一般的)
- YAML構文エラー(インデント、不正な
kind値) catalog.rulesで該当Kindがallowリストにない- ネットワーク問題によるGitHub API呼び出し失敗
復旧手順:
- Backstageログの確認:
kubectl logs -l app=backstage -c backstage --tail=100 - トークン有効性の検証:
curl -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/user - YAML検証:
npx @backstage/cli catalog-info validate catalog-info.yaml - 手動リフレッシュ:Backstage UIの該当エンティティページで「Refresh」ボタンをクリック
- キャッシュリセットが必要な場合:Backstage Podの再起動
事例2:ScaffolderテンプレートGitHubリポジトリ作成中の失敗
症状:テンプレート実行時に「publish:github」ステップでRequestError: HttpError: Resource not accessible by integrationエラー
原因分析:
- GitHub Appの
Repository: Administration権限の欠如 - 組織のリポジトリ作成ポリシーによるブロック
- 同名のリポジトリが既に存在
復旧手順:
- GitHub App権限の確認と更新
- 組織設定でAppがリポジトリ作成を許可されているか確認
- 失敗したタスクのログをBackstage UIで確認(Scaffolderタスクログページ)
- 部分的に作成されたリソース(空のリポジトリなど)があれば手動でクリーンアップ後に再実行
事例3:PostgreSQL接続プール枯渇
症状:Backstageの応答速度が急激に低下、断続的なConnectionTimeoutError
原因分析:
- カタログエンティティが数千に増加してDB接続が不足
- デフォルトの接続プールサイズ(10個)がトラフィックに対応できない
復旧手順と予防:
# app-config.yaml - 接続プールチューニング
backend:
database:
client: pg
connection:
host: ${POSTGRES_HOST}
port: ${POSTGRES_PORT}
user: ${POSTGRES_USER}
password: ${POSTGRES_PASSWORD}
pool:
min: 5
max: 30
acquireTimeoutMillis: 60000
idleTimeoutMillis: 30000
事例4:TechDocsビルド失敗
症状:サービスページでTechDocsタブが空またはビルドエラー表示
原因分析:
- リポジトリに
mkdocs.ymlファイルがない - Python依存関係(mkdocs-techdocs-core)のインストール失敗
- S3バケット権限の問題(外部パブリッシャー使用時)
復旧手順:
- リポジトリに
mkdocs.ymlとdocs/index.mdが存在するか確認 - ローカルで
npx @techdocs/cli generateコマンドによるビルドテスト - 外部パブリッシャー使用時のIAM権限確認
techdocs.builderをlocalに変更してBackstageが直接ビルドするよう設定変更(小規模環境)
事例5:Backstageアップグレード後のプラグイン互換性の破損
症状:アップグレード後、特定のプラグインページでホワイトスクリーンまたはランタイムエラー
原因分析:
- Backstageコアパッケージとプラグイン間のバージョン不一致
- APIがdeprecatedされた後に削除された
- 新しいBackstageシステム(New Backend System)へのマイグレーションが必要
復旧手順:
- 直ちに前のバージョンにロールバック(Helm rollbackまたは以前のイメージタグでデプロイ)
- ブラウザコンソールでエラーメッセージを確認
- 問題プラグインのGitHub issueを検索
- プラグインを最新の互換バージョンに更新するか、一時的に無効化
- ステージングで検証後に再度本番デプロイ
チェックリスト
IDP構築準備チェックリスト
- Platform Engineering専任チーム組成(最低2〜3名)
- 開発者ペインポイントサーベイの実施(認知負荷が最も大きい領域の把握)
- IDPの最初のMVP範囲の決定(推奨:Software Catalogから開始)
- Backstage vs SaaSツールの比較評価完了
- PostgreSQLインスタンスのプロビジョニング(本番)
- GitHub AppまたはOAuth Appの作成と権限設定
- SSOプロバイダー連携計画(Okta、Azure AD、Googleなど)
Backstage運用チェックリスト
-
app-config.production.yaml分離とシークレット管理(Vault、K8s Secret) - HTTPS/TLS設定(IngressまたはロードバランサーV)
- データベースバックアップスケジュール設定
- 監視構成(Backstageメトリクス + インフラメトリクス)
- 週次バージョンアップグレードワークフロー自動化
- カタログエンティティ検証CI(PRでcatalog-info.yamlの有効性検査)
- 開発者オンボーディングガイドドキュメント作成
- 四半期ごとの開発者満足度調査計画
カタログ登録チェックリスト(サービス別)
-
catalog-info.yamlの作成とリポジトリルートへの配置 -
metadata.nameが組織ネーミング規則に準拠しているか確認 -
spec.ownerが正しいチームグループに設定されているか -
spec.systemが正しいシステムに所属しているか - API仕様(OpenAPI、gRPC、AsyncAPI)の登録
-
annotationsにCI/CD、監視、インシデントツール連携情報を追加 - TechDocs設定(
mkdocs.yml+docs/ディレクトリ) - Kubernetesアノテーション設定(クラスター内ワークロードマッピング)
参考資料
- Backstage公式ドキュメント - What is Backstage?
- Platform Engineering - How to Set Up an Internal Developer Platform
- GitGuardian - Platform Engineering: Building Your Developer Portal with Backstage Part 1
- Growin Blog - Platform Engineering 2026
- The New Stack - In 2026, AI Is Merging with Platform Engineering: Are You Ready?
- CNCF - Backstage Project Page
- Spotify Engineering - How We Use Backstage at Spotify