Kubernetes運用前に勉強していること基礎編03-02

# Kubernetes運用前に勉強していること基礎編03-02

> **注意**  
> 本記事の内容は個人的な勉強・備忘録を目的としており、勤務先や関係者とは一切関係ありません。

---

## はじめに

Kubernetesの本番環境での運用を始めるにあたり、個人で勉強している内容を整理した記事です。構築や運用に必要な知識、注意点、実践して学んだことを随時更新していきます。基礎編の想定読者はコンテナの知識があり、Kubernetesでコンテナ運用したいがどうすればいいかを迷っている人です。今回は前回の引き続きで、Kubernetesのリソースカテゴリを学ぶことを目的としています。

## 勉強中の主な内容

- 基礎編
  - クラウドネイティブとは
  - Kubernetesのアーキテクチャ概要
  - <font color="Red">Kubernetesのリソース（今回の話）</font>

# ReplicaSet

ReplicaSet（RS）は、指定した数のPod（レプリカ）が常に稼働するよう保証するためのコントローラリソースである。ReplicaSetはPodのテンプレートとラベルセレクタを持ち、セルフヒーリング機能によって、Podがノード障害や終了で減少した場合に自動で再作成し、所定のレプリカ数を維持する。

**特徴**

- **冗長性** : Podを複数動かすと、障害を許容できる
- **スケール** : Podを複数動かすと、多くのリクエストを受け付けられる
- **シャーディング** : 異なるコンテナのレプリカを動かすと、異なる種類の処理を同時に受け付けられる

例えば、ReplicaSetのレプリカ数を3と設定すると、任意の時点で必ず3つのPodが稼働することを保証している。これは裏でPodの監視と再作成を行うコントロールループによって実現されており、ユーザは個々のPodではなくReplicaSetに対して desired replicas 数を宣言するだけでよいというメリットがある。 
ReplicaSetの.specにはreplicas（維持したいPod数）とselector（管理対象とするPodのラベル条件）、そしてPodのテンプレート（template）を指定する。

### 設計思想

ReplicaSetはKubernetesの宣言的オブザーバ制御の基本形である。ユーザが希望するPod数を宣言し、コントローラが実際のPod数とのズレを検知して調整するという制御ループにより、クラスターの状態を目標状態に維持する。この仕組みにより、オペレータは障害対応やスケーリングを個別に行わずとも、システムが自律的にPodを管理する。


# Deployment 

Deploymentは、アプリケーションのデプロイとローリングアップデート（段階的更新）を管理するための最も重要なリソースの一つである。DeploymentによりPodとReplicaSetの宣言的な更新が可能となり、アプリケーションの複数バージョン管理や容易なロールバックを実現する。
ユーザはDeploymentで desired state（望ましい状態）としてアプリケーションのレプリカ数やコンテナイメージなどを宣言し、Deploymentコントローラがその状態になるよう内部でReplicaSetを作成・更新することで調整する。 具体的な手順は下記のとおりである。

1. Deploymentを作成するとまず所定のPodテンプレート・レプリカ数に従ったReplicaSetが1つ生成される
1. ReplicaSetがPodを起動する
1. 新しいリビジョン（例：コンテナイメージの更新）を適用する
1. Deploymentは新たなReplicaSetを生成してローリングアップデートを開始する
1. 少しずつ新バージョンのPodを起動し、安定稼働を確認しながら旧バージョンのPodを削除する

**特徴**
- RollingUpdate戦略（デフォルト）が取られるため、サービスを継続しつつ無停止でアップデートできる
- 万一新バージョンに問題が発生した場合でも、Deploymentは以前のReplicaSetを残しているためロールバックが容易である
- Deploymentではspec.replicasを動的に変更することでスケーリング（Pod数の増減）も簡単にできる

PodやReplicaSetは変更されないコンテナイメージを扱うために作られたものであるが、Deploymentは新しいバージョンのリリースを管理する仕組みである。このため、Deploymentはアプリケーションのライフサイクル管理全般（デプロイ、更新、スケール、ロールバック）を担う高レベルリソースである。

