ブログ記事

Platform Engineering実践入門2025 - 開発者体験を劇的に向上させる基盤構築

Platform Engineeringの概念から実装まで徹底解説。Internal Developer Platform(IDP)の構築方法、Backstageの活用、開発生産性の向上テクニックを実例とともに紹介します。

ツール
Platform Engineering DevOps IDP Backstage 開発者体験
Platform Engineering実践入門2025 - 開発者体験を劇的に向上させる基盤構築のヒーロー画像

Platform Engineering は、2025 年のソフトウェア開発において最も注目される分野の 1 つとなっています。クラウドネイティブ時代における開発者の認知的負荷を軽減し、セルフサービス機能を提供することで、組織全体の開発生産性を劇的に向上させます。本記事では、Platform Engineering の基本概念から実践的な実装方法まで、包括的に解説します。

この記事で学べること

  • Platform Engineering の基本概念と devops との違い
  • Internal Developer Platform(IDP)の設計と構築方法
  • Backstage を使った開発者ポータルの実装
  • ゴールデンパスの設計とセルフサービス化
  • 組織への導入戦略とベストプラクティス

Platform Engineeringとは何か?

Platform Engineering は、クラウドネイティブ時代におけるソフトウェアエンジニアリング組織のためのセルフサービス機能を可能にするツールチェーンとワークフローを設計・構築する分野です。開発者が本来の価値創造に集中できるよう、インフラストラクチャや運用の複雑さを抽象化します。

Platform Engineeringのエコシステム

チャートを読み込み中...

Platform EngineeringとDevOpsの違い

DevOpsとPlatform Engineeringの比較
観点 DevOps Platform Engineering
アプローチ 文化とプラクティス プロダクトとプラットフォーム
責任範囲 開発者が運用も担当 専門チームがプラットフォームを提供
スケール チームごとに実装 組織全体で標準化
認知的負荷 開発者に高い負荷 抽象化により負荷を軽減
標準化 チームごとに異なる ゴールデンパスで統一

Internal Developer Platform(IDP)の構築

IDP は、開発チームが製品機能をより迅速に提供できるようにする、セルフサービスのAPIツール、サービス、知識、サポートの基盤です。

IDPの核心コンポーネント

開発者ポータル

統一されたUIでのアクセスポイント(Backstage等)

サービスカタログ

すべてのサービス、API、リソースの中央管理

セルフサービス機能

環境作成、デプロイ、スケーリングの自動化

ゴールデンパス

ベストプラクティスに基づく標準化されたワークフロー

観測性と分析

メトリクス、ログ、トレースの統合

IDP設計の原則

IDP設計の5つの原則

  1. 開発者ファースト: 開発者の体験を最優先に設計
  2. セルフサービス: 手動プロセスを最小化
  3. 標準化と柔軟性: ゴールデンパスを提供しつつカスタマイズも可能に
  4. プロダクト思考: IDP をプロダクトとして扱い、継続的に改善
  5. 段階的導入: 小さく始めて徐々に拡張

Backstageによる開発者ポータルの実装

Backstage は、Spotify が開発したオープンソースの開発者ポータル構築フレームワークです。実装方法を詳しく見ていきましょう。

Backstageのセットアップ

# 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>
  );
};

ゴールデンパスの設計と実装

ゴールデンパスは、開発者が迅速かつ安全にソフトウェアをデリバリーするための、標準化されたベストプラクティスのワークフローです。

ゴールデンパスの要素

標準化されたCI/CDパイプライン 100 %
完了
セキュリティのビルトイン 95 %
監視とログの自動設定 90 %
コスト最適化の自動化 85 %

実装例:マイクロサービスのゴールデンパス

# .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 as Code実装

