Kubernetes 1.25: SIG-Apps の変更内容

## はじめに

このページではKubernetes v1.25 における SIG-Apps に関連する変更内容をまとめています。

- https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.25.md

SIG-AppsはKubernetesのワークロードの扱いなどの変更を主に扱っているため、他のSIGと関係する変更が多くなっております。

- 直近での過去の変更内容は以下になります。
  - [Kubernetes 1.24: SIG-Apps の変更内容](https://qiita.com/yosshi_/items/08539d8f9e14da73c152)
  - [Kubernetes 1.23: SIG-Apps の変更内容](https://qiita.com/yosshi_/items/5ef6805eb358631fbbbc)
  - [Kubernetes 1.22: SIG-Apps の変更内容](https://qiita.com/yosshi_/items/95b8a38ad1c44a0266bd)


<details><summary>SIG / SIG-Apps とは？</summary><div>

- SIGとは？
    - Special Interest Groups の略称
    - 各 SIG には Subproject が与えられていて、 Subproject に対して独立して開発できるようになっています。
    - Kubernetes は巨大なプロジェクトなので、各SIG 毎に担当(Subproject)が割り当てられていて、各SIG は独立して開発をしています。
    - SIG 間を跨って話し合いをする必要が生じた場合は Working Groups が一時的に作られ、その枠組みの中で話し合うことになります。

   
- SIG-Appsとは？
    - Apps Special Interest Group の略称
    - Kubernetes に対して、application を deploy したりすることに関することが対象。具体的には Pod, ReplicaSet, Deployments, DaemonSet, StatefulSet, Jobs, CronJob が対象。
![Kubernetes基礎_-_Google_Slides.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309176/78f42f49-da9f-c268-9034-e8d73556334a.png)
    - 詳細について知りたい方は[こちら](https://github.com/kubernetes/community/tree/master/sig-apps)をご参照ください。


</div></details>

SIG-Apps 以外の SIG に関する変更は以下にまとめてありますので、合わせてご参照下さい。

- [Kubernetes 1.25: 変更点まとめ(What's new!)とアップグレード時の注意事項](https://qiita.com/uesyn/items/c537c739e179dc3562de)

## 注目の変更
Feature Gatesの中で今回Stageに変更のあった[Sig-Appsに関連する機能](https://github.com/kubernetes/enhancements/tree/master/keps/sig-apps)は以下になります。

- Pod
  - `PodDisruptionConditions`：`Alpha` https://github.com/kubernetes/enhancements/issues/3329
- Job
  - `JobPodFailurePolicy`：`Alpha` https://github.com/kubernetes/enhancements/issues/3329
  - `CronJobTimeZone`：`Beta` https://github.com/kubernetes/enhancements/issues/3140
- StatefulSet
  - `StatefulSetMinReadySeconds`：`Stable` https://github.com/kubernetes/kubernetes/issues/65098
- DaemonSet
  - `DaemonSetUpdateSurge`：`Stable` https://github.com/kubernetes/enhancements/issues/1591

:::note warn
**注意点**
未解決のバグがあるため、`Beta` ですがデフォルトで無効化されていた　　　`JobTrackingWithFinalizers`　がデフォルトで有効化されるようになりました。詳細については[こちら](https://github.com/kubernetes/kubernetes/pull/110948)をご確認ください。
:::

上記のうちで今回追加された`PodDisruptionConditions`と`JobPodFailurePolicy`についてもう少し詳しく記載します。その他の機能については、過去のSIG-Apps の変更内容をご確認下さい。


### Pod

#### Pod disruption conditions 

Pod 中断時の理由が追加されるようになります。


- 関連情報

|  KEP  |  [KEP-3329](https://github.com/kubernetes/enhancements/tree/master/keps/sig-apps/3329-retriable-and-non-retriable-failures)  |
| ---- | ---- |
|  **Feature stage**  |  **Alpha**  |
|  **Feature Gate**  |  **PodDisruptionConditions** | 
|  **issue**  |  **[#3140](https://github.com/kubernetes/enhancements/issues/3329)** | 
|  **PR**  |  **[#104915](https://github.com/kubernetes/kubernetes/pull/110959)** | 
|  **参考**  |  **[公式ドキュメント](https://kubernetes.io/docs/concepts/workloads/pods/disruptions/#pod-disruption-conditions)** | 

<details><summary>詳しい内容の説明 (クリックすると開きます)</summary><div>

pod の `status.conditions.type` に新しく `DisruptionTarget` が追加されました。
Kubernetes v1.24 までは以下の 5 つが存在していました。

- PodScheduled
- Ready
- Initialized
- Unschedulable
- ContainersReady

上記については[こちらの公式ドキュメント](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-conditions)や pod の describe の結果から確認できます。

```
$ kubectl describe po <Pod名>
apiVersion: v1
kind: Pod
metadata:
　　　:
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
　　　:
```

上記に加えて、Kubernetes v1.25 から Feature stage Alpha で以下の 2 つの `status.conditions.type` が追加されていました

- [PodHasNetwork (Feature Gate : PodHasNetworkCondition)](https://kubernetes.io/blog/2022/09/14/pod-has-network-condition/)
- DisruptionTarget (Feature Gate : PodDisruptionConditions)

上記のうち、今回の説明の対象は `DisruptionTarget` になります。
これは Pod の中断時に以下の 4 つの `reason` のいずれかとともに `status.conditions` に記録されるようになります。

- `PreemptionByKubeScheduler`
  kube-scheduler によって Pod がプリエンプションされた場合 
  [Preemption](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/) についてはこちらを参照ください
- `DeletionByTaintManager`
  NoExecute taint が理由で Taint Manager について削除された場合  
  [Taint](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) についてはこちらを参照ください
- `EvictionByEvictionAPI`
  Eviction API によって Pod evicte された場合  
  [Eviction API](https://kubernetes.io/docs/concepts/scheduling-eviction/api-eviction/) についてはこちらを参照ください
- `DeletionByPodGC`
  PodGC によって孤立した Pod が削除された場合  
  [Pod の Garbage collection](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-garbage-collection) についてはこちらを参照ください
  

`Pod disruption conditions` については単体でももちろん使用できますが、後述する `Pod failure policy` で使用することを想定して追加されたという背景があります。

</div></details>

### Job

#### Pod failure policy

Job が管理する Pod が失敗した時の挙動を Exit Code か PodCondition　に応じて指定できる機能です。

- 関連情報

|  KEP  |  [KEP-3329](https://github.com/kubernetes/enhancements/tree/master/keps/sig-apps/3329-retriable-and-non-retriable-failures)  |
| ---- | ---- |
|  **Feature stage**  |  **Alpha**  |
|  **Feature Gate**  |  **JobPodFailurePolicy** | 
|  **issue**  |  **[#3140](https://github.com/kubernetes/enhancements/issues/3329)** | 
|  **PR**  |  **[#104915](https://github.com/kubernetes/kubernetes/pull/111113)** | 
|  **参考**  |  **[公式ドキュメント](https://kubernetes.io/docs/concepts/workloads/controllers/job/#pod-failure-policy)** | 

<details><summary>詳しい内容の説明 (クリックすると開きます)</summary><div>

以下のように Job のマニフェストに `spec.podFailurePolicy` を追加して使用します。

```diff
apiVersion: batch/v1
kind: Job
metadata:
  name: job-pod-failure-policy-example
spec:
  completions: 12
  parallelism: 3
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: main
        image: docker.io/library/bash:5
        command: ["bash"]        # example command simulating a bug which triggers the FailJob action
        args:
        - -c
        - echo "Hello world!" && sleep 5 && exit 42
  backoffLimit: 6
+  podFailurePolicy:
+    rules:
+    - action: FailJob
+      onExitCodes:
+        containerName: main      # optional
+        operator: In             # one of: In, NotIn
+        values: [42]
+    - action: Ignore             # one of: Ignore, FailJob, Count
+      onPodConditions:
+      - type: DisruptionTarget   # indicates Pod disruption
```

上記のように `spec.podFailurePolicy` に複数の `rules` を記述できます。


`rules` を 1 組作るためには 2 つの設定が必要になります。
- `action`
  ルール適用時の動作内容
- `onExitCodes` or `onPodConditions`
  ルール適用の条件

`action` で設定できる内容は以下の 3 つになります。

- `Count`
  `JobPodFailurePolicye` の導入以前の失敗の挙動と同じになります。失敗として記録され `.spec.backoffLimit` がインクリメントされます。
- `FailJob`
  を失敗として記録され、該当の Pod を管理する Job で実行中の全ての Pod を停止します。
- `Ignore`
  失敗について記録されずに新しい Pod が作成され `.spec.backoffLimit` がインクリメントされません。

次に `onExitCodes` と `onPodConditions` のそれぞれについて説明していきます。

`onExitCodes` は コンテナの `exit code` (`.state.terminated.exitCode`) を条件に指定できます。  
設定できる内容は以下の 3 つになります。

```yaml
podFailurePolicy:
  rules:
  - action: FailJob
    onExitCodes:
      containerName: main      # optional
      operator: In             # one of: In, NotIn
      values: [42]
```

- `operator` (必須) 
  - `In` or `NotIn` のいずれかを指定します。
- `values` (必須) 
  - 条件に指定したい `exit code` を指定できます。
  - `0` 以外の正の整数が指定できます。
  - 複数の値が指定でき、指定できる上限数は 255 です。
- `containerName` (任意) 
  - Pod 内に含まれる `container` or `initContainer` の名前を指定できます。
  - 指定した場合：対象のコンテナの `exit code` のみが判定の条件になります。
  - 未指定の場合：Pod に含まれる全てのコンテナの `exit code` が条件の対象になります。


`onPodConditions` について説明します。

```yaml
podFailurePolicy:
  rules:
  - action: Ignore             # one of: Ignore, FailJob, Count
    onPodConditions:
    - type: DisruptionTarget   # indicates Pod disruption
```

こちらは pod の `status.conditions.type` を条件に Job で管理する Pod の挙動を制御するためのものになります。  
設定できる内容は以下の 2 つになります。

- `type`(必須) 
  - `status.conditions.type` を指定します
  - 機能としては、`Initialized` や `Unschedulable` を条件にすることはできますが、利用ケースとしては `Pod disruption conditions` を有効化して `DisruptionTarget` 指定するというのが想定されています。 
- `status` (必須) 
  - `status.conditions.type` の `status` を `true` or `false` で指定します。
  - フィールドとしては必須ですが、未指定の場合はデフォルトで `true` が代入されるようになっています。

上記の説明を理解すると `rules` を作成できるようになります。
最後に複数の `rules` を作成した場合の挙動について説明します。

- 順番に判定していき、1つでも該当するものがあればその時点で `action` が実行され残りのルールは無視される。
- どのルールにも該当しない場合は、デフォルトの挙動になる。(Job を失敗として記録し`.spec.backoffLimit` がインクリメントされる)
- ルールは最大で20個設定できる

さらに詳細の内容について知りたい場合は以下のコマンドを実行して、API の内容を確認することをお勧めします。

```yaml
$ kubectl explain job.spec.podFailurePolicy

$ kubectl explain job.spec.podFailurePolicy.rules

$ kubectl explain job.spec.podFailurePolicy.rules.onExitCodes

$ kubectl explain job.spec.podFailurePolicy.rules.onPodConditions
```

</div></details>

## v1.25 Release Notes

v1.25 Release Notes の中で SIG-Apps に関するものについて以下に和訳したものを記載します。

> :pencil: がついた文章は、CHANGELOGの公式内容ではなく筆者の補足です。


### :wastebasket: Deprecation(非推奨)
特になし

### :earth_asia: API Changes（API変更）
- pod failure policy rules に基づいて、Pod の失敗時に処理をハンドリングする機能が追加されました ([#111113](https://github.com/kubernetes/kubernetes/pull/111113), [@mimowo](https://github.com/mimowo))

- pod の condition type に `DisruptionTarget` 追加されます。`reason` フィールドに pod termination 時に以下が追加されるようになります。
  - PreemptionByKubeScheduler (kube-scheduler によって Pod がプリエンプションされた場合)
  - DeletionByTaintManager (NoExecute　が原因で　taint　manager によって Pod が削除された場合)
  - EvictionByEvictionAPI (Eviction API によって Pod evicte された場合)
  - DeletionByPodGC (PodGC によって孤立した Pod が削除された場合) ([#110959](https://github.com/kubernetes/kubernetes/pull/110959), [@mimowo](https://github.com/mimowo))

- StatefulSet の minReadySeconds が GA になりました。kube-apiserver と kube-controller-manager に対する `--feature-gates=StatefulSetMinReadySeconds=true` のフラグは不要となり、該当のフラグは次のポリシーに基づいて削除される予定になります。 https://kubernetes.io/docs/reference/using-api/deprecation-policy/#deprecation ([#110896](https://github.com/kubernetes/kubernetes/pull/110896), [@ravisantoshgudimetla](https://github.com/ravisantoshgudimetla)) [SIG API Machinery, Apps and Testing]

- CronJob の TimeZone 機能が beta になりました。 ([#111435](https://github.com/kubernetes/kubernetes/pull/111435), [@soltysh](https://github.com/soltysh))
  - :pencil: 紆余曲折ありましたが、ついに CronJob を spec.timeZone="Asia/Tokyo" で実行できるようになります。詳しい情報を知りたい方は以前書いた[こちらの記事](https://qiita.com/yosshi_/items/08539d8f9e14da73c152#timezone-support-in-cronjob)参照ください。

- DaemonSet MaxSurge が GA になりました。 kube-apiserver と kube-controller-manager に対する `--feature-gates=DaemonSetUpdateSurge=true` のフラグは不要となり、該当のフラグは次のポリシーに基づいて削除される予定になります https://kubernetes.io/docs/reference/using-api/deprecation-policy/#deprecation . ([#111194](https://github.com/kubernetes/kubernetes/pull/111194), [@ravisantoshgudimetla](https://github.com/ravisantoshgudimetla))
  - :pencil: 特に機能の追加変更はなく GA になったようです。ドキュメントの方には追加されてませんが、KEP の方には [Troubleshooting の Playbook](https://github.com/kubernetes/enhancements/tree/master/keps/sig-apps/1591-daemonset-surge#troubleshooting)が追加されてるので、利用される場合は一読しておくといいと思います。

### :sparkle: Feature（機能追加）

- Pod の DisruptionTarget condition が status=True かつ２分以上 DeletionTimestamp がない場合に、control plane が DisruptionTarget condition を status=False にリセットするようになります。([#111475](https://github.com/kubernetes/kubernetes/pull/111475), [@alculquicondor](https://github.com/alculquicondor))
  - :pencil: これは新しく追加された `PodDisruptionConditions` に関する変更になります。DisruptionTarget condition を管理するコントローラーが Pod 削除前に何らかの理由で再起動した際に、古い status の状態のまま残り続けるのを抑止するために追加されました。

- `JobTrackingWithFinalizers` がデフォルトで有効になります。この機能により Pod が API-Server に頼らずに状態が追跡されるようになります。 ([#110948](https://github.com/kubernetes/kubernetes/pull/110948), [@alculquicondor](https://github.com/alculquicondor))
  - :pencil: `JobTrackingWithFinalizers` の機能は k8s v1.23 で `Beta` となり、デフォルトで有効化されていましたが未解決のバグがあったため無効化されていました。それが今回の変更でデフォルトで有効に戻った形になります。
  - :pencil: 過去の経緯については以前書いた[こちらの記事](https://qiita.com/yosshi_/items/08539d8f9e14da73c152#%E6%B3%A8%E7%9B%AE%E3%81%AE%E5%A4%89%E6%9B%B4)を参照ください。


- StatefulSets に MaxUnavailable が導入されたことにより、一度に複数の Pod を停止できるようになっため、 RollingUpdate が早くなります。 同時にダウンできる Pod は maxUnavailable のパラメータで設定できます。 ([#109251](https://github.com/kubernetes/kubernetes/pull/109251), [@krmayankk](https://github.com/krmayankk)) [SIG Apps and CLI]
  - :pencil: Changelogの内容は StatefulSets に MaxUnavailable が導入されたこと全体の説明になっていますが、街頭の PR での変更内容は `kubectl describe statefulset` に `MaxUnavailable` が表示されるようになったことだけになります。

### :page_facing_up: Documentation（ドキュメント改善）
特になし

### :hammer_and_wrench: ENHANCEMENT（機能改善）
特になし

### :bug: Bug or Regression(バグ修正)
- ResourceQuota と一時的に衝突した際に、job が再実行されないケースのバグが修正されました。 ([#111026](https://github.com/kubernetes/kubernetes/pull/111026), [@alculquicondor](https://github.com/alculquicondor))

- 失敗した job の condition status を `False` に変更した場合に、conditions に複数の結果が記載されないように変更されました([#110292](https://github.com/kubernetes/kubernetes/pull/110292), [@mimowo](https://github.com/mimowo))
  - :pencil: 以下の issue 申告に対する修正になります、
  - https://github.com/kubernetes/kubernetes/issues/109904

- 設定時に job controller が activeDeadlineSeconds が強制されないバグが修正されました。 ([#110294](https://github.com/kubernetes/kubernetes/pull/110294), [@harshanarayana](https://github.com/harshanarayana))

- job が失敗と判定された後に pod が成功した場合に、API と競合して job の終了がブロックされる JobTrackingWithFinalizers のバグが修正されました。 ([#111646](https://github.com/kubernetes/kubernetes/pull/111646), [@alculquicondor](https://github.com/alculquicondor))

- 以下の `JobTrackingWithFinalizers` のバグが修正されました
  - 作成された全ての Pod のステータスが全てカウントされる前に、job の終了が宣言されていたバグ
  - finalizers を持つ pod が残っている場合に、pod と job が削除できないバグ
   `JobTrackingWithFinalizers` はまだデフォルトで無効化されています。 ([#109486](https://github.com/kubernetes/kubernetes/pull/109486), [@alculquicondor](https://github.com/alculquicondor))

- `JobTrackingWithFinalizers` に関連して job controller がメモリリークするバグが修正されました([#111721](https://github.com/kubernetes/kubernetes/pull/111721), [@alculquicondor](https://github.com/alculquicondor))

- cronjobs に `@every X` の形式で実行時刻を指定した場合にリキューされない不具合を修正 ([#109250](https://github.com/kubernetes/kubernetes/pull/109250), [@d-honeybadger](https://github.com/d-honeybadger)) [SIG Apps]
  - :pencil: そもそも CronJob の `spec.schedule` に `@every X` 形式で設定できることを知らなかったので、新鮮な気持ちでした。

### :microscope: Other (その他の修正)
特になし

## 所感

今回の変更の中では `Pod failure policy` が一番の注目かなと思います。今まで Kubernetes で Job を実行する際には Preemption によって Pod が中断するケースなどについては、 backoffLimit 値を多めに設定してリトライ回数を増やしておくことでしか対応できませんでした。


`Pod failure policy` が GA になれば、Job を実行する際に以下のように DisruptionTarget の時に Ignore を設定するのが定石になるのかなという期待が持てる機能追加に感じました。

```diff
apiVersion: batch/v1
kind: Job
metadata:
  name: job-pod-failure-policy-example
spec:
　　　　:
  backoffLimit: 6
+  podFailurePolicy:
+    rules:
+    - action: Ignore             # one of: Ignore, FailJob, Count
+      onPodConditions:
+      - type: DisruptionTarget   # indicates Pod disruption
```

紆余曲折あった CronJob の TimeZone　対応と`JobTrackingWithFinalizers` が有効化されました。 `JobTrackingWithFinalizers`　　についてはいくつかのバグが修正されて再びデフォルトで true となりましたが、今後の動向についてはまだ少し注意していきたいと思っています。