🚨 災害発生:2025年8月12日 14:30
「今度のマイクロサービス基盤は完璧な設計です」
私がそう自信満々に宣言してから、わずか6時間後。全社のWebサービスが完全停止し、顧客からの苦情電話が鳴り止まなくなった。
発生した問題:
- 200以上のマイクロサービス間通信が完全遮断
- IP アドレス枯渇によりサービス起動不能
- Auto Scaling 発動時に新しいPodが作成できない事態
- 決済システムまで巻き込んだ全社システム停止
影響範囲:
- 顧客向けWebサイト: 完全停止
- 社内システム: 80%機能停止
- 決済処理: 5日間停止
- 推定売上損失: 3億円
この記事は、サブネット設計の甘さが招いた5日間の地獄とその完全復旧までの記録である。
💀 設計ミスの発端:過信したサブネット計画
問題の設計図
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
# 災害を招いた設計
VPC: microservices-vpc (10.0.0.0/16)
Subnets:
# ❌ 致命的な設計ミス
container-subnet: 10.0.10.0/24 # ←256個しかIP無い
Purpose: GKE Cluster (200サービス)
Expected_Pods: "50個くらい?"
Reality: 1,200個のPod必要
service-mesh-subnet: 10.0.3.0/28 # ←16個のIP
Purpose: Istio Control Plane
Expected: "Control Plane 3台"
Reality: Istio Proxy 全Pod分必要
database-subnet: 10.0.4.0/27 # ←32個のIP
Purpose: Database Services
Expected: "DB 10台"
Reality: 各サービス専用DB必要
|
🤦♂️ 甘かった見積もり
私の楽観的計算:
- マイクロサービス: 200個
- 1サービスあたりPod: 1〜2個
- 必要IP: 「500個もあれば十分」
現実:
- 1サービスあたりPod: 3〜15個(本番/ステージング/カナリー)
- Istio Proxy: 全Pod分必要
- Database: サービス専用DBが各3〜5インスタンス
- 必要IP総数: 3,000個超
🔥 災害の瞬間:IP枯渇の連鎖反応
14:30 - 移行作業開始
1
2
|
# 自信満々でデプロイ開始
kubectl apply -f microservices-manifests/
|
最初の50サービスは順調に起動。
「見ろ、完璧な設計だ」
15:45 - 最初の異変
1
2
3
4
|
Error: Pod "payment-service-7d4c8f9b-xrt2k" failed to schedule
Reason: IP address allocation failed in subnet container-subnet
Available IPs: 12
Required IPs: 45
|
「おかしい…計算では余裕があるはず」
16:20 - 連鎖的システム停止開始
IP枯渇により:
- 新しいPodが起動できない
- Auto Scalingが機能しない
- 既存Podの通信がIstio経由で不可能
- 決済サービスが応答不能
17:00 - 全社システム完全停止
1
2
3
|
# 絶望的な状況確認
kubectl get pods --all-namespaces | grep -v Running
# 結果: 800+ Pods が Pending 状態
|
管理者から緊急連絡:
「顧客サイトが全部死んでる。すぐ戻せ!」
🚨 緊急対応:5日間の修羅場
Day 1-2: 応急処置で時間稼ぎ
緊急IP確保作戦
1
2
3
|
# 他のサブネットからIP借用(応急処置)
gcloud compute networks subnets expand-ip-range container-subnet \
--prefix-length=22 # /24 → /22に拡張
|
結果: 一部サービス復旧するも、根本解決にならず
とりあえず古いシステムに戻す試み
1
2
3
4
|
# 旧システムに緊急ロールバック
kubectl rollout undo deployment/payment-service
kubectl rollout undo deployment/user-service
# ... 200回繰り返し
|
問題: データベースのマイグレーションが完了済みでロールバック不可能
Day 3-4: 根本設計見直し
正しいIP計算をやり直し
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# 現実的な設計に変更
Container_IP_Requirements:
Microservices: 200 services
Per_Service_Pods:
Production: 5 pods
Staging: 3 pods
Canary: 2 pods
Total: 10 pods/service
Total_Application_Pods: 200 × 10 = 2,000
Istio_Proxy: 2,000 (各Podにサイドカー)
Database_Pods: 200 services × 3 replicas = 600
Monitoring_Pods: 100
Safety_Buffer: 50%
Total_Required: (2,000 + 600 + 100) × 1.5 = 4,050 IPs
|
新しいサブネット構成設計
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
# 修正後の設計
VPC: microservices-vpc-v2 (10.0.0.0/16)
Subnets:
# ✅ 現実的な設計
container-subnet: 10.0.0.0/20 # 4,096 IPs
Purpose: GKE Main Cluster
Available: 4,096 - 16 = 4,080 IPs
container-staging-subnet: 10.0.16.0/22 # 1,024 IPs
Purpose: Staging Environment
service-mesh-subnet: 10.0.20.0/22 # 1,024 IPs
Purpose: Istio Control Plane + Proxies
database-subnet: 10.0.24.0/21 # 2,048 IPs
Purpose: Database Services
monitoring-subnet: 10.0.32.0/24 # 256 IPs
Purpose: Prometheus / Grafana
backup-subnet: 10.0.33.0/24 # 256 IPs
Purpose: Future Expansion
|
Day 5: 完全再構築
新VPC環境の構築
1
2
3
4
5
6
7
8
9
|
# 新しいVPCを並行して構築
gcloud compute networks create microservices-vpc-v2 \
--subnet-mode regional
# 適切なサイズのサブネット作成
gcloud compute networks subnets create container-subnet-v2 \
--network microservices-vpc-v2 \
--range 10.0.0.0/20 \
--region asia-northeast1
|
データベース移行(最も困難)
1
2
3
4
5
6
7
8
9
|
# データ無停止移行のためのレプリケーション設定
gcloud sql instances patch main-db \
--enable-bin-log \
--backup-start-time 01:00
# 新環境への段階的レプリケーション
gcloud sql instances create main-db-v2 \
--master-instance-name main-db \
--replica-type FAILOVER
|
💡 根本原因分析:なぜこんな設計をしたのか
1. 過度な楽観的見積もり
1
2
3
4
5
6
7
8
9
|
Wrong_Assumptions:
"1サービス = 1 Pod":
Reality: Production/Staging/Canary で 10 Pod以上
"IPは余るほどある":
Reality: Kubernetesクラスターは大量IP消費
"Istioは軽い":
Reality: 全Pod分のProxy IPが必要
|
2. 理論と現実のギャップ
1
2
3
4
5
|
Kubernetes_Reality:
Pod_Density: "理論値の50%程度"
IP_Fragmentation: "連続IP確保が困難"
Service_Mesh_Overhead: "想定の5倍のリソース"
Auto_Scaling_Burst: "瞬間的に10倍のPod起動"
|
3. テスト環境での検証不足
1
2
3
4
5
6
7
8
9
|
Test_Environment_Problems:
Scale: "10サービスのみでテスト"
Load: "実負荷の1/100"
Network: "シンプルな構成でテスト"
Real_Environment:
Scale: "200サービス同時稼働"
Load: "予想の10倍のトラフィック"
Network: "複雑なサービス間依存"
|
🛠️ 完全解決策:enterprise レベルのサブネット設計
階層化サブネット戦略
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# 本番レベルの設計原則
Subnet_Design_Strategy:
Principle_1_Isolation:
- Environment別完全分離(prod/staging/dev)
- Service Tier別分離(web/app/data)
- Security Zone別分離(dmz/internal/restricted)
Principle_2_Scalability:
- 現在必要量の5倍を確保
- Auto Scaling burst対応
- 将来拡張考慮(10年先まで)
Principle_3_Security:
- Zero Trust Network設計
- Service Mesh segmentation
- Network Policy enforcement
|
実用的なIP計算フォーミュラ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
# 実用IP計算式(災害を避ける)
IP_Calculation_Formula:
Base_Requirements:
Services: N
Pods_Per_Service: P
Environments: E (prod/staging/dev/canary)
Service_Mesh_Factor: 2.0 # Istio proxy分
Database_Factor: 1.5 # DB replica分
Monitoring_Factor: 1.2 # Monitoring stack
Auto_Scaling_Factor: 3.0 # Burst scaling
Safety_Buffer: 2.0 # 余裕を持った設計
Total_IPs = N × P × E × 2.0 × 1.5 × 1.2 × 3.0 × 2.0
Example:
200 services × 3 pods × 4 envs × 2.0 × 1.5 × 1.2 × 3.0 × 2.0
= 200 × 3 × 4 × 21.6 = 51,840 IPs required
Recommended_CIDR: /14 (65,536 IPs) 以上
|
最終的な設計図
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
# 災害を経て完成した設計
VPC: microservices-enterprise-vpc (10.0.0.0/14) # 262,144 IPs
Production_Environment:
prod-ingress-subnet: 10.0.0.0/22 # 1,024 IPs
prod-app-subnet: 10.0.4.0/20 # 16,384 IPs
prod-data-subnet: 10.0.20.0/21 # 2,048 IPs
prod-mesh-subnet: 10.0.28.0/20 # 16,384 IPs
Staging_Environment:
staging-app-subnet: 10.1.0.0/21 # 2,048 IPs
staging-data-subnet: 10.1.8.0/22 # 1,024 IPs
staging-mesh-subnet: 10.1.12.0/21 # 2,048 IPs
Development_Environment:
dev-app-subnet: 10.2.0.0/22 # 1,024 IPs
dev-data-subnet: 10.2.4.0/23 # 512 IPs
dev-mesh-subnet: 10.2.6.0/22 # 1,024 IPs
Special_Purpose:
ci-cd-subnet: 10.3.0.0/22 # 1,024 IPs
monitoring-subnet: 10.3.4.0/22 # 1,024 IPs
backup-subnet: 10.3.8.0/22 # 1,024 IPs
future-expansion: 10.4.0.0/18 # 16,384 IPs
|
🚀 復旧作業:段階的移行戦略
Phase 1: 緊急復旧(完了:Day 5)
1
2
3
4
5
6
7
|
# クリティカルサービス優先復旧
kubectl create namespace critical-services
kubectl apply -f critical-manifests/ -n critical-services
# 決済システム最優先
kubectl scale deployment payment-service --replicas=10
kubectl scale deployment user-auth-service --replicas=8
|
Phase 2: 段階的移行(完了:Day 10)
1
2
3
4
5
6
7
8
9
10
11
|
Migration_Strategy:
Week_1: Critical services (payment, auth, user)
Week_2: Customer-facing services (web, api, mobile)
Week_3: Internal services (admin, reporting, batch)
Week_4: Development/staging environments
Risk_Mitigation:
- Blue-Green deployment per service
- Real-time health monitoring
- Immediate rollback capability
- Database replica synchronization
|
Phase 3: 監視・自動化強化(完了:Day 14)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
# IP使用率監視の自動化
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
spec:
groups:
- name: subnet-monitoring
rules:
- alert: SubnetIPUtilizationHigh
expr: subnet_ip_utilization > 0.8
labels:
severity: warning
annotations:
summary: "Subnet IP utilization above 80%"
- alert: SubnetIPUtilizationCritical
expr: subnet_ip_utilization > 0.95
labels:
severity: critical
annotations:
summary: "URGENT: Subnet running out of IPs"
|
📊 災害から学んだ教訓
❌ やってはいけない設計パターン
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
Anti_Patterns:
Underestimating_Kubernetes:
- "1 Service = 1 Pod" の思い込み
- サイドカーProxy のIP消費を無視
- Auto Scaling burst を考慮しない
Insufficient_Testing:
- 小規模環境でのテスト のみ
- 負荷テスト不足
- ネットワーク分割テスト不足
Poor_Capacity_Planning:
- 楽観的見積もり
- 余裕を持たない設計
- 将来拡張を考慮しない
|
✅ 推奨される設計パターン
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
Best_Practices:
Realistic_Capacity_Planning:
- 現実的なPod数見積もり(5-10倍余裕)
- Service Mesh overhead考慮(2-3倍)
- Auto Scaling burst考慮(3-5倍)
- 将来拡張考慮(10年先まで)
Comprehensive_Testing:
- Production同等規模でのテスト
- 負荷テスト + ネットワーク分割テスト
- 段階的デプロイによるリスク軽減
Proactive_Monitoring:
- IP使用率リアルタイム監視
- 閾値アラート設定(80%で警告、95%で緊急)
- 自動スケールアウトの準備
|
🎯 ビジネス教訓
1
2
3
4
5
6
7
8
9
10
|
Business_Lessons:
Technical_Debt_Cost:
- 不適切設計の代償: 3億円売上損失
- 復旧コスト: エンジニア延べ200時間
- 信頼回復コスト: 測定不可能
Investment_Priority:
- インフラ設計に十分な時間とリソースを投資
- テスト環境の Production 同等化
- 監視・運用の自動化への先行投資
|
🔍 技術的深堀り:サブネット設計の科学
Kubernetes ネットワーキングの現実
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
Kubernetes_Networking_Reality:
Pod_IP_Consumption:
- 1 Pod = 1 IP (基本)
- Istio Proxy = Pod分の追加IP
- Init Containers = 一時的なIP消費
- Failed Pods = IP の断片化要因
Service_Discovery_Overhead:
- ClusterIP Service = 仮想IP消費
- NodePort Service = Node IP消費
- LoadBalancer Service = 外部IP消費
- Ingress Controller = 追加IP消費
Auto_Scaling_Burst_Pattern:
- CPU spike時: 瞬間的に5-10倍Pod作成
- Memory pressure時: Pod migration発生
- Network policy変更: Pod restart cascade
|
Service Mesh の隠れコスト
1
2
3
4
5
6
7
8
9
10
11
12
|
Istio_Hidden_Costs:
Control_Plane:
- istiod: 3-5 replicas × N zones = 15 IPs
- Ingress Gateway: 3-5 replicas = 15 IPs
- Egress Gateway: 3-5 replicas = 15 IPs
Data_Plane:
- Envoy Proxy: 全Pod分 = Application Pod数分
- Mixer/Telemetry: Pod数 × 0.1
- Pilot Agent: Pod数 × 0.05
Total_Factor: Application Pod × 2.15
|
大規模運用での実測データ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
Production_Data_200_Services:
Expected_vs_Reality:
Estimated_Pods: 400 (2 per service)
Actual_Pods: 3,200 (16 per service average)
Estimated_IPs: 800
Actual_IPs: 6,400
Growth_Rate: 800% over estimate
Peak_Scaling_Events:
Black_Friday: 15,000 Pods (4.7x normal)
Database_Failover: 8,000 Pods (2.5x normal)
Network_Partition: 12,000 Pods (3.8x normal)
|
🎯 完全復旧:システム安定化まで
最終的な安定稼働状態
1
2
3
4
5
6
7
8
9
10
11
|
# 復旧完了後の状況確認
kubectl get pods --all-namespaces | wc -l
# Result: 3,247 pods running
kubectl get nodes -o wide
# Result: 15 nodes, all Ready
# IP使用率確認
gcloud compute networks subnets describe container-subnet-v2 \
--format="value(ipCidrRange, availableIpAddressCount)"
# Result: 10.0.0.0/20, 892 available (78% utilization)
|
パフォーマンステスト結果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
Performance_Test_Results:
Load_Test_Peak:
Requests_Per_Second: 50,000
Response_Time_95th: 120ms
Error_Rate: 0.02%
Pod_Count_Peak: 4,200
IP_Utilization_Peak: 84%
Stress_Test_Results:
Auto_Scale_Time: 45 seconds
New_Pod_IP_Assignment: < 5 seconds
Service_Discovery_Propagation: < 10 seconds
Disaster_Recovery_Test:
Failover_Time: 2 minutes
Data_Loss: 0 transactions
Service_Restoration: 100%
|
📈 長期運用結果
6ヶ月後の状況
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
Six_Months_Later:
System_Stability:
Uptime: 99.97%
Major_Incidents: 0
IP_Related_Issues: 0
Capacity_Utilization:
Average_Pod_Count: 2,800
Peak_Pod_Count: 4,200
IP_Utilization: 65-85%
Headroom_Available: 30%
Cost_Impact:
Infrastructure_Cost: +40% (larger subnets)
Operational_Cost: -60% (automation)
Incident_Cost: -100% (zero outages)
Business_Impact:
Customer_Satisfaction: Restored
Revenue_Impact: +15% (improved reliability)
Team_Productivity: +30% (less firefighting)
|
🏆 まとめ:災害を防ぐサブネット設計の鉄則
🎯 設計時の絶対ルール
-
現実的な容量計画
- 楽観的見積もりに5-10倍の余裕
- Service Mesh overhead(2-3倍)を必ず計算
- Auto Scaling burst(3-5倍)を考慮
-
本番同等のテスト
- スケール・負荷・障害の3点セット
- ネットワーク分割テストの実施
- 段階的デプロイによるリスク検証
-
プロアクティブ監視
- IP使用率の常時監視
- 閾値アラート(80%警告、95%緊急)
- 自動拡張の準備
💡 運用時の継続改善
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
Continuous_Improvement:
Monthly_Review:
- IP使用率トレンド分析
- 成長予測の見直し
- キャパシティプランの更新
Quarterly_Test:
- 災害復旧訓練
- スケールテスト
- セキュリティ監査
Annual_Architecture_Review:
- 技術選択の再評価
- サブネット構成の最適化
- コスト効率の改善
|
🚨 絶対に避けるべき間違い
- ❌ 「うちは小さいから大丈夫」という過信
- ❌ 開発環境と本番環境の規模違いを無視
- ❌ Kubernetesの「隠れリソース消費」を軽視
- ❌ 成長を見込まない固定的な設計
- ❌ 監視なしでの本番投入
この災害から3年。今も私たちのシステムは安定稼働している。あの5日間の地獄は、確実にチームを成長させた。二度と同じ過ちを繰り返さないために、この記録を残す。
読者の皆さん、同じ災害を起こさないために。サブネット設計は軽く考えてはいけない。現実を見据えた、余裕のある設計を。
📅 災害発生: 2025年08月12日
📅 完全復旧: 2025年08月17日
📅 記録作成: 2025年09月14日
教訓: インフラ設計に「だいたい大丈夫」は存在しない