### 設計思想

Deploymentは“Kubernetesでアプリケーション運用する上での標準形”として設計されている。状態を一意に持たない複数のPodを扱う場合に、適切なローリングアップデートや自己修復、意図したスケーリングを自動化することで、人手によるミスを減らし可用性を最大化する。Deploymentコントローラは常にアプリケーションの現在の状態を監視し、ユーザが定義したdesired stateに近づけるよう差分を調整できる。
この制御ループにより、例えばPodが意図せず停止した場合でもDeployment -> ReplicaSetによって自動的に再作成され、所定のサービスレベルが維持される。また、ReplicaSetを世代管理することで過去のリビジョンを履歴として保持でき、kubectl rollout undoコマンド等で簡単に以前のバージョンへ切り戻すこともできる。

### 運用上の課題やトラブル事例

#### ローリングトラブル

Deploymentではローリングアップデートが停止してしまうケースが代表的です。例えば新しいPodがCrashLoopで起動失敗を繰り返すと、既定では最大Unavailable数を超えて停止し、DeploymentのProgressingが進まない。このようなロールアウト失敗時はkubectl rollout statusで原因を確認し、問題を修正するかrollbackする。
EKS環境ではCluster Autoscalerを有効化しておくことで、DeploymentのPod増加要求に応じて自動でEC2ノード（Managed Node Groupなど）を増やせますが、オートスケーラーが権限不足や設定ミスで動かないとスケーリング失敗に繋がる。
運用上は、ヘルスチェックとReadinessProbeを適切に設定してローリング更新時のサービス中断を防ぐこと、PodDisruptionBudgetで許容ダウン数を指定して計画メンテナンス時に必要以上のPodが落ちないように設定する。

#### IAMとの統合

Deployment自体はIAMと直接統合されていません。ただしDeploymentから生成されるPodにはServiceAccountとIRSAの仕組みを適用できる。具体例として、AWSリソースにアクセスするアプリケーションをDeploymentでデプロイする場合、該当Pod用のServiceAccountにIAMロールを関連付けておけば、Deploymentで生成されるすべてのPodに適用さる。これによりDeployment管理のマイクロサービスごとに異なるAWS権限を付与することができる。

# DaemonSet
DaemonSetは、クラスタ内の全てまたは特定のノード上に1つずつPodを起動することを保証するWorkloadリソースである。主にノード単位で実行すべき常駐プロセス（デーモン）的なコンテナを配備するために利用される。DaemonSetを作成すると、既存の各ノードに対象Podが1つずつスケジューリングされ、以降ノードが追加されればそのノード上にも自動でPodが追加される（ノード削除時は該当Podも削除）。こうしてクラスター内のノード数に応じてPodが増減するため、「各ノードで1 Pod稼働」という状態を常に維持できる。

### 典型的な用途

ログ収集デーモン（Fluentbitなど）やメトリクス収集エージェント（Prometheus Node Exporterなど）、あるいはノードストレージ管理デーモン（Cephなど）を各ノードに実行したいPodなどがあれば、DaemonSetが適している。Kubernetesクラスターでは、ノードごとに稼働させる必要がある機能（ネットワークプロキシのkube-proxy自体もデフォルトではDaemonSetとして実装されている）や、インフラ監視エージェントなどが存在しますが、DaemonSetによりそれらを一括管理できる。また、特定条件のノードのみにデーモンを配置することも可能である。

### 設計思想

DaemonSetは「各ノードでの均一なサービス提供」という要求を満たすために設計されている。スケジューラをバイパスし、専用のDaemonSetコントローラがノードイベントにフックしてPodの配置制御を行う仕組みになっており、ノード追加・削除のたびに対応できる。これにより、ノード数を意識せずに「全ノード上で稼働するPod」という宣言的状態を維持できる。Deploymentが扱うReplicaSetでは「クラスタ全体でのPod数」を制御するのに対し、DaemonSetは「ノード単位でのPod数（通常1つ）」を制御する点で異なる。

