Platform Engineering実践入門2025 - 開発者体験を劇的に向上させる基盤構築
Platform Engineeringの基本概念から実装まで徹底解説。内部開発者ポータル、セルフサービス化、自動化による開発者体験(DevEx)の向上方法を、具体的な事例とともに紹介します。
Platform Engineeringの概念から実装まで徹底解説。Internal Developer Platform(IDP)の構築方法、Backstageの活用、開発生産性の向上テクニックを実例とともに紹介します。
Platform Engineering は、2025 年のソフトウェア開発において最も注目される分野の 1 つとなっています。クラウドネイティブ時代における開発者の認知的負荷を軽減し、セルフサービス機能を提供することで、組織全体の開発生産性を劇的に向上させます。本記事では、Platform Engineering の基本概念から実践的な実装方法まで、包括的に解説します。
Platform Engineering は、クラウドネイティブ時代におけるソフトウェアエンジニアリング組織のためのセルフサービス機能を可能にするツールチェーンとワークフローを設計・構築する分野です。開発者が本来の価値創造に集中できるよう、インフラストラクチャや運用の複雑さを抽象化します。
チャートを読み込み中...
観点 | DevOps | Platform Engineering |
---|---|---|
アプローチ | 文化とプラクティス | プロダクトとプラットフォーム |
責任範囲 | 開発者が運用も担当 | 専門チームがプラットフォームを提供 |
スケール | チームごとに実装 | 組織全体で標準化 |
認知的負荷 | 開発者に高い負荷 | 抽象化により負荷を軽減 |
標準化 | チームごとに異なる | ゴールデンパスで統一 |
IDP は、開発チームが製品機能をより迅速に提供できるようにする、セルフサービスのAPIツール、サービス、知識、サポートの基盤です。
統一されたUIでのアクセスポイント(Backstage等)
すべてのサービス、API、リソースの中央管理
環境作成、デプロイ、スケーリングの自動化
ベストプラクティスに基づく標準化されたワークフロー
メトリクス、ログ、トレースの統合
Backstage は、Spotify が開発したオープンソースの開発者ポータル構築フレームワークです。実装方法を詳しく見ていきましょう。
# Backstageアプリケーションの作成
npx @backstage/create-app@latest
# プロジェクトディレクトリへ移動
cd my-backstage-app
# 依存関係のインストール
yarn install
# 開発サーバーの起動
yarn dev
# app-config.yaml
app:
title: My Company Developer Portal
baseUrl: http://localhost:3000
organization:
name: My Company
backend:
baseUrl: http://localhost:7007
cors:
origin: http://localhost:3000
catalog:
import:
entityFilename: catalog-info.yaml
pullRequestBranchName: backstage-integration
rules:
- allow: [Component, System, API, Resource, Location, Domain]
locations:
# GitHubからカタログを読み込む
- type: url
target: https://github.com/myorg/service-catalog/blob/main/catalog-info.yaml
# ローカルファイル
- type: file
target: ../../catalog-entities/all.yaml
integrations:
github:
- host: github.com
token: ${GITHUB_TOKEN}
# catalog-info.yaml - サービス定義の例
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: user-service
description: User authentication and management service
annotations:
github.com/project-slug: myorg/user-service
backstage.io/techdocs-ref: dir:.
labels:
tier: backend
tags:
- golang
- authentication
spec:
type: service
lifecycle: production
owner: platform-team
system: auth-system
dependsOn:
- resource:database/users-db
- component:notification-service
providesApis:
- user-api
---
apiVersion: backstage.io/v1alpha1
kind: API
metadata:
name: user-api
description: User Service API
spec:
type: openapi
lifecycle: production
owner: platform-team
definition: |
openapi: "3.0.0"
info:
version: 1.0.0
title: User Service API
paths:
/users:
get:
summary: List all users
/users/{id}:
get:
summary: Get user by ID
---
apiVersion: backstage.io/v1alpha1
kind: System
metadata:
name: auth-system
description: Authentication and authorization system
spec:
owner: platform-team
domain: identity
# template.yaml - サービステンプレートの例
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: microservice-template
title: Microservice Template
description: Create a new microservice with best practices
tags:
- recommended
- microservice
spec:
owner: platform-team
type: service
parameters:
- title: Service Information
required:
- name
- description
properties:
name:
title: Name
type: string
description: Unique name of the service
pattern: '^[a-z0-9-]+$'
description:
title: Description
type: string
description: What does this service do?
- title: Choose Technology Stack
required:
- language
properties:
language:
title: Programming Language
type: string
description: Language to use
enum:
- golang
- nodejs
- python
- java
enumNames:
- Go
- Node.js
- Python
- Java
- title: Infrastructure Options
properties:
database:
title: Database
type: string
enum:
- postgresql
- mysql
- mongodb
- none
cache:
title: Cache
type: string
enum:
- redis
- memcached
- none
steps:
- id: fetch
name: Fetch Base Template
action: fetch:template
input:
url: ./skeleton/${{ parameters.language }}
values:
name: ${{ parameters.name }}
description: ${{ parameters.description }}
- id: publish
name: Publish to GitHub
action: publish:github
input:
description: Initial commit
repoUrl: github.com?owner=myorg&repo=${{ parameters.name }}
defaultBranch: main
- id: register
name: Register in Catalog
action: catalog:register
input:
repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
catalogInfoPath: '/catalog-info.yaml'
output:
links:
- title: Repository
url: ${{ steps.publish.output.remoteUrl }}
- title: Open in catalog
icon: catalog
entityRef: ${{ steps.register.output.entityRef }}
// plugins/custom-plugin/src/plugin.ts
import {
createPlugin,
createRoutableExtension,
} from '@backstage/core-plugin-api';
import { rootRouteRef } from './routes';
export const customPlugin = createPlugin({
id: 'custom-platform-features',
routes: {
root: rootRouteRef,
},
});
export const CustomPlatformPage = customPlugin.provide(
createRoutableExtension({
name: 'CustomPlatformPage',
component: () =>
import('./components/PlatformDashboard').then(m => m.PlatformDashboard),
mountPoint: rootRouteRef,
}),
);
// components/PlatformDashboard.tsx
import React from 'react';
import {
Content,
ContentHeader,
HeaderLabel,
SupportButton,
} from '@backstage/core-components';
import { Grid } from '@material-ui/core';
import { DeploymentStats } from './DeploymentStats';
import { ServiceHealth } from './ServiceHealth';
import { CostAnalytics } from './CostAnalytics';
export const PlatformDashboard = () => {
return (
<Content>
<ContentHeader title="Platform Dashboard">
<HeaderLabel label="Owner" value="Platform Team" />
<HeaderLabel label="Lifecycle" value="Production" />
<SupportButton>
Need help? Contact the platform team
</SupportButton>
</ContentHeader>
<Grid container spacing={3}>
<Grid item xs={12} md={4}>
<DeploymentStats />
</Grid>
<Grid item xs={12} md={4}>
<ServiceHealth />
</Grid>
<Grid item xs={12} md={4}>
<CostAnalytics />
</Grid>
</Grid>
</Content>
);
};
ゴールデンパスは、開発者が迅速かつ安全にソフトウェアをデリバリーするための、標準化されたベストプラクティスのワークフローです。
# .platform/golden-path.yaml
apiVersion: platform.company.com/v1
kind: GoldenPath
metadata:
name: microservice-golden-path
spec:
stages:
- name: development
pipeline:
- step: code-quality
tools:
- sonarqube
- eslint
- step: unit-tests
coverage: 80
- step: build
cache: true
- step: security-scan
tools:
- trivy
- snyk
- name: staging
approvals:
required: false
pipeline:
- step: deploy
strategy: blue-green
- step: integration-tests
- step: performance-tests
sla:
p95_latency: 200ms
error_rate: 0.1%
- name: production
approvals:
required: true
approvers: [tech-lead, platform-team]
pipeline:
- step: deploy
strategy: canary
traffic:
- 10%: 10m
- 50%: 30m
- 100%: 60m
- step: monitoring
alerts:
- error_rate > 1%
- p99_latency > 500ms
開発者が自律的に作業できるセルフサービス機能は、Platform Engineering の中核です。
// self-service-api/src/controllers/environment.controller.ts
import { Request, Response } from 'express';
import { KubernetesClient } from '../clients/kubernetes';
import { TerraformRunner } from '../runners/terraform';
import { validateEnvironmentRequest } from '../validators';
export class EnvironmentController {
constructor(
private k8sClient: KubernetesClient,
private tfRunner: TerraformRunner
) {}
async createEnvironment(req: Request, res: Response) {
try {
// リクエストの検証
const validation = await validateEnvironmentRequest(req.body);
if (!validation.valid) {
return res.status(400).json({ errors: validation.errors });
}
const { name, type, resources, duration } = req.body;
// コスト見積もり
const costEstimate = await this.estimateCost(resources);
// 承認が必要な場合
if (costEstimate.monthly > 1000) {
return res.status(202).json({
status: 'pending_approval',
costEstimate,
approvalUrl: `/approvals/create?env=${name}`
});
}
// 環境の作成
const environment = await this.provisionEnvironment({
name,
type,
resources,
owner: req.user.email,
expiresAt: duration ? new Date(Date.now() + duration) : null
});
// 自動設定
await this.configureEnvironment(environment);
res.status(201).json({
environment,
accessUrl: `https://${name}.dev.company.com`,
credentials: await this.generateCredentials(environment)
});
} catch (error) {
console.error('Environment creation failed:', error);
res.status(500).json({ error: 'Failed to create environment' });
}
}
private async provisionEnvironment(spec: EnvironmentSpec) {
// Terraformワークスペースの作成
const workspace = await this.tfRunner.createWorkspace(spec.name);
// インフラストラクチャのプロビジョニング
const tfVars = {
environment_name: spec.name,
environment_type: spec.type,
resources: spec.resources,
tags: {
Owner: spec.owner,
CreatedBy: 'platform-self-service',
ExpiresAt: spec.expiresAt?.toISOString()
}
};
const result = await this.tfRunner.apply(workspace, tfVars);
// Kubernetesネームスペースの作成
await this.k8sClient.createNamespace(spec.name, {
labels: {
'platform.company.com/owner': spec.owner,
'platform.company.com/type': spec.type
}
});
return result;
}
private async configureEnvironment(environment: Environment) {
// 監視の設定
await this.setupMonitoring(environment);
// ログ収集の設定
await this.setupLogging(environment);
// ネットワークポリシーの適用
await this.applyNetworkPolicies(environment);
// RBACの設定
await this.setupRBAC(environment);
}
private async estimateCost(resources: ResourceSpec): Promise<CostEstimate> {
// AWSコスト計算ツールAPIを使用
const instances = resources.compute.count * resources.compute.size;
const storage = resources.storage.size;
const database = resources.database?.enabled ? 100 : 0;
return {
hourly: instances * 0.1 + storage * 0.001 + database * 0.05,
monthly: (instances * 0.1 + storage * 0.001 + database * 0.05) * 730
};
}
}
// cli/src/commands/deploy.ts
import { Command } from 'commander';
import { PlatformClient } from '../client';
import { loadConfig } from '../config';
import chalk from 'chalk';
import ora from 'ora';
export const deployCommand = new Command('deploy')
.description('Deploy a service to the platform')
.option('-e, --environment <env>', 'Target environment', 'development')
.option('-v, --version <version>', 'Version to deploy')
.option('--dry-run', 'Show what would be deployed')
.action(async (options) => {
const spinner = ora('Preparing deployment...').start();
try {
// 設定の読み込み
const config = await loadConfig();
const client = new PlatformClient(config.apiUrl, config.token);
// プロジェクト情報の取得
spinner.text = 'Analyzing project...';
const projectInfo = await analyzeProject();
// デプロイメント仕様の生成
const deploySpec = {
service: projectInfo.name,
version: options.version || projectInfo.version,
environment: options.environment,
config: projectInfo.platformConfig
};
if (options.dryRun) {
spinner.stop();
console.log(chalk.yellow('Dry run mode - no changes will be made'));
console.log(chalk.blue('Deployment specification:'));
console.log(JSON.stringify(deploySpec, null, 2));
return;
}
// 検証
spinner.text = 'Validating deployment...';
const validation = await client.validateDeployment(deploySpec);
if (!validation.valid) {
spinner.fail('Validation failed');
console.error(chalk.red('Validation errors:'));
validation.errors.forEach(err => console.error(` - ${err}`));
process.exit(1);
}
// デプロイの実行
spinner.text = 'Deploying service...';
const deployment = await client.deploy(deploySpec);
// 進捗の監視
await monitorDeployment(client, deployment.id, spinner);
spinner.succeed('Deployment completed successfully!');
console.log(chalk.green(`\nService URL: ${deployment.url}`));
console.log(chalk.blue(`View logs: platform logs ${projectInfo.name}`));
} catch (error) {
spinner.fail('Deployment failed');
console.error(chalk.red(error.message));
process.exit(1);
}
});
async function monitorDeployment(
client: PlatformClient,
deploymentId: string,
spinner: ora.Ora
) {
let status = 'in_progress';
while (status === 'in_progress') {
const deployment = await client.getDeployment(deploymentId);
status = deployment.status;
spinner.text = `Deploying... ${deployment.progress}%`;
if (deployment.currentStep) {
spinner.text += ` (${deployment.currentStep})`;
}
await new Promise(resolve => setTimeout(resolve, 2000));
}
if (status !== 'success') {
throw new Error(`Deployment failed: ${status}`);
}
}
Platform Engineering では、プラットフォームの使用状況を継続的に監視し、改善することが重要です。
# grafana-dashboard.json
{
"dashboard": {
"title": "Platform Engineering Metrics",
"panels": [
{
"title": "Developer Productivity",
"type": "graph",
"targets": [
{
"expr": "rate(deployments_total[1h])",
"legendFormat": "Deployments/hour"
},
{
"expr": "avg(deployment_duration_seconds)",
"legendFormat": "Avg deployment time"
}
]
},
{
"title": "Platform Adoption",
"type": "stat",
"targets": [
{
"expr": "count(distinct(user))",
"legendFormat": "Active users"
},
{
"expr": "count(service_catalog_entries)",
"legendFormat": "Services in catalog"
}
]
},
{
"title": "Self-Service Usage",
"type": "heatmap",
"targets": [
{
"expr": "sum by (action) (platform_api_requests_total)",
"legendFormat": "{{action}}"
}
]
},
{
"title": "Cost Optimization",
"type": "gauge",
"targets": [
{
"expr": "sum(resource_cost_dollars) / sum(resource_allocated)",
"legendFormat": "Cost efficiency"
}
]
}
]
}
}
開発者の満足度を定期的に測定し、フィードバックを元に継続的に改善することが、Platform Engineering の成功の鍵です。私たちは四半期ごとに NPS サーベイを実施し、開発者体験を数値化しています。
// developer-satisfaction-survey.ts
interface DeveloperSurvey {
questions: {
nps: {
question: "プラットフォームを同僚に推奨する可能性は?";
scale: [0, 10];
};
productivity: {
question: "プラットフォームは生産性向上に貢献していますか?";
options: ["大いに貢献", "貢献", "どちらでもない", "妨げている", "大いに妨げている"];
};
painPoints: {
question: "最も改善してほしい点は?";
type: "open-ended";
};
};
}
class SatisfactionAnalyzer {
async analyzeSurveyResults(responses: SurveyResponse[]) {
const npsScore = this.calculateNPS(responses);
const productivityScore = this.calculateProductivityScore(responses);
const painPoints = this.extractPainPoints(responses);
return {
nps: npsScore,
productivity: productivityScore,
topPainPoints: painPoints.slice(0, 5),
recommendations: this.generateRecommendations(painPoints)
};
}
private calculateNPS(responses: SurveyResponse[]): number {
const scores = responses.map(r => r.nps);
const promoters = scores.filter(s => s >= 9).length;
const detractors = scores.filter(s => s <= 6).length;
return ((promoters - detractors) / scores.length) * 100;
}
}
Platform Engineering を組織に導入する際の戦略的アプローチを解説します。
1-2チームで小規模に開始し、価値を実証
基本的なセルフサービス機能とゴールデンパスの実装
全開発チームへの展開と採用促進
フィードバックに基づく継続的改善
役割 | 責任 | 必要なスキル |
---|---|---|
Platform Product Manager | ビジョンとロードマップ策定 | プロダクト管理、開発者理解 |
Platform Engineer | プラットフォーム構築と運用 | インフラ、自動化、プログラミング |
Developer Advocate | 採用促進と教育 | コミュニケーション、技術文書作成 |
Site Reliability Engineer | 信頼性と性能の確保 | モニタリング、インシデント対応 |
Security Engineer | セキュリティのビルトイン | セキュリティ、コンプライアンス |
成功する Platform Engineering のためのベストプラクティスを紹介します。
Platform Engineering 導入時の包括的なチェックリストです。
カテゴリ | チェック項目 | 優先度 |
---|---|---|
戦略 | ビジョンとロードマップの策定 | 高 |
戦略 | ステークホルダーの合意形成 | 高 |
技術 | 開発者ポータルの構築 | 高 |
技術 | CI/CDパイプラインの標準化 | 高 |
技術 | インフラのコード化 | 中 |
プロセス | セルフサービスワークフローの定義 | 高 |
プロセス | 承認プロセスの自動化 | 中 |
文化 | 開発者コミュニティの構築 | 中 |
文化 | ナレッジ共有の仕組み | 中 |
計測 | KPIの定義と追跡 | 高 |
Platform Engineering は、開発者の生産性を劇的に向上させる強力なアプローチです。本記事で解説した内容をまとめます:
Platform Engineering は単なる技術的な取り組みではなく、組織全体の開発文化を変革する戦略的なアプローチです。本記事を参考に、あなたの組織でも Platform Engineering の導入を検討してみてください。