# 機能設計書 129-DownwardAPIボリューム

## 概要

本ドキュメントは、DownwardAPIボリュームプラグインの設計を記述する。DownwardAPIボリュームは、PodおよびコンテナのメタデータやリソースフィールドをファイルとしてPod内にマウントする機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：Pod自身のメタデータ（名前、名前空間、ラベル、アノテーション等）やリソース情報（CPU/メモリのlimits/requests）をコンテナ内からファイルとして読み取れるようにする。アプリケーションが自身のPod情報を参照する際に使用される。

**機能の利用シーン**：Pod SpecでDownwardAPIボリュームを定義し、fieldRefまたはresourceFieldRefで取得するフィールドを指定する。kubeletがPod情報からデータを抽出してファイルとして配置する。

**主要な処理内容**：
1. fieldRef: Podフィールドパスからの値抽出（ExtractFieldPathAsString）
2. resourceFieldRef: コンテナリソースフィールドからの値抽出（ExtractResourceValueByContainerNameAndNodeAllocatable）
3. EmptyDir（Memory medium/tmpfs）ラッパーセットアップ
4. AtomicWriterによるアトミック書き込み
5. FSGroup権限適用

**関連システム・外部連携**：kubeletのPod情報、ノードアロケータブルリソース、EmptyDirプラグイン、AtomicWriter。

**権限による制御**：ファイルモードはdefaultModeまたはitems[].modeで個別指定可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | DownwardAPIはCLI画面を持たないkubelet内部処理 |

## 機能種別

ボリュームプラグイン / メタデータ投影

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| items | []DownwardAPIVolumeFile | Yes | ファイル投影定義リスト | 少なくとも1つのアイテム |
| defaultMode | *int32 | No | デフォルトファイルパーミッション | nilでないこと |

### DownwardAPIVolumeFile項目

| フィールド | 型 | 説明 |
|-----------|-----|------|
| path | string | 出力ファイルパス |
| fieldRef | ObjectFieldSelector | Podフィールド参照（metadata.name、metadata.namespace、metadata.labels、metadata.annotations等） |
| resourceFieldRef | ResourceFieldSelector | コンテナリソース参照（limits.cpu、limits.memory、requests.cpu、requests.memory等） |
| mode | *int32 | ファイルパーミッション（個別指定） |

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| フィールドファイル | ファイル | fieldRefで指定されたPodフィールドの値 |
| リソースファイル | ファイル | resourceFieldRefで指定されたリソースの値 |

### 出力先

- `<kubeletDir>/pods/<podUID>/volumes/kubernetes.io~downward-api/<volumeName>/` (tmpfs上)

## 処理フロー

### 処理シーケンス（SetUpAt）