# StatefulSet

StatefulSetは、ステートフル（状態を持つ）なアプリケーションのためのWorkloadリソースであり、Podに固定の識別子（アイデンティティ）を持たせて管理する点に特徴がある。StatefulSetが生成するPodには、それぞれ一貫した名前（インデックス付きのホスト名）と、再スケジューリング後も変わらない粘着的（sticky）なIDが付与される。例えば、StatefulSet名がwebの場合、Podはweb-0, web-1, web-2...といった具合に連番名で作成され、仮にweb-0Podが一度消えても、新しく作り直されたweb-0Podは同じ名前・IDを引き継ぐ。この性質により、分散データベースや有状態サービスのように各インスタンスを識別し継続性を保つ必要があるシナリオに適している。

# 技術的な背景

ReplicaSet、Deployment、Statefulを理解するには、3つのサービスモデルを理解しておくと、Kubernetesの概念がより明確になる。

### 1. シングルトンサービス

シングルトンサービスとは、システム内で常に1つだけ稼働するサービスである。このサービスモデルでは、冗長性がなく、障害が発生すると、サービス停止リスクがある。オブジェクト指向プログラミングのシングルトンパターンと同様に、シングルトンサービスも複数のインスタンスを作成しないように設計されている。

![シングルトンサービスパターン01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976553/69dbbec3-eb79-4adc-ba25-ebcd0dd142b7.png)

実現する方法として図のように、アプリケーション内ロック（アプリケーション自体が管理するロジックによる単一性の確保）と、アプリケーション外のロック（外部の調整メカニズムを使用した排他制御）があります。KubernetesのStatefulSetでは、これらのロック機構を活用し、状態を一貫して維持しながら複数のインスタンスを慎重に管理する仕組みを提供している。
シングルトンサービスは分散環境における合意形成（コンセンサス）にも用いられており、etcdなどのシステムでよく見られます。etcdではraftアルゴリズムを用いて分散環境下での唯一性を保証している。

### 2. ステートレスサービス

ステートレスサービスは、サービスのインスタンス間で状態情報（ステート）を保持しないサービスモデルである。マイクロサービスアーキテクチャの設計原則の考え方に基づいている。

![Kubernetes上の分散ステートレスアプリケーション01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976553/258445c2-29b7-4f76-b8eb-dffbe34853fe.png)

図のようにステートレスなサービスは、過去のリクエストの状態を保持せず、各リクエストを独立して処理する。サービスのインスタンスは全て同一かつ置き換え可能であり、インスタンス間での情報共有が不要である。これにより、動的なクラウド環境でのスケールアップ・スケールダウン、障害からの復旧が容易になります。必要な状態情報はデータベース、メッセージキュー、外部ファイルシステムなど、外部の永続的なストレージに保存される。
ロードバランサ（ネットワーク）を介してリクエストがランダムに分散されても問題なく動作するのがステートレスサービスの特徴である。

### 3. ステートフルサービス

ステートフルサービスとは、データやセッション情報などの「状態（ステート）」を自身の内部に保持し、過去の処理結果に依存して動作するサービスのことを指している。各インスタンスが固有で一意な情報を持ち、長期間継続して動作するという特性がある。
Kubernetesが登場した初期段階では、ステートレスなサービスの管理が主な用途であり、ステートフルなワークロードへのサポートは限定的でした。そのため、ステートレスサービスをKubernetesで運用しつつ、ステートフルサービスは従来型のインフラで管理することが一般的でした。

![Kubernetes上の分散ステートフルアプリケーション01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976553/ad2757b6-659e-42b4-b8d2-5f0a97e4be11.png)


図のように現在のKubernetesでは、ステートフルなサービスを管理するための仕組みとして「StatefulSet」というリソースが提供されている。これにより、ステートフルサービスの運用が劇的に容易になりました。

