はじめに
「Kubernetes Patterns, 2nd Edition」(O'Reilly)は、Kubernetesを使ったクラウドネイティブアプリケーション設計における、繰り返し現れる問題とその解決策を「パターン」という形で体系化した一冊です。
コンテナのライフサイクル管理からセキュリティ設計、オペレータパターンまで、6つのパートに分けて30以上のパターンが解説されています。本書の最大の価値は、Kubernetesの各機能を「なぜ必要か」という問題意識から説明している点にあります。チームでの設計議論に使える共通言語を得られる一冊です。
本書の構成
本書は6部構成になっています。
| パート | テーマ |
|---|---|
| Part I | 基礎パターン |
| Part II | 行動パターン |
| Part III | 構造パターン |
| Part IV | 構成パターン |
| Part V | セキュリティパターン |
| Part VI | 高度なパターン |
Part I:基礎パターン
第1章 はじめに——クラウドネイティブへの道
本書はまず、優れたクラウドネイティブアプリケーションを作るために必要なスキル層を整理します。
- コードレベル:クリーンコード、継続的リファクタリング
- ドメイン駆動設計:境界付きコンテキスト、集約
- ヘキサゴナルアーキテクチャ:コアビジネスロジックとインフラの分離
- マイクロサービス / Twelve-Factor App:変化に強い分散アプリケーションの原則
- コンテナ:パッケージングと実行の標準
本書はこれらのうち「コンテナオーケストレーションのパターン」のみに絞って論じており、前提として内部設計の整備が必要であると明言しています。
分散プリミティブとJVMの対比
本書が面白いのは、KubernetesのプリミティブをJVMの世界と対比させている点です。
| コンセプト | JVM(ローカル) | Kubernetes(分散) |
|---|---|---|
| 動作のカプセル化 | クラス | コンテナイメージ |
| インスタンス | オブジェクト | コンテナ |
| 再利用単位 | .jar | コンテナイメージ |
| 構成 | クラスの組み合わせ | サイドカーパターン |
| デプロイ単位 | .jar / .war | Pod |
| 定期タスク | ScheduledExecutorService | CronJob |
| バックグラウンドタスク | デーモンスレッド | DaemonSet |
| 設定管理 | System.getenv() | ConfigMap / Secret |
この対比を見るだけでも、Kubernetesが単なる「デプロイツール」ではなく、分散アプリケーションのランタイムプラットフォームであることがよくわかります。
Podとサービスの役割
- Pod:コンテナグループのスケジューリング・デプロイメント・ランタイム分離の単位。ビルド時はコンテナイメージがマイクロサービスを表しますが、実行時はPodがその単位になります。
- Service:Podの短命さ(スケールアップ・ダウン・再スケジュール)を吸収し、サービス名をIPとポートに永続的にバインドします。
- ラベル:Podを論理的にグループ化し、ReplicaSetのセレクターやアフィニティルールの基盤となります。
- Namespace:クラスターを論理的なリソースプールに分割し、ResourceQuotaと組み合わせてリソース消費を制限できます。
第2章 予測可能な需要
コンテナのリソースプロファイル(requestsとlimits)を適切に宣言することで、スケジューラが最適なノードを選べるようになります。QoSレベル(Guaranteed / Burstable / BestEffort)の考え方も解説されており、ノードのメモリ不足(OOMKill)への対処にも繋がります。
第3章 宣言的なデプロイメント
RollingUpdate・Recreate・Blue-Greenなどのデプロイ戦略を、Kubernetesの宣言的APIでどう表現するかを扱います。maxSurge・maxUnavailableの組み合わせによる細かな制御が可能です。
Part I:基礎パターン(続き)
第4章 ヘルスプローブ
アプリケーションの健全性をKubernetesに伝えるためのAPIです。
プロセスが生きていても、アプリケーションが機能していないケースは多くあります(デッドロック、OutOfMemoryErrorなど)。ヘルスプローブはこれを検出するための仕組みです。
4種類のプローブ
spec:
containers:
- name: app
startupProbe: # 起動完了を通知(起動に時間がかかるアプリ向け)
exec:
command: ["stat", "/var/run/ready"]
failureThreshold: 15
periodSeconds: 60
livenessProbe: # 生死確認。失敗するとコンテナを再起動
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
readinessProbe: # トラフィック受付可否を通知。失敗するとEndpointから除外
exec:
command: ["stat", "/var/run/random-generator-ready"]
| プローブ | 役割 | 失敗時のアクション |
|---|---|---|
| Startup | 起動完了の通知 | 再起動 |
| Liveness | 生死確認 | 再起動 |
| Readiness | トラフィック受付可否 | Endpointから除外 |
Readiness Gateの活用
外部ロードバランサーの準備完了もPodの準備完了条件に組み込めるreadinessGatesは、高度な制御が必要な場合に有効です。
第5章 管理されたライフサイクル
アプリケーションがKubernetesからのライフサイクルイベントにどう応答すべきかを定義します。
シグナルとフック
| イベント | 説明 |
|---|---|
SIGTERM |
シャットダウンの通知。この時点で速やかに終了処理を開始する |
SIGKILL |
SIGTERMから(デフォルト)30秒後に強制終了 |
postStart |
コンテナ起動直後に非同期実行。ウォームアップや前提条件チェックに使う |
preStop |
コンテナ終了前のブロッキング呼び出し。正常シャットダウン処理に使う |
lifecycle:
postStart:
exec:
command: ["sh", "-c", "sleep 30 && echo 'ready' > /tmp/postStart_done"]
preStop:
httpGet:
path: /shutdown
port: 8080
postStartは「少なくとも1回」のセマンティクスを持ちます。重複実行を考慮した実装が必要です。
Init ContainerとLifecycle Hookの使い分け
| 観点 | Lifecycle Hook | Init Container |
|---|---|---|
| 粒度 | コンテナレベル | Podレベル |
| 起動時アクション |
postStart(非同期) |
順次・完了まで実行 |
| シャットダウン | preStop |
対応なし |
| 再利用性 | コンテナと密結合 | コンテナイメージとして再利用可 |
Part I:基礎パターン(続き)
第6章 自動配置
KubernetesスケジューラがどのようにノードにPodを割り当てるか、そしてそれをどう制御するかを解説します。
スケジューリングの制御手段(比較)
| 手段 | 用途 | 強度 |
|---|---|---|
nodeSelector |
ラベルによるシンプルなフィルタ | Hard |
| Node Affinity | 演算子を使った柔軟な条件指定 | Hard / Soft |
| Pod Affinity | 他のPodとの相対的な配置 | Hard / Soft |
| Pod Anti-Affinity | 他のPodとの分離 | Hard / Soft |
| Topology Spread Constraints | ゾーン/ノード間の均等分散 | Hard / Soft |
| Taints & Tolerations | ノード側からの制御(オプトイン) | Hard / Soft / Evict |
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: numberCores
operator: Gt
values: ["3"]
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: bar
過度なスケジューリング制約はクラスターリソースの断片化を招きます。まずリソースプロファイルとラベルを適切に設定し、スケジューラに任せるところから始めるのが推奨です。
Part II:行動パターン
Podを「どのように実行するか」を管理するコントローラーの選び方を扱います。
| パターン | 章 | 使うコントローラー |
|---|---|---|
| バッチジョブ | 第7章 | Job(完了まで1回実行) |
| 定期ジョブ | 第8章 | CronJob |
| デーモンサービス | 第9章 | DaemonSet(全ノードで1Pod) |
| シングルトンサービス | 第10章 | StatefulSet + Leader Election |
| ステートレスサービス | 第11章 | Deployment + ReplicaSet |
| ステートフルサービス | 第12章 | StatefulSet + PersistentVolume |
| サービス検出 | 第13章 | Service / Headless Service |
| 自己認識 | 第14章 | Downward API |
第14章の「自己認識」パターンでは、PodがDownward APIを通じて自身のIPアドレス、Namespace、リソース制限などのメタデータを取得できます。外部サービスレジストリへの登録や、ログへのコンテキスト付与に役立ちます。
Part III:構造パターン
第15章 初期化コンテナ
アプリケーションコンテナが起動する前に、前提条件を整えるために使います。データのダウンロード、設定ファイルの生成、依存サービスの待機など、順次・完了まで実行される保証があります。
第16章 サイドカー
メインコンテナと同じPod内でヘルパーコンテナを実行するパターンです。
Pod
├── Main Container(アプリケーション)
└── Sidecar Container(ログ収集・プロキシ・設定同期など)
責務を分離し、メインコンテナを変更せずに横断的な機能を追加できます。サービスメッシュ(Envoyなど)はこのパターンの典型例です。
第17章 アダプタ / 第18章 大使
- アダプタ:外部から見るインターフェースを標準化します(例:独自フォーマットのメトリクスをPrometheus形式に変換するサイドカー)。
- 大使:メインコンテナの代わりに外部サービスへのプロキシとして機能します(例:ローカルキャッシュ、サービスディスカバリの抽象化)。
Part IV:構成パターン
第20章 構成リソース(ConfigMap / Secret)
環境変数・ボリュームマウントを通じて、設定とコードを分離します。
第21章 不変の設定
バージョン付きConfigMapを作成し、変更時は新しいリソースとして作り直すアプローチです。ローリングアップデートと組み合わせることで、設定変更の追跡とロールバックが容易になります。
第22章 構成テンプレート
HelmやKustomizeを使って、テンプレートから環境ごとに異なるKubernetesマニフェストを生成するパターンです。
第23章 プロセスの包含
ビルドパイプラインや設定生成のロジックをコンテナ化し、Kubernetesのリソースとして定義します。
Part V:セキュリティパターン
第24章 ネットワークセグメンテーション
NetworkPolicyを用いて、Namespace間・Pod間の通信を制御します。デフォルトでは名前空間をまたいだ通信が許可されるため、明示的な制限が重要です。
第25章 セキュアな構成
Secretの適切な管理(外部シークレット管理システムとの統合、Sealed Secretsなど)と、Pod Security StandardsによるPodレベルのセキュリティ制約を扱います。
第26章 アクセス制御
RBAC(Role-Based Access Control)によるAPIアクセスの制限と、ServiceAccountを用いた最小権限の原則を解説します。
Part VI:高度なパターン
第27章 コントローラー
Kubernetesの制御ループ(Reconciliation Loop)の仕組みを理解し、カスタムコントローラーを実装する方法を扱います。「期待する状態」と「現在の状態」を継続的に比較し、差分を埋める設計思想がKubernetesの根幹です。
第28章 オペレーター
カスタムリソース(CRD)とカスタムコントローラーを組み合わせた「オペレーター」パターンです。ステートフルなアプリケーション(データベース、メッセージブローカーなど)の運用知識をコードとして表現します。
CRD(Custom Resource Definition)
↕
Custom Controller(Reconciliation Loop)
↕
Kubernetes API
第29章 弾性スケール
HPA(Horizontal Pod Autoscaler)・VPA(Vertical Pod Autoscaler)・KEDA(イベント駆動スケーリング)を組み合わせたスケーリング戦略を解説します。
第30章 イメージビルダー
KanikoやBuildahを用いた、Kubernetes内でのコンテナイメージビルドパターンです。CI/CDパイプラインとの統合に役立ちます。
本書から得られる設計の視点
「問題→解決」の思考フレーム
本書の各パターンは必ず「問題」セクションから始まります。「なぜこの機能が必要か」という問いへの答えを先に示すことで、機能の理解が深まります。Kubernetesの機能を「使い方」ではなく「なぜ使うか」から理解できる構成になっています。
コンテナ設計の原則
本書が繰り返し強調するコンテナ設計の原則をまとめると次のようになります。
良いコンテナの特性
- 単一の問題に対処する機能の単位
- 単一のチームが所有し、独自のリリースサイクルを持つ
- 自己完結型(ランタイム依存関係を定義・保持する)
- 不変(一度ビルドしたら変更しない、設定で制御する)
- リソース要件と外部依存関係を宣言する
- 明確に定義されたAPIで機能を公開する
- 一時的(スケールアップ・ダウンをいつでも安全に行える)
クラウドネイティブのスタック全体像
本書が示す「クラウドネイティブへの道」は、Kubernetesを使いこなすだけでは不十分であることを示しています。クリーンコード → DDD → ヘキサゴナルアーキテクチャ → マイクロサービス → コンテナ設計 → Kubernetesパターン、というスタック全体を意識することで、初めてクラウドネイティブの恩恵を最大限に活かせます。
まとめ
「Kubernetes Patterns, 2nd Edition」は、Kubernetesの各機能をパターンとして体系化することで、設計上の意思決定に使える共通語彙を提供してくれます。
特に印象的だったのは次の3点です。
- 問題→解決の構成:機能の「なぜ」から入ることで、適材適所の判断ができるようになります
- JVMとの対比:分散プリミティブを既知の概念から理解できる導入が秀逸です
- パターン間の繋がり:サイドカー・アダプタ・大使の違い、Init ContainerとLifecycle Hookの使い分けなど、似た機能の選択基準が明確になります
Kubernetesの「動かし方」は学べても「設計の仕方」が曖昧に感じている方に、特に読んでほしい一冊です。