```
1. EmptyDirラッパー（Memory medium）セットアップ
2. CollectData: 各アイテムからデータ収集
   ├─ fieldRef: fieldpath.ExtractFieldPathAsString(pod, fieldPath)
   └─ resourceFieldRef: resource.ExtractResourceValueByContainerNameAndNodeAllocatable()
3. wrappedのSetUpAt
4. MakeNestedMountpoints
5. AtomicWriter.Write
6. FSGroup権限適用
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-129-1 | 読み取り専用 | DownwardAPIボリュームは常にReadOnly=true | 常時 |
| BR-129-2 | tmpfs使用 | wrappedVolumeSpecでStorageMediumMemoryを指定 | 常時 |
| BR-129-3 | 再マウント必須 | RequiresRemount=trueで定期更新をサポート（ラベル/アノテーション変更反映） | 常時 |
| BR-129-4 | パスクリーニング | filepath.Cleanでパスを正規化 | 常時 |
| BR-129-5 | モード指定 | items[].modeが指定されればそれを使用、なければdefaultMode | 常時 |
| BR-129-6 | エラー集約 | 複数アイテムのエラーをutilerrors.NewAggregateで集約 | 常時 |
| BR-129-7 | セットアップ失敗時クリーンアップ | SetUp失敗時にdeferでTearDownを実行 | 失敗時 |

## データベース操作仕様

| 操作 | 対象リソース | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ノードアロケータブル取得 | Node | SELECT | resourceFieldRef使用時にノードアロケータブルリソースを取得 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | フィールド抽出エラー | 無効なfieldPathが指定された | Pod Specの修正 |
| - | リソース抽出エラー | 無効なresourceFieldRefまたはコンテナ名が不正 | Pod Specの修正 |
| - | defaultMode未指定 | defaultModeがnil | Pod Specの修正 |
| - | ノードアロケータブル取得エラー | ノード情報が取得できない | ノード状態の確認 |

### リトライ仕様

RequiresRemount=trueによるkubelet sync loop経由でのリトライ。ラベルやアノテーションの変更は定期的に反映される。

## トランザクション仕様

AtomicWriterによるアトミック更新を保証。

## パフォーマンス要件

Pod情報はメモリ上で処理されるため、I/O待ちはない。ノードアロケータブル取得のみ外部依存。

## セキュリティ考慮事項

- DownwardAPIで公開される情報はPod自身のメタデータに限定される
- 他のPodの情報は取得できない
- tmpfs上に保存されるためディスクに残留しない

## 備考

- CollectData関数はProjectedボリュームからも呼び出される（エクスポート済み）
- DownwardAPI envVarとは異なり、ボリューム経由ではラベル/アノテーションの変更が自動反映される

---

## コードリーディングガイド

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | downwardapi.go | `pkg/volume/downwardapi/downwardapi.go` | downwardAPIPlugin構造体（44-46行目）: host |
| 1-2 | downwardapi.go | `pkg/volume/downwardapi/downwardapi.go` | downwardAPIVolume構造体（134-141行目）: volName、items、pod、podUID |
| 1-3 | downwardapi.go | `pkg/volume/downwardapi/downwardapi.go` | downwardAPIVolumeMounter構造体（145-148行目）: source |

#### Step 2: データ収集処理を理解する（最重要）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | downwardapi.go | `pkg/volume/downwardapi/downwardapi.go` | CollectData()（238-277行目）: メインのデータ収集処理 |
| 2-2 | downwardapi.go | `pkg/volume/downwardapi/downwardapi.go` | **246-252行目**: パスクリーニングとモード設定 |
| 2-3 | downwardapi.go | `pkg/volume/downwardapi/downwardapi.go` | **253-260行目**: fieldRef処理（ExtractFieldPathAsString） |
| 2-4 | downwardapi.go | `pkg/volume/downwardapi/downwardapi.go` | **261-272行目**: resourceFieldRef処理（ExtractResourceValueByContainerNameAndNodeAllocatable） |

**読解のコツ**: fieldRefはPodオブジェクトのフィールドパスを文字列で指定し、fieldpath.ExtractFieldPathAsStringが該当フィールドの値を文字列として抽出する。resourceFieldRefはコンテナ名+リソース名（limits.cpu等）を指定し、resource.ExtractResourceValueByContainerNameAndNodeAllocatableがノードアロケータブルも考慮して値を算出する。

#### Step 3: セットアップ処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | downwardapi.go | `pkg/volume/downwardapi/downwardapi.go` | SetUpAt()（170-231行目）: EmptyDirラッパー + CollectData + AtomicWriter |
| 3-2 | downwardapi.go | `pkg/volume/downwardapi/downwardapi.go` | TearDownAt()（295-297行目）: UnmountViaEmptyDir |

### プログラム呼び出し階層図

```
kubelet volume manager
    |
    ├─ downwardAPIPlugin.NewMounter(spec, pod)
    |      └─ downwardAPIVolumeMounter{} 構築
    |
    ├─ downwardAPIVolumeMounter.SetUp()
    |      └─ SetUpAt(dir)
    |             ├─ host.NewWrapperMounter()  [EmptyDir(Memory)ラッパー]
    |             ├─ CollectData(items, pod, host, defaultMode)
    |             |      ├─ [fieldRef] fieldpath.ExtractFieldPathAsString()
    |             |      └─ [resourceFieldRef] resource.ExtractResourceValueByContainerNameAndNodeAllocatable()
    |             ├─ wrapped.SetUpAt()
    |             ├─ volumeutil.MakeNestedMountpoints()
    |             ├─ volumeutil.NewAtomicWriter()
    |             └─ writer.Write(data, setPerms)
    |
    └─ downwardAPIVolumeUnmounter.TearDown()
           └─ TearDownAt()
                  └─ volumeutil.UnmountViaEmptyDir()
```

### データフロー図

```
[入力]                          [処理]                        [出力]

DownwardAPIVolumeSource ──▶ NewMounter() ──────▶ downwardAPIVolumeMounter
  items[] ─────────────────▶    │
  defaultMode ─────────────▶    │
                                 │
Pod Object ────────────────▶ CollectData()
  metadata.name ───────────▶    │
  metadata.labels ─────────▶    ├──▶ ファイル群（tmpfs上）
  resources.limits ────────▶    │
Node Allocatable ──────────▶    │
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| downwardapi.go | `pkg/volume/downwardapi/downwardapi.go` | ソース | メイン実装 |
| fieldpath/ | `pkg/fieldpath/` | ソース | Podフィールドパス抽出 |
| api/v1/resource/ | `pkg/api/v1/resource/` | ソース | コンテナリソース値抽出 |
| util/atomic_writer.go | `pkg/volume/util/atomic_writer.go` | ソース | アトミックファイル書き込み |
| emptydir/empty_dir.go | `pkg/volume/emptydir/empty_dir.go` | ソース | tmpfsラッパー |