# 手動でインフラを設定 1. AWSコンソールにログイン 2. EC2インスタンスを作成 3. セキュリティグループを設定 4. ロードバランサーを設定 5. RDSデータベースを作成 6. 監視を設定 7. ログ収集を設定 8. バックアップを設定 # 問題点: - 再現性がない - ヒューマンエラーのリスク - ドキュメント化が困難 - 環境間の差異
# platform.tf - Terraformによる宣言的設定 module "microservice_platform" { source = "./modules/golden-path" service_name = "user-service" environment = "production" compute = { instance_type = "t3.medium" min_size = 2 max_size = 10 autoscaling = { target_cpu = 70 scale_in_cooldown = 300 } } database = { engine = "postgres" version = "14" instance_class = "db.t3.medium" backup_retention = 7 } observability = { enable_apm = true enable_logging = true log_retention = 30 alerts = [ { name = "high_error_rate" threshold = 0.01 evaluation_periods = 2 } ] } }
従来の手動設定
# 手動でインフラを設定 1. AWSコンソールにログイン 2. EC2インスタンスを作成 3. セキュリティグループを設定 4. ロードバランサーを設定 5. RDSデータベースを作成 6. 監視を設定 7. ログ収集を設定 8. バックアップを設定 # 問題点: - 再現性がない - ヒューマンエラーのリスク - ドキュメント化が困難 - 環境間の差異
Platform as Codeアプローチ
# platform.tf - Terraformによる宣言的設定 module "microservice_platform" { source = "./modules/golden-path" service_name = "user-service" environment = "production" compute = { instance_type = "t3.medium" min_size = 2 max_size = 10 autoscaling = { target_cpu = 70 scale_in_cooldown = 300 } } database = { engine = "postgres" version = "14" instance_class = "db.t3.medium" backup_retention = 7 } observability = { enable_apm = true enable_logging = true log_retention = 30 alerts = [ { name = "high_error_rate" threshold = 0.01 evaluation_periods = 2 } ] } }

セルフサービス機能の実装

開発者が自律的に作業できるセルフサービス機能は、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 ツールの実装

// 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 サーベイを実施し、開発者体験を数値化しています。

Platform Engineering Manager 大手テック企業
// 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 Engineeringチームの構成
役割 責任 必要なスキル
Platform Product Manager ビジョンとロードマップ策定 プロダクト管理、開発者理解
Platform Engineer プラットフォーム構築と運用 インフラ、自動化、プログラミング
Developer Advocate 採用促進と教育 コミュニケーション、技術文書作成
Site Reliability Engineer 信頼性と性能の確保 モニタリング、インシデント対応
Security Engineer セキュリティのビルトイン セキュリティ、コンプライアンス

ベストプラクティスとアンチパターン

成功する Platform Engineering のためのベストプラクティスを紹介します。

ベストプラクティス

Platform Engineering成功の秘訣

  1. 小さく始めて段階的に拡大: 全てを一度に解決しようとしない
  2. 開発者の声を聞く: 定期的なフィードバックセッションを実施
  3. ドキュメントの充実: セルフサービスには優れたドキュメントが不可欠
  4. 計測と改善: メトリクスに基づいた意思決定
  5. コミュニティの構築: 社内の Platform Engineering コミュニティを育成

避けるべきアンチパターン

よくある失敗パターン

  • 強制的な移行: 開発者に選択肢を与えずに強制する
  • 過度な抽象化: 必要以上に複雑な抽象化レイヤー
  • フィードバックの無視: 開発者の要望を聞かない
  • メンテナンスの軽視: プラットフォームの継続的な改善を怠る
  • 全てを自作: 既存のツールを活用せずに車輪の再発明

実装チェックリスト

Platform Engineering 導入時の包括的なチェックリストです。

Platform Engineering実装チェックリスト
カテゴリ チェック項目 優先度
戦略 ビジョンとロードマップの策定
戦略 ステークホルダーの合意形成
技術 開発者ポータルの構築
技術 CI/CDパイプラインの標準化
技術 インフラのコード化
プロセス セルフサービスワークフローの定義
プロセス 承認プロセスの自動化
文化 開発者コミュニティの構築
文化 ナレッジ共有の仕組み
計測 KPIの定義と追跡

まとめ

Platform Engineering は、開発者の生産性を劇的に向上させる強力なアプローチです。本記事で解説した内容をまとめます:

本記事のポイント

  • Platform Engineering は開発者の認知的負荷を軽減し、価値創造に集中できる環境を提供
  • Internal Developer Platform(IDP)により、セルフサービスで必要なリソースを即座に利用可能
  • Backstage などのツールを活用し、統一された開発者体験を実現
  • ゴールデンパスにより、ベストプラクティスを標準化しつつ柔軟性も確保
  • 継続的な測定と改善により、プラットフォームを進化させることが重要

Platform Engineering は単なる技術的な取り組みではなく、組織全体の開発文化を変革する戦略的なアプローチです。本記事を参考に、あなたの組織でも Platform Engineering の導入を検討してみてください。

この記事は役に立ちましたか?

Daily Hackでは、開発者の皆様に役立つ情報を毎日発信しています。