# 所感
クラウドネイティブな環境でKubernetesを効果的に運用するには、StatefulSetやDaemonSetといったリソースの使い方をただ知るだけではなく、その背景にあるステートフルとステートレスサービスの特性や、サービスの構成パターン（例えばシングルトンパターンなど）を深く理解することが重要だと思いました。
なぜなら、ステートフルなアプリケーションは永続的なデータ管理や一貫性のある識別性を必要とし、それに応じた運用上の注意点や戦略が不可欠となるからです。今後、prometheus operatorやpostgresssql Operator(CloudNativePG)などのKubernetesでの運用に必要なアプリケーションを理解するのに重要だと思っています。
このように、技術的な要素を単体で捉えるのではなく、クラウドネイティブの思想や原理原則に基づいた全体像を捉える視点を持つことで、より安定性が高く、スケーラブルで信頼性のあるインフラ運用を実現できると感じています。次の記事は引き続き、ワークロードの説明を行います。

# 補足

過去の記事で記載していた内容を補足として追記しています。

## Kubernetesのリソースカテゴリ

 Kubernetesのリソースカテゴリは、[『Kubernetes完全ガイド第二版』](https://www.amazon.co.jp/Kubernetes%E5%AE%8C%E5%85%A8%E3%82%AC%E3%82%A4%E3%83%89-%E7%AC%AC2%E7%89%88-Top-Gear-%E9%9D%92%E5%B1%B1/dp/4295009792)をベースとしている。

| カテゴリ                                      | 概要                                   | 
| ------------------------------------------ | ------------------------------------ | 
| **Workload APIs**<br> | アプリケーション（コンテナ）の実行を管理するためのリソース        | 
| **Service APIs**<br> | Pod内のコンテナをネットワーク経由で公開し、アクセスを提供するリソース|
| **Config APIs**<br> | コンテナで利用する設定や機密情報を管理するためのリソース  | 
| **Storage APIs**<br> | コンテナで利用する永続化データを管理するためのリソース  | 
| **Cluster APIs**<br> | クラスタ内のリソースの運用や管理、セキュリティを制御するリソース     |
| **Metadata APIs**<br>        | クラスタ内の他リソースの操作や動的なメタデータ管理を行うリソース  |

# Workload APIs（ワークロード）

WorkloadカテゴリはPodやそれを管理するコントローラを含み、コンテナ化されたワークロードのデプロイ・実行を担うオブジェクト群である。ユーザは望ましい状態を宣言し、Kubernetesのコントローラが実際の状態を調整する。下記の表では主要リソースについて説明している。

| リソース種類          | 説明とユースケース例      |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Pod**  | 最小のデプロイ単位（コンテナの集合）。単体で使うよりDeployment等で管理されることが多い  |
| **Deployment**  | ステートレスなアプリケーションの管理に使用。複数のPodレプリカを管理しローリングアップデートなどを提供する                                                     |
| **ReplicaSet**  | Deploymentから内部的に生成されるリソースで、Podの所定数維持を担う。通常は直接操作せずDeployment経由で使用する |
| **StatefulSet** | ステートフルなアプリケーションのためのリソース。各Podに安定した固有ID（ホスト名）と永続ボリュームを割り当て、順序付けたデプロイ/削除を保証する |
| **DaemonSet**   | 全て（または特定）のノード上で1つずつPodを実行するためのリソース。|
| **Job**         | 一時的なバッチ処理ジョブの実行に使用。完了すべきタスクをPodとして実行し、成功終了で完了とする  |
| **CronJob**     | 定期実行ジョブ。スケジュールに従いJobを作成する |

# 参考文献

- [Kubernetes完全ガイド](https://www.amazon.co.jp/Kubernetes%E5%AE%8C%E5%85%A8%E3%82%AC%E3%82%A4%E3%83%89-%E7%AC%AC2%E7%89%88-Top-Gear-%E9%9D%92%E5%B1%B1/dp/4295009792)
- [分散システムデザインパターン](https://www.oreilly.co.jp//books/9784873118758/)
- [Kubernetesパターン](https://www.oreilly.co.jp/books/9784814400881/)