Kubernetes: CRDを作るなら「.status.conditions」を活用しないともったいない！

Kubernetesをしばらく使っていると、`.status.conditions`というフィールドをよく目にすることはありませんか？PodやNode、その他多くのリソースでこのフィールドを見かけますが、その詳細な仕組みや設計意図を理解している方は意外と少ないのではないでしょうか。

`.status.conditions`はリソースの状態を標準的な方法で表現できるので、様々なツールが対応していたり、運用者がまず確認しに行くところだったりと、さまざまなメリットがあるフィールドです。

本稿では、Kubernetesリソースの状態管理の標準的な仕組みである`.status.conditions`について、その役割から実装方法、活用方法まで詳しく解説していきます。

## 1. Conditionsとは？ 〜基本的な役割と意義〜

Kubernetesリソースの`.status.conditions`は、リソースの現在の状態を表現するための標準化されたリストです。各要素（Condition）はリソースの特定の側面に関する観察結果を示し、主に`type`と`status`を中心に状態を表現します。

例えば、Podの場合を見てみましょう。Podには`Ready`というConditionがあり、これはPod内の全コンテナが実行中かつトラフィックを受け入れ可能な場合にのみ`True`になります。同様に、Nodeでは`Ready`条件がノードの健全性を示し、`DiskPressure`等の条件がリソース圧迫の有無を示します。

この仕組みの優れている点は、以下の3つです：

1. 標準化された形式で状態を表現できる
2. 複数の状態を並行して持てる
3. 「未知(Unknown)」の状態も表現できる

特に2点目は重要で、例えば「正常稼働中」かつ「アップグレード進行中」といった複数の状態を同時に表現できます。これは単一のステータス値による状態管理より柔軟な仕組みと言えます。

## 2. Conditionsの標準的な仕様と実装方法

それでは、`.status.conditions`の実装方法について見ていきましょう。各Conditionは以下のような共通のスキーマを持ちます：

```yaml
conditions:
  - type: Ready
    status: "True"
    lastTransitionTime: "2025-02-20T10:00:00Z"
    reason: KubeletReady
    message: "kubelet is posting ready status"
```

各フィールドの役割を詳しく見ていきましょう：

### type（必須）
Conditionの種類を示す文字列です。先頭大文字のCamelCaseで記述します。例えば：
- `"Ready"`
- `"Available"`
- `"Failed"`
など

### status（必須）
Conditionが満たされているかどうかを示す状態値です。以下の3つのいずれかを取ります：
- `"True"`: 条件が現在当てはまる
- `"False"`: 条件が当てはまらない
- `"Unknown"`: 不明もしくは評価不能

### lastTransitionTime（必須）
このConditionの`status`が最後に変化した日時をISO8601タイムスタンプで記録します。これにより、状態がいつから現在の値になっているのかを追跡できます。

### reason（オプション）
状態遷移の理由を表すコード名です。簡潔な英語のUpperCamelCaseテキストとして定義します。例えば：
- `"KubeletReady"`
- `"MinimumReplicasAvailable"`

このフィールドは機械的な処理やハンドリングを想定した情報として使われます。

### message（オプション）
状態に関する人間向けの詳細な説明メッセージです。`reason`より長文で、エラーの詳細や現在の状況を記述します。

## 3. 主要なConditionタイプとその意味

Kubernetesにおける代表的なConditionタイプについて、その意味と使用方法を詳しく見ていきましょう。

### Ready
最も基本的かつ重要な条件の一つです。リソースが必要な準備を全て終え、正常に稼働しているかを示します。

- **Podの場合**: すべてのコンテナが稼働中でサービス提供可能な状態
- **Nodeの場合**: ノードが健全でPodを受け入れ可能な状態
- **カスタムリソースの場合**: 多くのCRDも全体の健康状態を示すために`Ready`条件を実装

### Available
主にDeploymentやReplicaSetなどで使用される条件です。必要な副作用（レプリカ数など）を満たして利用可能な状態にあるかを示します。

例えばDeploymentでは、所定の数のPodが起動しユーザーから利用可能になれば`Available=True`となります。

### Progressing
特にDeploymentなどでよく使用され、ロールアウト（更新）が進行していることを示す条件です。

- **True**: 新しいReplicaSetのPod起動や古いPodの終了が順調に進行中
- **False**: 進行が停止または失敗（タイムアウト等）

## 4. 実装上のベストプラクティス

Conditionsを効果的に活用するためのベストプラクティスをいくつかご紹介します。

### マルチステートの活用
リソースの状態を一つのフェーズやステータスコードで管理するのではなく、複数の独立したConditionで表現しましょう。例えば：

```yaml
conditions:
  - type: Ready
    status: "True"
  - type: Progressing
    status: "True"
  - type: Failed
    status: "False"
```

