「つくって、壊して、直して学ぶ Kubernetes入門」を読みながら勉強したKubernetesの要点をまとめてメモ。
ちなみに、上記の本はハンズオンも丁寧で、k8s完全初心者でもついていけて楽しかった。おすすめです。
1. コントローラーの階層構造
管理関係
Deployment → ReplicaSet → Pod
- Deployment: ReplicaSetの上位コントローラー、ReplicaSetを管理する
- ReplicaSet: Podのコントローラー、Podを管理する
- Pod: 実際のアプリケーションが動作するコンテナ群
Deploymentの利点
- 複数のReplicaSetを並列で作成・管理可能
- Podのローリングアップデートが可能
- 無停止でのアプリケーション更新を実現
- 新旧バージョンのPodを段階的に入れ替えることでダウンタイムなし
なぜこの階層構造が必要か
- Deploymentが複数のReplicaSetを並列管理することで、新旧バージョンのPodを段階的に入れ替えられる
- これにより無停止でのアプリケーション更新が実現できる
2. Deploymentの更新戦略
更新戦略の種類
RollingUpdate(デフォルト)
- 新しいPodと古いPodを順番に入れ替える
- 無停止更新が可能
- 段階的な入れ替えでサービス継続性を保証
- 新旧バージョンが一時的に混在する
Recreate
- 古いPodを一気に削除し、新しいPodに切り替える
- 一時的なダウンタイムが発生
- 新旧バージョンの混在を避けたい場合に使用
RollingUpdateの制御パラメータ
maxUnavailable
- 更新中に利用不可にできるPod数の上限
- 更新の速度を制御
maxSurge
- レプリカ数を一時的に超過できるPod数の上限
- リソース使用量と更新速度のバランスを調整
- 値を大きくすると更新は速いがリソースを多く消費
更新戦略の選択基準
- 通常はRollingUpdateを使用(無停止が基本)
- 新旧バージョンの混在が問題になる場合のみRecreateを検討
3. Service(ネットワーク管理)
Serviceの役割
- ネットワーク管理の抽象化レイヤー
- Podへの安定したアクセスポイントを提供
- ラベルセレクタでPodを選択し、固定のエンドポイントを提供
なぜServiceが必要か
- PodのIPアドレスは動的に変わる(再作成時など)
- Serviceが固定のエンドポイントを提供することで、クライアントは変更を意識しない
- DeploymentとServiceの分離により、アップデート中も通信継続が可能
- ローリングアップデート中でも、Serviceが適切なPodにトラフィックを振り分ける
Serviceの種類
ClusterIP
- 用途: クラスタ内部からのみアクセス可能
- 特徴: 内部サービス間通信に使用
- アクセス方法: クラスタ内部の内部IPアドレスでアクセス
- 使用例: マイクロサービス間の通信、データベースへのアクセス
NodePort
- 用途: クラスタ外部からもアクセス可能
- 特徴: Node全体で指定のポートを開放
- ポート範囲: 通常30000-32767の範囲のポートを使用
-
アクセス方法:
<NodeIP>:<NodePort>でアクセス - 使用例: 開発環境、小規模な外部公開
LoadBalancer
- 用途: 本番環境での外部公開
- 特徴: 外部のロードバランサー(AWS ELB、GCP Load Balancer、Azure Load Balancerなど)を管理
- 自動管理: クラウドプロバイダーのロードバランサーをk8sから自動的に作成・管理
- 負荷分散: 外部からのトラフィックを適切にPodに分散
- 使用例: 本番環境のWebアプリケーション、APIサーバー
Serviceタイプの使い分け
- ClusterIP: 内部通信用(デフォルト)
- NodePort: 簡易的な外部アクセス
- LoadBalancer: 本番環境での外部アクセス(推奨)
4. ConfigMapとSecret
ConfigMap
概要
- 環境変数などを別のファイルに切り出して管理
- 設定とコードの分離によるベストプラクティスを実現
- アプリケーションから設定を分離し、再ビルドなしに変更可能
特徴
- 一般的な設定情報を保存(公開されても問題ない情報)
- 環境ごとに異なる設定を管理しやすい
- 同じイメージを異なる環境で使用可能
利用方法
- 環境変数として読み込み
- Volumeとして読み込み(ファイルとしてマウント)
Volumeとの組み合わせ
- ConfigMapをVolumeマウントすることで、Pod再起動なしに設定ファイルの内容変更が可能
- ただし、アプリケーションへの反映にはPod再起動が必要
- 設定変更の柔軟性と運用の効率化を実現
Secret
概要
- パスワード、APIキー、証明書などの機密情報を管理
- アクセス権を分けて管理するために使用
- ConfigMapとは異なり、より厳格な権限管理が可能
特徴
- Base64でエンコードして記載(暗号化ではなくエンコーディング)
- RBAC(Role-Based Access Control)による細かいアクセス制御
- etcdレベルでの暗号化など、追加のセキュリティ対策も推奨
利用方法
- 環境変数として読み込み(
secretKeyRefを使用) - Volumeとして読み込み(ファイルとしてマウント)
ConfigMapとの使い分け
- ConfigMap: 一般的な設定情報(公開されても問題ない)
- Secret: 機密情報(厳格な管理が必要)
セキュリティ上の注意
- Base64は単なるエンコーディングであり、暗号化ではない
- etcdレベルでの暗号化やRBACなどの追加セキュリティ対策が重要
- SecretをGitにコミットしない(外部のシークレット管理ツールの利用を検討)
5. Volume
Volumeの役割
永続化
- Podが削除されても消えてほしくないデータを保持
- データベースのデータ、ログファイル、アップロードされたファイルなど
- Docker volumeと類似の概念
データ共有
- 同一Pod内の複数コンテナ間でのファイル共有
- 異なるPod間でのデータ共有(特定のVolumeタイプ)
Volumeの種類(例)
- emptyDir: Pod内の一時的なストレージ、Pod削除時に消える
- hostPath: Nodeのファイルシステムをマウント
- persistentVolumeClaim: 永続ボリュームへのアクセス要求
- configMap / secret: ConfigMapやSecretをファイルとしてマウント
ConfigMapとの組み合わせ
- ConfigMapをVolumeマウントで設定ファイルの動的更新
- Pod再起動なしに設定ファイル自体は更新される
- アプリケーションが設定を再読み込みすれば、Pod再起動なしに反映可能
- ただし、多くのアプリケーションは再起動が必要
6. JobとCronJob
ワークロードの種類による使い分け
- Deployment: 常時稼働するアプリケーション(Webサーバー、APIなど)
- Job: 一回限りのタスク
- CronJob: 定期的なタスク
Job
概要
- 一回限りのタスクを実行するためのリソース
- タスクが完了したら終了する(Deploymentとの大きな違い)
特徴
- 完了まで実行: 成功するまでPodを実行
- 再試行機能: 失敗した場合の自動再試行
-
並列実行: 複数のPodを並列実行可能(
parallelism設定) -
完了数の指定: 指定回数成功したら完了(
completions設定)
使用例
- バッチ処理
- データ移行
- 初期化処理
- ワンタイムのデータ処理
CronJob
概要
- 定期的にJobを実行するリソース
- Linuxのcronと同様のスケジュール機能
特徴
-
スケジュール管理: cron形式でスケジュール指定(
* * * * *) - Jobの自動生成: 指定された時間にJobを自動作成・実行
- 履歴管理: 成功・失敗したJobの履歴保持設定
使用例
- 定期バックアップ
- レポート生成
- 定期メンテナンス
- ログのローテーション
- 定期的なデータ集計
7. ヘルスチェック(Probe)
Probeの必要性
- アプリケーションの健全性を自動的に監視
- 障害の早期発見と自動復旧
- ローリングアップデート時やアプリケーション障害時の安全性向上
- ユーザーへの影響を最小化
Probeの種類
Readiness Probe
- 目的: トラフィックの制御
- 失敗時の動作: Serviceのエンドポイントから除外(トラフィック停止)
-
用途:
- 一時的な負荷でリクエストを受け付けられない時
- アプリケーションのウォームアップ中
- 依存サービスが利用できない時
- 特徴: Podは削除されず、トラフィックのみ停止
Liveness Probe
- 目的: Pod自体の健全性チェック
- 失敗時の動作: Podを再起動
-
用途:
- デッドロック状態の検出
- アプリケーションがハングした状態からの回復
- 内部エラーからの自動復旧
- 特徴: Podを強制的に再起動して問題解決を試みる
Startup Probe
- 目的: 起動時のチェック
-
特徴:
- 起動に時間がかかるアプリケーションへの猶予を提供
- Startup Probe成功後に他のProbe(LivenessとReadiness)が開始
- 起動時のタイムアウトによる誤った再起動を防ぐ
-
用途:
- レガシーアプリケーション
- 大量のデータをロードするアプリケーション
- 初期化に時間がかかるアプリケーション
Probeの実装方法
-
HTTP GET: 指定したパス(例:
/health)にHTTPリクエストを送信 - TCP Socket: 指定したポートへのTCP接続を試行
- Exec: コンテナ内でコマンドを実行し、終了コードで判定
ベストプラクティス
Readiness Probeを先に実行
- Readiness ProbeとLiveness Probeを併用する場合
- Readiness Probeが先に失敗するように設定(
initialDelaySecondsやfailureThresholdを調整) - 理由: トラフィック停止 → 再起動の流れで、ユーザーへの影響を最小化
- エラーレスポンスを返さず、単にトラフィックを停止してから再起動
その他の推奨事項
- Probeのエンドポイントは軽量に(データベースへの重い問い合わせは避ける)
-
timeoutSecondsを適切に設定(レスポンスが遅い場合の考慮) -
periodSecondsでチェック頻度を調整(頻繁すぎるとオーバーヘッド)
8. リソース管理
リソース設定の重要性
- クラスタ全体のリソースを効率的に利用
- Podのスケジューリングの最適化
- リソース枯渇時の影響を最小化
- 本番環境では必須の設定
リソース設定
Resource Request
- 意味: Podスケジューリング時の最低保証リソース
-
動作: request分のリソースがない場合、Podは立ち上がらない(
Pending状態) - 用途: スケジューラーがPodを配置するNodeを決定する基準
- 保証: 最低限このリソースは確保される
Resource Limit
- 意味: Podが使えるリソースの上限
-
動作:
- CPU: 上限に達するとスロットリング(処理速度の制限)
- Memory: 上限を超えるとOOM Killer(Out Of Memory Killer)で強制終了
- 用途: 一つのPodがリソースを占有するのを防ぐ
リソースの種類
- CPU: ミリコア単位(1000m = 1 CPU)
- Memory: バイト単位(Mi、Gi など)
- その他: GPU、ephemeral-storage など
QoS(Quality of Service)クラス
クラスの分類
Node全体でリソース枯渇時(リソース使い切り)の削除優先順位:
1. BestEffort(最低優先度)
- 条件: リソースの指定がない(requestもlimitもなし)
- 優先度: 最初に削除対象
- 用途: 優先度の低いバッチ処理、開発環境
2. Burstable(中優先度)
-
条件:
- Pod内のコンテナのうち、少なくとも一つはリソース指定あり
- または request < limit の設定
- 優先度: 中間
- 用途: 通常のアプリケーション
3. Guaranteed(最高優先度)
-
条件:
- Pod内の全コンテナにリソース指定あり
- かつ request = limit
- 優先度: 最後まで保護される
- 用途: 重要な本番アプリケーション、データベース
リソース枯渇時の挙動(Eviction)
- Nodeのリソースが枯渇すると、kubeletがPodを削除(Eviction)
- 削除順序: BestEffort → Burstable → Guaranteed
- 同じQoSクラス内では、リソース使用量が多いPodから削除
ベストプラクティス
- 本番環境: 重要なPodはGuaranteedに設定
- 開発環境: BestEffortやBurstableでリソース節約
- 適切な値設定: 実際の使用量を監視して調整
- limitはrequestの1.5〜2倍程度: バーストに対応しつつ、無制限な使用を防ぐ
9. スケジューリング制御
スケジューリング制御の目的
- Podを特定のNodeに配置
- 高可用性の実現(障害時の影響を最小化)
- リソースの最適配置
- 専用Nodeの確保(GPU、高性能CPU等)
基本的な配置制御
NodeSelector
- 特徴: シンプルなラベルマッチングでNode指定
- 仕組み: Nodeのラベルと完全一致するNodeに配置
-
使用例:
-
disktype=ssdというラベルのNodeにのみ配置 - 特定のハードウェア要件があるアプリケーション
-
- 制限: 単純な条件のみ(AND条件のみ)
Node Affinity
- 特徴: より柔軟な条件指定が可能
-
種類:
-
requiredDuringScheduling: 必須条件(該当Nodeがないとスケジュールされない) -
preferredDuringScheduling: 優先条件(該当Nodeがなければ他のNodeでもOK)
-
-
利点:
- 複雑な条件(OR、NOT等)が使用可能
- 優先度の重み付けが可能
- NodeSelectorより柔軟
Pod間の関係性による配置
Pod Affinity
- 目的: 特定のPodと同じNodeに配置
-
使用例:
- キャッシュサーバーとアプリケーションを同じNodeに配置(レイテンシ削減)
- データ処理アプリと参照するデータを同じNodeに配置
- 仕組み: ラベルセレクタで対象Podを選択
Pod Anti-Affinity
- 目的: 特定のPodと異なるNodeに配置
-
使用例:
- 高可用性: 同じアプリケーションのPodを異なるNodeに分散
- 障害対策: 1つのNodeが落ちても他のNodeで稼働継続
- レプリカを複数のAZ(Availability Zone)に分散
- 重要性: 本番環境での障害対策に必須
高度な分散制御
Pod Topology Spread Constraints
- 目的: Podをトポロジー全体に均等に分散
-
トポロジーの例:
- Node単位
- AZ(Availability Zone)単位
- リージョン単位
-
使用例:
- 各AZに均等にPodを配置
- 負荷を複数のNodeに均等分散
-
設定:
maxSkewで許容する偏りを指定
除外制御
Taint / Toleration
-
概念: 「汚れ」の比喩
- Taint(汚れ): Nodeに「このNodeは特殊」とマーク
- Toleration(許容): Pod側で「この汚れは許容できる」と宣言
-
仕組み:
- デフォルトでは、TaintのあるNodeにはPodがスケジュールされない
- TolerationがあるPodのみ、そのNodeに配置可能
-
使用例:
- 専用Node: GPUノード、高性能CPUノードなど
- メンテナンス: メンテナンス中のNodeへの新規配置を防ぐ
- システムPod: マスターNodeに特定のシステムPodのみ配置
-
Taintのエフェクト:
-
NoSchedule: 新規Podをスケジュールしない -
PreferNoSchedule: できれば避ける(優先度低) -
NoExecute: 既存Podも削除
-
優先度制御
PriorityClass
- 目的: Podの優先度を明示的に設定
-
仕組み:
- PriorityClassリソースを作成(優先度を数値で定義)
- Podのマニフェストで
priorityClassNameを指定 - 数値が高いほど優先度が高い
Preemption(プリエンプション)
-
動作:
- リソース不足時、高優先度Podのために低優先度Podが強制退去
- 低優先度Podを削除して、高優先度Podをスケジュール
-
リスク:
- 予期しないPod削除でサービスが不安定になる可能性
- 重要なサービスが突然停止する恐れ
注意点と推奨事項
- 慎重な設計が必要: むやみに高優先度を設定しない
-
階層設計: システムの重要度に応じた優先度階層を設計
- 例: システムPod > 本番アプリ > 開発環境
- PodDisruptionBudgetとの併用: 削除されるPod数に制限を設定
- 本当に必要なPodにのみ高優先度を設定: 乱用するとPreemptionが頻発
リソース管理との関係
- QoS(Quality of Service): リソース枯渇時の削除優先度
- PriorityClass: スケジューリング時の優先度
- この2つを組み合わせることで、より細かいクラスタ管理が可能
10. オートスケーリング
スケーリングの種類
- 水平スケール(Horizontal Scaling): Pod数を増減(スケールアウト/イン)
- 垂直スケール(Vertical Scaling): Podのリソース量を増減(VPA: Vertical Pod Autoscaler)
Horizontal Pod Autoscaler(HPA)
概要
- Pod数を自動的に増減させるリソース
- 負荷に応じて自動的にスケーリング
- リソースの効率的な利用とコスト最適化
自動スケーリングの仕組み
スケールアウト
- 指定条件を満たすと自動的にPod数を増加
-
メトリクスの例:
- CPU使用率(最も一般的)
- メモリ使用率
- カスタムメトリクス(リクエスト数、キュー長など)
- 動作: メトリクスがしきい値を超えるとPod追加
スケールイン
- 条件が解消された後、一定時間経過でPod数を減少
-
クールダウン期間: 急激なスケールイン防止のための待機時間
- デフォルトでスケールイン前に5分間待機
- 負荷の一時的な低下での過剰なスケールイン防止
- 動作: メトリクスがしきい値を下回り、クールダウン期間経過後にPod削除
前提条件
- Metrics Server: リソース使用状況を収集するコンポーネントが必要
-
Resource Request: メトリクスの基準として必須
- 例: CPU使用率 = 実際のCPU使用量 / CPU Request
設定例
- メトリクス: CPU使用率80%
- 最小Pod数: 2
- 最大Pod数: 10
- この場合、CPU使用率に応じて2〜10個のPodが自動調整される
実用上のポイント
- 急激な負荷変動への対応: スケールアウトは速く、スケールインは慎重に
- 無駄なリソース削減: 負荷が低い時は自動的にPod削減
- コスト最適化: 必要な時だけリソースを使用
- SLAの維持: 常に適切なリソース量を確保
他のリソースとの連携
- Deployment: HPAがDeploymentのレプリカ数を自動調整
- Service: スケーリングされたPodへ自動的にトラフィック振り分け
- Probe: 新しいPodがReadyになってからトラフィックを受け付け
ベストプラクティス
- 適切なメトリクス選択: アプリケーションの特性に合ったメトリクス
- しきい値の調整: 実際の負荷パターンを監視して調整
- 最小/最大Pod数の設定: リソース保護と可用性のバランス
- 複数メトリクスの併用: CPU、メモリ、カスタムメトリクスを組み合わせ
11. 全体のまとめ
学習の体系
「つくって、壊して、直して学ぶ Kubernetes入門」を読み進め、以下の流れで理解を深めた:
- 基本アーキテクチャ: Deployment → ReplicaSet → Podの階層構造
- ネットワーク: Serviceによる安定したアクセス
- 設定管理: ConfigMapとSecretによる設定の外部化
- データ永続化: Volumeによるデータ管理
- タスク実行: JobとCronJobによる多様なワークロード
- 可用性: Probeによるヘルスチェックと自動復旧
- リソース最適化: QoSとリソース管理
- 配置戦略: スケジューリング制御による柔軟な運用
- 自動化: HPAによる自動スケーリング
重要な設計原則
疎結合
- DeploymentとServiceの分離
- 設定(ConfigMap/Secret)とコード(コンテナイメージ)の分離
- 各コンポーネントが独立して変更・管理可能
宣言的設定
- 「あるべき状態」を宣言(マニフェストファイル)
- k8sが自動的にその状態を維持
- 自己修復機能による高い可用性
自動化
- ローリングアップデートによる無停止デプロイ
- Probeによる自動ヘルスチェックと復旧
- HPAによる自動スケーリング
高可用性
- レプリカによる冗長化
- Anti-Affinityによる分散配置
- Probeによる障害検知と自動復旧
本番環境への適用時の考慮事項
セキュリティ
- Secretの適切な管理
- RBACによるアクセス制御
- ネットワークポリシーによる通信制限
可観測性
- ログ収集(Fluentd、Fluent Bitなど)
- メトリクス監視(Prometheus、Grafana)
- 分散トレーシング(Jaegerなど)
運用
- リソース使用量の継続的な監視
- 適切なリソース設定の調整
- スケーリング戦略の最適化
- バックアップとディザスタリカバリ