Twelve-Factor Appとは
Twelve-Factor Appは、Herokuの共同創業者であるAdam Wiggins氏が2011年に提唱した、モダンなWebアプリケーションを構築するための12の設計原則です。クラウド環境で動作するSaaS(Software as a Service)に適した設計を実現します。
なぜ重要か: コンテナ化、マイクロサービス、CI/CDが当たり前となった現代において、これらの原則はクラウドネイティブなアプリケーション設計の基礎となっています。
12の原則
1. コードベース(Codebase)
バージョン管理される1つのコードベースから、複数のデプロイを行う。
flowchart LR
Repo["リポジトリ"] --> Dev["開発環境"]
Repo --> Staging["ステージング環境"]
Repo --> Prod["本番環境"]
- ✗ 環境ごとに異なるリポジトリ
- ✗ 1つのリポジトリに複数のアプリ
2. 依存関係(Dependencies)
依存関係を明示的に宣言し、分離する。
// package.json - 明示的な依存宣言
{
"dependencies": {
"express": "^4.18.0",
"pg": "^8.10.0"
}
}
# システムにグローバルインストールされたパッケージに依存しない
✗ グローバルの imagemagick に依存
✓ Dockerfile で明示的にインストール
3. 設定(Config)
設定を環境変数に格納する。
// ✗ 悪い例: コードに設定をハードコード
const dbHost = 'localhost';
// ✓ 良い例: 環境変数から取得
const dbHost = process.env.DATABASE_HOST;
# 環境変数で設定
DATABASE_HOST=db.example.com
DATABASE_USER=admin
API_KEY=secret123
4. バックエンドサービス(Backing Services)
バックエンドサービス(DB、キャッシュ、キュー等)をアタッチされたリソースとして扱う。
flowchart LR
App["アプリケーション"] --> DB["PostgreSQL<br/>(ローカル or Amazon RDS)"]
App --> Cache["Redis<br/>(ローカル or ElastiCache)"]
App --> Storage["S3<br/>(外部ストレージ)"]
接続先を環境変数で切り替えるだけで移行可能
5. ビルド、リリース、実行(Build, Release, Run)
ビルド、リリース、実行の3つのステージを厳密に分離する。
flowchart LR
Code["コード"] --> Build["ビルド"]
Build --> Artifact["実行可能<br/>アーティファクト"]
Config["設定"] --> Release["リリース<br/>バージョン"]
Artifact --> Release
Release --> Run["実行中<br/>プロセス"]
✗ 本番で直接コードを編集 ✓ 新しいリリースをデプロイ
6. プロセス(Processes)
アプリを1つまたは複数のステートレスなプロセスとして実行する。
// ✗ 悪い例: メモリにセッションを保存
const sessions = {};
app.use((req, res, next) => {
sessions[req.sessionId] = req.user;
});
// ✓ 良い例: 外部ストアを使用
const RedisStore = require('connect-redis');
app.use(session({
store: new RedisStore({ client: redisClient })
}));
7. ポートバインディング(Port Binding)
ポートバインディングによってサービスを公開する。
// アプリ自体がWebサーバーとなる
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
8. 並行性(Concurrency)
プロセスモデルによってスケールアウトする。
Web [■] [■] [■] [■] ← 4プロセス
Worker [■] [■] ← 2プロセス
Clock [■] ← 1プロセス
→ 負荷に応じてプロセス数を調整
9. 廃棄容易性(Disposability)
高速な起動とグレースフルシャットダウンで堅牢性を最大化する。
// グレースフルシャットダウン
process.on('SIGTERM', async () => {
console.log('SIGTERM received, shutting down gracefully');
// 新しいリクエストの受付を停止
server.close();
// 処理中のリクエストを完了させる
await finishPendingRequests();
// DB接続をクローズ
await db.close();
process.exit(0);
});
10. 開発/本番一致(Dev/Prod Parity)
開発、ステージング、本番環境をできるだけ一致させる。
| ギャップ | 従来型 | Twelve-Factor |
|---|---|---|
| 時間 | 数週間〜数ヶ月 | 数時間〜数日 |
| 担当者 | 開発者と運用者が別 | 同じ人がデプロイ |
| ツール | 開発はSQLite、本番はPostgreSQL | 同じサービスを使用 |
# docker-compose.yml - 開発でも本番と同じDBを使用
services:
db:
image: postgres:15
redis:
image: redis:7
11. ログ(Logs)
ログをイベントストリームとして扱う。
// ✗ 悪い例: ファイルに書き込み
fs.appendFileSync('/var/log/app.log', message);
// ✓ 良い例: 標準出力に出力
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
level: 'info',
message: 'User logged in',
userId: '123'
}));
# ログは外部で収集・集約
docker logs app | fluentd
12. 管理プロセス(Admin Processes)
管理タスクを1回限りのプロセスとして実行する。
# マイグレーション
npx prisma migrate deploy
# データ修正スクリプト
node scripts/fix-data.js
# REPLでのデバッグ
node --inspect app.js
実践のポイント
Dockerとの相性
# Twelve-Factor準拠のDockerfile
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production # 2. 依存関係
COPY . .
# 7. ポートバインディング
EXPOSE 3000
# 6. ステートレスプロセス
CMD ["node", "server.js"]
Kubernetesとの組み合わせ
# ConfigMap で設定を管理 (3. 設定)
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
NODE_ENV: production
# Deployment でスケール (8. 並行性)
apiVersion: apps/v1
kind: Deployment
spec:
replicas: 3
まとめ
Twelve-Factor Appの原則は、クラウドネイティブなアプリケーション開発の基礎となる考え方です。これらの原則に従うことで、スケーラブルで保守しやすく、ポータブルなアプリケーションを構築できます。すべてを一度に適用する必要はなく、プロジェクトの状況に応じて段階的に取り入れていくことをお勧めします。
← 一覧に戻る