このように、互いに異なる側面（準備完了か、処理中か、エラーか）を別々のConditionにすることで、状態が並行する場合も矛盾なく表現できます。

### True/False/Unknownの明確な定義
各Conditionについて、何をもってTrueとし、何をもってFalseまたはUnknownとするかを明確に定義して運用しましょう：

- **True**: その条件が現在成立している
- **False**: 明確に「成立していない」と判断できる
- **Unknown**: コントローラーが判断不能または未評価

### 失敗時の詳細情報提供
状態が`False`になった場合は、必ず`reason`と`message`で詳細情報を提供しましょう。例えば：

```yaml
conditions:
  - type: Ready
    status: "False"
    reason: ContainerCreating
    message: "waiting to start: ContainerCreating"
```

## 5. CRD設計における考慮点

Custom Resource Definition（CRD）を設計する際は、以下の点に特に注意を払いましょう。

### 必要なConditionタイプの選定
そのリソースにとって重要な状態やイベントを整理し、それぞれを表すConditionタイプを決めます。他のリソースで既に一般的に使われているものに近い概念があれば、可能な限り名称や意味を揃えると利用者に優しい設計になります。

### Ready系Conditionの用意
他に細かい条件を用意していても、最終的な可用性を示す`Ready`（または類似の名称）の有無は多くのユーザーが真っ先に確認するものです。実際、Kubernetes内で最も一般的に使われているConditionタイプは`Ready`であり、これを導入することで多くの既存ツールがそのまま活用できるようになります。

### 世代管理の実装
CRDコントローラー実装者は、リソースをリコンシリエーション（調整）した際に`.status.observedGeneration`を更新し、現在の`metadata.generation`を記録することで、「このconditionsはリソースのどの世代に対する最新情報か」を示すことができます。

### 説明資料の作成

設計時の資料として、Conditionタイプと各Conditionが取りうる状態を説明する資料を作っておくとよいでしょう。以下は、説明資料の例です。

**Conditionタイプ**

| Conditionタイプ | 説明 |
|---------------|-------------|
| Ready | アプリケーション全体の準備状態 |
| DatabaseReady | データベース接続とマイグレーションの状態 |
| ApplicationReady | アプリケーションコンテナとサービスの状態 |


**DatabaseReadyの取りうる状態**

| Status | Reason | 説明 | 運用者のアクション |
|--------|---------|-------------|-----------------|
| True | DatabaseConnected | データベースに接続され、マイグレーションが完了している | 対応不要 |
| False | ConnectionFailed | データベースへの接続が確立できない | データベースの認証情報とネットワーク接続を確認 |
| False | MigrationFailed | データベースマイグレーションが失敗した | マイグレーションログとデータベースの状態を確認 |
| False | CredentialsMissing | データベースの認証情報が正しく設定されていない | Secretの設定を確認 |
| Unknown | ConnectionTimeout | データベース接続確認がタイムアウトした | データベースの可用性とネットワーク状態を確認 |

**ApplicationReadyの状態遷移**

```mermaid
stateDiagram-v2
    direction LR
    [*] --> True: ContainersReady
    True --> False: ContainerCrashLoopBackOff
    True --> False: ImagePullBackOff
    False --> Unknown: ProbeFailure
    Unknown --> True: ContainersReady
    False --> True: ContainersReady
```

## 6. 監視と運用における活用

Conditionsは監視ツールで扱いやすい形式のため、積極的な活用をお勧めします。例えば、kube-state-metricsは各オブジェクトのConditionを自動でPrometheusメトリクスとして公開します：

```promql
kube_pod_status_ready{condition="true"|"false"}
```

このように、`condition="false"`のものをカウントすれば未ReadyのPod数を監視できます。

また、Conditionsはステートフルな障害検知に向いており、イベント（Events）と組み合わせて監視することで、クラスタ内リソースの状況を漏れなく把握できます。特にカスタムリソースでは、独自の監視要件に合わせてConditionを定義し、それをメトリクスとして活用することで効果的な運用が可能です。

## まとめ

`.status.conditions`は、Kubernetesにおける状態管理の中心的な仕組みとして確立されています。単なる状態フラグではなく、リソースの多面的な状態を表現し、また人間と機械の両方に適切な情報を提供できる柔軟な仕組みです。

特にCRDを設計・実装する際には、この仕組みを積極的に活用することで、既存のKubernetesエコシステムとの親和性が高く、運用性に優れたリソース定義を実現できます。ただし、過剰な設計は避け、必要十分な数のConditionを適切に管理することが重要です。

本稿が、皆さんのKubernetesリソース設計・実装の参考になれば幸いです。最後までお読みいただき、ありがとうございました。

https://qiita.com/suin/items/0b29e88c949ed8dc4c46