Kubernetes 1.21: SIG-Apps の変更内容

## はじめに

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

- https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.21.md
- https://relnotes.k8s.io/?releaseVersions=1.21.0&sigs=apps

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

- 直近での過去の変更内容は以下になります。
  - [Kubernetes 1.19: SIG-Apps の変更内容](https://qiita.com/yosshi_/items/56493481553ded0c3ad1)
  - [Kubernetes 1.20: SIG-Apps の変更内容](https://qiita.com/yosshi_/items/20994d6446688c5c066a)


<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 あたりが開発対象。
    - 詳細について知りたい方は[こちら](https://github.com/kubernetes/community/tree/master/sig-apps)をご参照ください。
</div></details>

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

- [Kubernetes 1.21: 変更点まとめ(What's new!)](https://qiita.com/uesyn/items/49a76dd029a1371f8cf8) 

## 注目の変更
今回は、SIG-Apps に関して大きな変更が多かったので個人的に気になるものをいくつかピックアップして先に紹介していきます。

### DaemonSet
#### Allow DaemonSets to surge during update like Deployments
DaemonSet に MaxSurge が導入されました。
従来の通りだと、DaemonSet がローリングアップグレードする際には、既存の Pod が削除された後に新しい Pod が立ち上がり始めるのでダウンタイムが長かったのですが、 MaxSurge を利用すると新しい Pod が Ready になってから古い Pod が削除され始めるのでダウンタイムの低減が期待できます。

- 関連情報

|  KEP  |  [KEP-1591](https://github.com/kubernetes/enhancements/tree/master/keps/sig-apps/1591-daemonset-surge)  |
| ---- | ---- |
|  **Feature stage**  |  **Alpha**  |
|  **Feature Gate**  |  **DaemonSetUpdateSurge** | 
|  **issue**  |  **[#1591](https://github.com/kubernetes/enhancements/issues/1591)** | 
|  **PR**  |  **[#96441](https://github.com/kubernetes/kubernetes/pull/96441)** | 

<details><summary>実際の使用イメージ (クリックすると開きます)</summary><div>

- 以下のように `maxSurge` を設定した DaemonSet を用意します。

```yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ds-maxsurge
spec:
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1  # デフォルトでは 0 が設定されています
  selector:
    matchLabels:
      app: ds-maxsurge
  template:
    metadata:
      labels:
        app: ds-maxsurge
    spec:
      containers:
      - name: nginx
        image: nginx:1.18
```

- ついに、DaemonSet に `maxSurge` が設定できるようになっています。

```
$ kubectl apply -f ds.yaml                                            
daemonset.apps/ds-maxsurge created

$ kubectl get ds -ojson | jq -r '.items[].spec.updateStrategy'
{
  "rollingUpdate": {
    "maxSurge": 1,
    "maxUnavailable": 0
  },
  "type": "RollingUpdate"
}
```

- ローリングアップデートすると `maxSurge` が機能してることが確認できます。

```sh
$ kubectl set image DaemonSet/ds-maxsurge nginx=nginx:1.19  
daemonset.apps/ds-maxsurge image updated

$ kubectl get po -o wide                                                 
NAME                READY   STATUS              RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
ds-maxsurge-gqjbq   0/1     ContainerCreating   0          25s   <none>       minikube   <none>           <none>
ds-maxsurge-rd5t8   1/1     Running             0          81s   172.17.0.4   minikube   <none>           <none>
```

まだ、同一ノード上で Running の Pod があるにも関わらず、新しい Pod の ContainerCreating になっているところが今回の大きな変更になります。

##### 注意点：hostPort の利用
[KEP-1591](https://github.com/kubernetes/enhancements/tree/master/keps/sig-apps/1591-daemonset-surge) にも記載がありますが、 `maxSurge` と `hostPort` は併用できません。

- hostPort を利用するマニフェストを作成してデプロイしてみます。

```diff
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ds-maxsurge
spec:
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
+      maxSurge: 1
  selector:
    matchLabels:
      app: ds-maxsurge
  template:
    metadata:
      labels:
        app: ds-maxsurge
    spec:
+      hostNetwork: true
      containers:
      - name: nginx
        image: nginx:1.18
        ports:
        - containerPort: 80
+          hostPort: 80
```

- Pod の生成には成功します。

```diff
$ kubectl get ds -o yaml 
          ports:
          - containerPort: 80
+            hostPort: 80
+        hostNetwork: true
    updateStrategy:
      rollingUpdate:
+        maxSurge: 1
        maxUnavailable: 0
      type: RollingUpdate
```

- ローリングアップデートをすると新しい Pod がずっと Pending になります。

```
$ kubectl set image DaemonSet/ds-maxsurge nginx=nginx:1.19  
daemonset.apps/ds-maxsurge image updated

$ kubectl get po
NAME                READY   STATUS    RESTARTS   AGE
ds-maxsurge-khm9w   0/1     Pending   0          17s
ds-maxsurge-s2zpz   1/1     Running   0          4m59s
```

- 中を確認すると、port がなくてスケジューラーが割り当てられないことが分かります。

```
$ kubectl describe po ds-maxsurge-khm9w   
    :
Events:
  Type     Reason            Age                From               Message
  ----     ------            ----               ----               -------
  Warning  FailedScheduling  29s (x2 over 31s)  default-scheduler  0/1 nodes are available: 1 node(s) didn't have free ports for the requested pod ports.
```

おそらくこの挙動はベータになるときに、`maxSurge` と `hostPort` の両方を設定した DaemonSet がそもそも作成できないように変更になるのかなと思ってます。


- 補足  
本来なら、公式ドキュメントの[Feature Gates](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/) を確認するとアルファ機能を利用するために必要な Feature Gate 名が分かるのですが、今回は公式ドキュメントの更新が漏れてます。そういう時は該当機能の [KEP](https://github.com/kubernetes/enhancements/tree/master/keps/sig-apps/1591-daemonset-surge) と ソースコードの [kube_features.go](https://github.com/kubernetes/kubernetes/blob/v1.21.0/pkg/features/kube_features.go#L836) を照らし合わせながら確認すると対象機能の Feature Gate 名が取得できます。


```go
	// owner: @smarterclayton
	// alpha: v1.21
	//
	// DaemonSets allow workloads to maintain availability during update per node
	DaemonSetUpdateSurge featuregate.Feature = "DaemonSetUpdateSurge"
          :
          :
	DaemonSetUpdateSurge:                           {Default: false, PreRelease: featuregate.Alpha},
```
</div></details>


### Job
#### Indexed Job  
Job を実行時に `completionMode` に `Indexed` を設定することで、Job を実行する Pod は、 Job 内でユニークな `Completed Indexes` を持つことが出来るようになります。
これにより、 Pod が実行時に自身に割り当てられた `Completed Indexes` を確認して処理を分岐することで、一つの Job の中でそれぞれの Pod が別の処理を容易に実現できるようになります。(今までは、これを実行するために、他の仕組みと併用する必要がありました。)

- 関連情報

|  KEP  |  [KEP-2214](https://github.com/kubernetes/enhancements/tree/master/keps/sig-apps/2214-indexed-job)  |
| ---- | ---- |
|  **Feature stage**  |  **Alpha**  |
|  **Feature Gate**  |  **IndexedJob** | 
|  **issue**  |  **[#2214](https://github.com/kubernetes/enhancements/issues/2214), [#14188](https://github.com/kubernetes/kubernetes/issues/14188)** | 
|  **PR**  |  **[#98441](https://github.com/kubernetes/kubernetes/pull/98441), [#98812](https://github.com/kubernetes/kubernetes/pull/98812)** | 

<details><summary>実際の使用イメージ (クリックすると開きます)</summary><div>

- 以下のように `completionMode` を設定した Job のマニフェストを用意します。

```yaml 
apiVersion: batch/v1
kind: Job
metadata:
  name: 'indexed-job'
spec:
  completions: 5
  parallelism: 3
  completionMode: Indexed  # デフォルトでは NonIndexed が設定されています
  template:
    spec:
      restartPolicy: Never
      initContainers:
      - name: 'input'
        image: 'docker.io/library/bash'
        command:
        - "bash"
        - "-c"
        - |
          items=(foo bar baz qux xyz)
          echo ${items[$JOB_COMPLETION_INDEX]} > /input/data.txt  # $JOB_COMPLETION_INDEX で取得        
        volumeMounts:
        - mountPath: /input
          name: input
      containers:
      - name: 'worker'
        image: 'docker.io/library/busybox'
        command:
        - "rev"
        - "/input/data.txt"
        volumeMounts:
        - mountPath: /input
          name: input
      volumes:
      - name: input
        emptyDir: {}
```

- 実際に実行すると以下のようになります。

```
$ kubectl get job,po
NAME                    COMPLETIONS   DURATION   AGE
job.batch/indexed-job   3/5           17s        17s

NAME                    READY   STATUS      RESTARTS   AGE
pod/indexed-job-65cvf   0/1     Init:0/1    0          3s
pod/indexed-job-7r5f7   0/1     Completed   0          17s
pod/indexed-job-g2r5r   0/1     Completed   0          17s
pod/indexed-job-pwrh8   0/1     Init:0/1    0          5s
pod/indexed-job-t264f   0/1     Completed   0          17s
```

- Job を確認すると以下のようになります。

```diff
$ kubectl describe job                            
Name:               indexed-job
Namespace:          default
Selector:           controller-uid=e14835d4-18aa-45ab-8904-1fbeb27239bb
Labels:             controller-uid=e14835d4-18aa-45ab-8904-1fbeb27239bb
                    job-name=indexed-job
Annotations:        <none>
Parallelism:        3
Completions:        5
Completion Mode:    %!s(*v1.CompletionMode=0xc0002b9fc0)
Start Time:         Thu, 22 Apr 2021 08:31:59 +0900
Completed At:       Thu, 22 Apr 2021 08:32:25 +0900
Duration:           26s
Pods Statuses:      0 Running / 5 Succeeded / 0 Failed
+ Completed Indexes:  0-4  # 0 〜 {Completions - 1} になっています
Pod Template:
```

- Pod 毎の処理結果を確認すると、結果がそれぞれに異なることが分かります。

```
$ kubectl logs indexed-job-65cvf 
zyx  # Completed Indexes が 4 だったため

$ kubectl logs indexed-job-7r5f7                                            
bar  # Completed Indexes が 2 だったため
```
</div></details>

#### Suspend Jobs
Job を実行時に `suspend` に `true` を設定することで、 Job を一時停止することが出来るようになりました。
今までだと、途中で優先度の高い Job が実行されたとしても既存の実行中の Job は実行し続けていましたが、この機能を使うことにより、限られたクラスタのリソースをより複雑な Job のワークロードの中でうまく使えるようになります。

- 関連情報


|  KEP  |  [KEP-2322](https://github.com/kubernetes/enhancements/tree/master/keps/sig-apps/2232-suspend-jobs)  |
| ---- | ---- |
|  **Feature stage**  |  **Alpha**  |
|  **Feature Gate**  |  **SuspendJob** | 
|  **issue**  |  **[#2232](https://github.com/kubernetes/enhancements/issues/2232)** | 
|  **PR**  |  **[#98727](https://github.com/kubernetes/kubernetes/pull/98727)** | 

<details><summary>実際の使用イメージ (クリックすると開きます)</summary><div>

- 以下のように `suspend` を設定した Job のマニフェストを用意します。

```yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: my-job
spec:
  suspend: true # デフォルトでは false が設定されています
  parallelism: 2
  completions: 10
  template:
    spec:
      containers:
      - name: my-container
        image: busybox
        command: ["sleep", "5"]
      restartPolicy: Never
```

- 実行すると以下のようになり、 `Job suspended` となっていることが分かります。

```diff
$ kubectl get job,po        
NAME               COMPLETIONS   DURATION   AGE
job.batch/my-job   0/10                     7s



$ k describe job 
Name:             my-job
Namespace:        default
Selector:         controller-uid=47a07336-12ca-4681-90b9-4ba8b7bc8bbd
Labels:           controller-uid=47a07336-12ca-4681-90b9-4ba8b7bc8bbd
                  job-name=my-job
Annotations:      <none>
Parallelism:      2
Completions:      10
Completion Mode:  %!s(*v1.CompletionMode=0xc0006bcf30)
Pods Statuses:    0 Running / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  controller-uid=47a07336-12ca-4681-90b9-4ba8b7bc8bbd
           job-name=my-job
  Containers:
   my-container:
    Image:      busybox
    Port:       <none>
    Host Port:  <none>
    Command:
      sleep
      5
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Events:
  Type    Reason     Age   From            Message
  ----    ------     ----  ----            -------
+  Normal  Suspended  20s   job-controller  Job suspended
```

- `suspend` を `false` に変更します。

```diff
$ kubectl edit job my-job     

spec:
-  suspend: true
+  suspend: false
```

- Job が実行されることが確認できます。

```
$ kubectl get job,po
NAME               COMPLETIONS   DURATION   AGE
job.batch/my-job   1/10          13s        7m51s

NAME               READY   STATUS              RESTARTS   AGE
pod/my-job-7dlq7   0/1     ContainerCreating   0          2s
pod/my-job-ptzxp   0/1     Completed           0          13s
pod/my-job-tk6d8   1/1     Running             0          13s
```

手動で `suspend` の値を切り替えることはあまりないと思いますが、 Operator 等で上手く制御することで、複雑な Job のワークロードを Kubernetes 上で実行するための下地の一つが出来たかなという印象があります。

</div></details>

### ReplicaSet

#### Random Pod Selection on ReplicaSet Downscale
ReplicaSet をスケールダウンするときに優先的に削除される Pod が、従来では起動時間が短い Pod が優先的に削除されてましたが、この優先度の付け方に少し変更が入りました。これは、起動時間の短い Pod の方がより影響範囲が小さいだろうという仮定の元に実装されていました。

今回の変更では以下のように変更になっています。

1. Pod の起動時間を対数目盛(logarithmic scale) で丸め込んでから起動時間の短い方を比較
1. 同じものがあれが、Pod の UUID で比較する。

これにより、従来の起動時間が短いものを優先するというのをある程度守りながら、 UUID を用いることでランダムに選択されるようになりました。

<details><summary>Pod の起動時間を対数目盛を丸め込むイメージ (クリックすると開きます)</summary><div>

基数 10 で対数目盛を使用した際のイメージになります。

| Duration | Scale |
|----------|-------|
| 5ns      | 0     |
| 23ns     | 1     |
| 71ns     | 1     |
| 1ms      | 6     |
| 8ms      | 6     |
| 50ms     | 7     |
| 2m       | 11    |
| 11m      | 11    |

ある程度起動時間の近しいものだけが、比較対象となり、 UUID を用いて擬似的にランダムで削除される Pod が選択されるイメージが持てるかと思います。

</div></details>

- 関連情報

|  KEP  |  [KEP-2185](https://github.com/kubernetes/enhancements/tree/master/keps/sig-apps/2185-random-pod-select-on-replicaset-downscale)  |
| ---- | ---- |
|  **Feature stage**  |  **Alpha**  |
|  **Feature Gate**  |  **LogarithmicScaleDown** | 
|  **issue**  |  **[#2185](https://github.com/kubernetes/enhancements/issues/2185), [#96748](https://github.com/kubernetes/kubernetes/issues/96748)** | 
|  **PR**  |  **[#99212](https://github.com/kubernetes/kubernetes/pull/99212)** | 




#### ReplicaSet Pod Deletion Cost
Pod に `controller.kubernetes.io/pod-deletion-cost` のアノテーションを付与することで、スケールダウン時に優先的に削除するように制御できるようになりました。
従来だと、起動時間が短いものがより優先的に削除されましたが、例えば preemptible/spot VM などで起動している Pod を優先的に削除したいなど、起動時間と削除の優先度に関係がない場合により柔軟な制御が可能になりました。



- 関連情報

|  KEP  |  [KEP-2255](https://github.com/kubernetes/enhancements/tree/master/keps/sig-apps/2255-pod-cost)  |
| ---- | ---- |
|  **Feature stage**  |  **Alpha**  |
|  **Feature Gate**  |  **PodDeletionCost** | 
|  **issue**  |  **[#2255](https://github.com/kubernetes/enhancements/issues/2255)** | 
|  **PR**  |  **[#99163](https://github.com/kubernetes/kubernetes/pull/99163)** | 


<details><summary>実際の使用イメージ (クリックすると開きます)</summary><div>

- 以下のように `controller.kubernetes.io/pod-deletion-cost` のアノテーションを設定した Deployment のマニフェストを用意します。

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
      annotations:
　　　　　# 何も設定していない場合は、"0" が設定されているものとしてコスト計算されます
        controller.kubernetes.io/pod-deletion-cost: "0" 
    spec:
      containers:
      - name: nginx
        image: nginx
```

- Deployment によって、 Pod が3つ生成されます。

```
$ kubectl get po
NAME                                READY   STATUS    RESTARTS   AGE
sample-deployment-d9489fcc6-2vt9n   1/1     Running   0          5m14s
sample-deployment-d9489fcc6-q69bk   1/1     Running   0          5m14s
sample-deployment-d9489fcc6-twhrr   1/1     Running   0          5m14s
```

- 1つだけ Pod を削除し、 Pod の起動時間が他より短くなるようにします。

```
$ kubectl delete po sample-deployment-d9489fcc6-2vt9n
pod "sample-deployment-d9489fcc6-2vt9n" deleted

$ kubectl get po                                        
NAME                                READY   STATUS    RESTARTS   AGE
sample-deployment-d9489fcc6-7wvvc   1/1     Running   0          15s
sample-deployment-d9489fcc6-q69bk   1/1     Running   0          5m37s
sample-deployment-d9489fcc6-twhrr   1/1     Running   0          5m37s
```

- 起動時間が長い Pod の内の一つを選択して `pod-deletion-cost` の値を変更します。

```diff
$ kubectl edit po sample-deployment-d9489fcc6-q69bk

apiVersion: v1
kind: Pod
metadata:
  annotations:
-    controller.kubernetes.io/pod-deletion-cost: "0"
+    controller.kubernetes.io/pod-deletion-cost: "-10"
```

`pod-deletion-cost` の値は -2147483647 〜 2147483647 の範囲で指定が可能です。


- `pod-deletion-cost` の値を確認すると、1つだけ異なることが分かります。

```
$ kubectl get po -ojson | jq -r '.items[].metadata.annotations'
{
  "controller.kubernetes.io/pod-deletion-cost": "0"
}
{
  "controller.kubernetes.io/pod-deletion-cost": "-10"
}
{
  "controller.kubernetes.io/pod-deletion-cost": "0"
}
```

- この状態で、スケールダウンをして Pod 数を削減します。

```
$ kubectl scale deployment.v1.apps/sample-deployment --replicas=2
deployment.apps/sample-deployment scaled

$ kubectl get po                                                          
NAME                                READY   STATUS    RESTARTS   AGE
sample-deployment-d9489fcc6-7wvvc   1/1     Running   0          79s
sample-deployment-d9489fcc6-twhrr   1/1     Running   0          6m41s
```

従来なら、起動時間の最も短い `sample-deployment-d9489fcc6-7wvvc` が削除されているはずですが残っていることが分かります。

- `pod-deletion-cost` の値を確認します。

```
$ kubectl get po -ojson | jq -r '.items[].metadata.annotations'  
{
  "controller.kubernetes.io/pod-deletion-cost": "0"
}
{
  "controller.kubernetes.io/pod-deletion-cost": "0"
}
```

`pod-deletion-cost` が `-10` を設定した Pod が削除されていることが確認できます。


手動で `pod-deletion-cost` を操作することはあまりやらないと思いますが、 preemptible/spot VM で動作してる Pod に対して自動で `pod-deletion-cost` を付与する仕組みを作ったり、 Pod の起動時間とサービスの影響度の関連性が低い場合において、より柔軟に ReplicaSet をスケールダウンする際の Pod の制御ができるようになったかなと思います。 


</div></details>

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

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

### :wastebasket: Deprecation(非推奨)
- Service の `topologyKeys` フィールドが非推奨になります。 この機能は今後予定されている Topology Aware Subsetting と Service Internal Traffic Policy に置き換えられていきます。 ([#96736](https://github.com/kubernetes/kubernetes/pull/96736), [@andrewsykim](https://github.com/andrewsykim)) [SIG Apps]

  - :pencil: Topology Aware Subsetting の [KEP](https://github.com/kubernetes/enhancements/tree/master/keps/sig-network/2004-topology-aware-subsetting) 
  - :pencil: Service Internal Traffic Policy の [KEP](https://github.com/kubernetes/enhancements/tree/master/keps/sig-network/2086-service-internal-traffic-policy) 
  - :pencil: Topology Aware Hints について詳細を知りたい方は公式サイトの[こちら](https://kubernetes.io/docs/concepts/services-networking/topology-aware-hints/)をご参照ください。

- CronJob の `batch/v2alpha1` とそのクライアントが非推奨になって削除されました。 ([#96987](https://github.com/kubernetes/kubernetes/pull/96987), [@soltysh](https://github.com/soltysh)) [SIG API Machinery, Apps, CLI and Testing]
  - :pencil: CronJobControllerV2 がベータになったためになります。


### :earth_asia: Changes（変更）
- １. PodAffinityTerm は対象の namespace を選択できるように namespaceSelector のラベルを持ちます。
  ２. 新しい CrossNamespacePodAffinity quota scope API は namespaceSelector か namespace フィールド を使用して、 namespace に跨る PodAffinityTerm を用いて namespace を制限します。 ([#98582](https://github.com/kubernetes/kubernetes/pull/98582), [@ahg-g](https://github.com/ahg-g)) [SIG API Machinery, Apps, Auth and Testing]
    - :pencil: Namespace selector について詳細を知りたい方は公式サイトの[こちら](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#namespace-selector)をご参照ください。
    - :pencil: Namespace Selector For Pod Affinity の [KEP](https://github.com/kubernetes/enhancements/tree/master/keps/sig-scheduling/2249-pod-affinity-namespace-selector) 

- Probe-level の terminationGracePeriodSeconds フィールドが追加されました。([#99375](https://github.com/kubernetes/kubernetes/pull/99375), [@ehashman](https://github.com/ehashman)) [SIG API Machinery, Apps, Node and Testing]
    - :pencil: terminationGracePeriodSecond について詳細を知りたい方は公式サイトの[こちら](https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#hook-handler-execution)をご参照ください。
    - :pencil: Liveness Probe Grace Periods の [KEP](https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2238-liveness-probe-grace-period) 


- Added `.spec.completionMode` フィールドが追加されました。このフィールドには `NonIndexed` (default値) か `Indexed` が指定できます。 この機能は alpha のため `IndexedJob` feature gate を有効化した場合にのみ機能します。 ([#98441](https://github.com/kubernetes/kubernetes/pull/98441), [@alculquicondor](https://github.com/alculquicondor)) [SIG Apps and CLI]


- NetworkPolicy に endPort フィールドがサポートされます。([#97058](https://github.com/kubernetes/kubernetes/pull/97058), [@rikatz](https://github.com/rikatz)) [SIG Apps and Network]


- DaemonSets の MaxSurge の rolling update strategy に数値かパーセントを設定してノード上の Pod をアップデートすると新しい Pod が ready になった後に、古い Pod をマーキングしてから削除するようになります。これにより DaemonSets でデプロイされた Pod のアップグレード時のダウンタイムを低減することができます。この機能は alpha 機能のため使用するには DaemonSetUpdateSurge feature gate を有効化する必要があります。 ([#96441](https://github.com/kubernetes/kubernetes/pull/96441), [@smarterclayton](https://github.com/smarterclayton)) [SIG Apps and Testing]
  - :pencil: alpha 機能ですが DaemonSets に MaxSurge が導入されました:tada:
  - :pencil: DaemonSets を使って node-exporter や fluentdをデプロイするケースは多いと思いますが、この機能があると設定変更時に発生するダウンタイムの低減が期待できて嬉しいですね。
  - :pencil: node-local-dns などの場合での利用も期待したいですが、HostPort とMaxSurge の併用はできないためちょっと難しいそうです。DaemonSets が Host のリソースを直接使用することを想定する場合には MaxSurge には注意が必要です。


- Generic ephemeral volumes がベータになりました。([#99643](https://github.com/kubernetes/kubernetes/pull/99643), [@pohly](https://github.com/pohly)) [SIG API Machinery, Apps, Auth, CLI, Node, Storage and Testing]
    - :pencil: Generic ephemeral volumes について詳細を知りたい方は公式サイトの[こちら](https://kubernetes.io/docs/concepts/storage/ephemeral-volumes/#generic-ephemeral-volumes)をご参照ください。


- Hugepages のリクエスト値が page size の整数倍に制限されます。 ([#98515](https://github.com/kubernetes/kubernetes/pull/98515), [@lala123912](https://github.com/lala123912)) [SIG Apps]
    - :pencil: HugePages について詳細を知りたい方は公式サイトの[こちら](https://kubernetes.io/docs/tasks/manage-hugepages/scheduling-hugepages/)をご参照ください。

- Jobs API に新しく `.spec.suspend` フィールドが追加されました。 これにより、 Job に対して suspend と resume が出来るようになります。 ([#98727](https://github.com/kubernetes/kubernetes/pull/98727), [@adtac](https://github.com/adtac)) [SIG API Machinery, Apps, Node, Scheduling and Testing]
    - :pencil: `.spec.suspend` に `true` を設定することで、対象の job を停止することが出来ます。 `false` に設定すると再開されます。デフォルトでは `false` が設定されています。
    - :pencil: Suspend Jobs の [KEP](https://github.com/kubernetes/enhancements/tree/master/keps/sig-apps/2232-suspend-jobs) 
    - :pencil: Suspend Jobs について詳細を知りたい方は公式サイトの[こちら](https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/#suspend)をご参照ください。

- Namespace API オブジェクトが新しく `kubernetes.io/metadata.name` ラベルをもつようになりました。 namespace の  metadata.name フィールドに対して label selector が使用できるようになります。([#96968](https://github.com/kubernetes/kubernetes/pull/96968), [@jayunit100](https://github.com/jayunit100)) [SIG API Machinery, Apps, Cloud Provider, Storage and Testing]


- Service に "InternalTrafficPolicy" フィールドが追加されました。
  cluster internal traffic のルーティングを all endpoints が node-local endpoints のみに指定します。
  "Cluster" ルーティングの場合は Service に対する internal traffic は全ての endpoint が対象になります。
  "Local" ルーティングの婆愛は node-local endpoint のみが対象となり、 traffic を受けられる node-local endpoint ない場合はドロップします。 
  The default value is "Cluster". ([#96600](https://github.com/kubernetes/kubernetes/pull/96600), [@maplain](https://github.com/maplain)) [SIG API Machinery, Apps and Network]


- PodDisruptionBudget API の status に condition を持つようになりました。 ([#98127](https://github.com/kubernetes/kubernetes/pull/98127), [@mortent](https://github.com/mortent)) [SIG API Machinery, Apps, Auth, CLI, Cloud Provider, Cluster Lifecycle and Instrumentation]


- CronJobs が batch/v1 になりました。([#99423](https://github.com/kubernetes/kubernetes/pull/99423), [@soltysh](https://github.com/soltysh)) [SIG API Machinery, Apps, CLI and Testing]

- Immutable Secrets/ConfigMaps が Stable になります。これにより `immutable` のフィールドが設定された Secret と ConfigMap は immutable としてマークされるようになりました。 ([#97615](https://github.com/kubernetes/kubernetes/pull/97615), [@wojtek-t](https://github.com/wojtek-t)) [SIG Apps, Architecture, Node and Testing]

 - :pencil: Immutable Secrets/ConfigMaps が Stable になりました。以下のように `immutable` を使用することで設定できるようになります。
 
    ```diff
    apiVersion: v1
    kind: ConfigMap
    +immutable: true
    ```

- bazel による Kubernetes のビルドのサポートが廃止されました。 ([#99561](https://github.com/kubernetes/kubernetes/pull/99561), [@BenTheElder](https://github.com/BenTheElder)) [SIG API Machinery, Apps, Architecture, Auth, Autoscaling, CLI, Cloud Provider, Cluster Lifecycle, Instrumentation, Network, Node, Release, Scalability, Scheduling, Storage, Testing and Windows]


- Index 付きの Job がサポートされます。 対象の Job には 0 から .spec.completions-1 の index が付与され、 index が付与された全ての Job が成功したときに完了とみなされます。 ([#98812](https://github.com/kubernetes/kubernetes/pull/98812), [@alculquicondor](https://github.com/alculquicondor)) [SIG Apps and CLI]
    - :pencil: Indexed Job の( [KEP](https://github.com/kubernetes/enhancements/tree/master/keps/sig-apps/2214-indexed-job) )


- Endpoints resource に1000以上のアドレスが含まれるときに、Endpoints controller は `endpoints.kubernetes.io/over-capacity` のアノテーションに "warning" を設定します。将来のリリースでは Endpoints controller は制限を超えた Endpoint を削除します。([#99975](https://github.com/kubernetes/kubernetes/pull/99975), [@robscott](https://github.com/robscott)) [SIG Apps and Network]
    - :pencil: EndpointSlices の( [KEP](https://github.com/kubernetes/enhancements/tree/master/keps/sig-network/0752-endpointslices#roll-out-plan) )
    - :pencil: KEP 上の Roll Out Plan を確認すると Endpoints resource に登録できる Endpoint 数が1000になる制限については、Kubernetes 1.22 で実施される予定になっています。


- PodDisruptionBudget API が `policy/v1` になりました。 これに伴う schema の変更はありません。 唯一の変更は policy/v1 の空の selector (`{}`) に書き込まれたときに namespace 内の全ての Pod が対象となったことです。`policy/v1beta1` の動作からは変更ありません。PodDisruptionBudget API の `policy/v1beta1` は非推奨となり、1.25 以降では提供されなくなります。([#99290](https://github.com/kubernetes/kubernetes/pull/99290), [@mortent](https://github.com/mortent)) [SIG API Machinery, Apps, Auth, Autoscaling, CLI, Cloud Provider, Cluster Lifecycle, Instrumentation, Scheduling and Testing]
    - :pencil: PodDisruptionBudget を利用されている方は多いかと思いますが、1.25 までに `policy/v1beta1` から 
`policy/v1` に変更する必要があります。


- Topology Aware Hints がアルファになりました。 `TopologyAwareHints` feature gate を有効化することで使用できるようになります。 ([#99522](https://github.com/kubernetes/kubernetes/pull/99522), [@robscott](https://github.com/robscott)) [SIG API Machinery, Apps, Auth, Instrumentation, Network and Testing]
    - :pencil: Topology Aware Hints について詳細を知りたい方は公式サイトの[こちら](https://kubernetes.io/docs/concepts/services-networking/topology-aware-hints/)をご参照ください。

- APIService resources を利用した server-side apply が修正されました。 ([#98576](https://github.com/kubernetes/kubernetes/pull/98576), [@kevindelgado](https://github.com/kevindelgado)) [SIG API Machinery, Apps and Testing]

- `controller.kubernetes.io/pod-deletion-cost` のアノテーションは同じ ReplicaSet に所属している Pod が削除されるときに、他の Pod とのコスト比較のヒントになります。最も削除コストの低い Pod が最初に削除されます。 この機能はアルファになります。 ([#99163](https://github.com/kubernetes/kubernetes/pull/99163), [@ahg-g](https://github.com/ahg-g))
    - :pencil: Pod deletion cost  について詳細を知りたい方は公式サイトの[こちら](https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/#pod-deletion-cost)をご参照ください。
  - :pencil: ReplicaSet Pod Deletion Cost の [KEP](https://github.com/kubernetes/enhancements/tree/master/keps/sig-apps/2255-pod-cost) 


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

- `storage_operation_duration_seconds` のメトリクスに `migrated` フィールドが追加されます。  ([#99050](https://github.com/kubernetes/kubernetes/pull/99050), [@Jiawei0227](https://github.com/Jiawei0227)) [SIG Apps, Instrumentation and Storage]
    - :pencil: CSI migrate された voleme か識別できるように、メトリクスにフィールドが追加されました。
    - :pencil: CSI migration について詳細を知りたい方は[こちら](https://kubernetes.io/blog/2019/12/09/kubernetes-1-17-feature-csi-migration-beta/#what-is-csi-migration)を参照ください。


- kube-controller-manager　のメトリクスに `ephemeral_volume_controller_create[_failures]_total` が追いかされました。 ([#99115](https://github.com/kubernetes/kubernetes/pull/99115), [@pohly](https://github.com/pohly)) [SIG API Machinery, Apps, Cluster Lifecycle, Instrumentation and Storage]


- 複数のトポロジーによって静的にプロビジョニングされた PV の最適なサイズに基づいて、スケジューラーがノードの優先順位付けを行う `VolumeCapacityPriority` がアルファ機能として提供されます。([#96347](https://github.com/kubernetes/kubernetes/pull/96347), [@cofyc](https://github.com/cofyc)) [SIG Apps, Network, Scheduling, Storage and Testing]
    - :pencil: Prioritization on volume capacity の [KEP](https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1845-prioritization-on-volume-capacity) 
    - :pencil: Kubernetes v1.22 でベータの予定です。

- volume condition を Kubelet がチェックし、該当の Pod の event log に出力できるようになります。([#99284](https://github.com/kubernetes/kubernetes/pull/99284), [@fengzixu](https://github.com/fengzixu)) [SIG Apps, Instrumentation, Node and Storage]
    - :pencil: [external-health-monitor-agent](https://github.com/kubernetes-csi/external-health-monitor)で実現していた機能が、 Kubelet で出来るように修正されたようです。
    - :pencil: Volume Health Monitor の [KEP](https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1432-volume-health-monitor) 


- ReplicaSets をダウンスケールする際に、 ready と creation timestamps の比較をする際に対数スケールを使用するようになります。 ([#99212](https://github.com/kubernetes/kubernetes/pull/99212), [@damemi](https://github.com/damemi)) [SIG Apps and Testing]
    - :pencil: 既存の ReplicaSets はダウングレードする際に最も稼働時間の少ない Pod を削除します。これは新しい Pod の方がよりサービスに影響を与えにくいだろうという想定の元で実装されました。新しいドメインを追加して ReplicaSets をアップグレードをした後にダウンスケールをした場合に、作成時間の短い Pod が特定のドメインに偏ってしまい耐障害性が下がるケースがあるのでアルゴリズムに見直しが入りました。作成時間を基数が2の対数スケールを用いて丸め込んでから、Pod の UUID で比較するようにすることで、同じ程度の作成時間を持つ Pod の中からランダムで選ばれるように修正されています。
    - :pencil: Random Pod Selection on ReplicaSet Downscale の [KEP](https://github.com/kubernetes/enhancements/tree/master/keps/sig-apps/2185-random-pod-select-on-replicaset-downscale) 
    - :pencil: この機能は Kubernetes v1.22 でベータの予定です。

- `IPv6Dualstack` が `Beta` となりデフォルトで有効になります。 新規及び既存のクラスタは、secondary pod と service cidrs cli flags を利用しない限り影響はありません。詳細についてはこちらをご確認ください。 https://github.com/kubernetes/enhancements/tree/master/keps/sig-network/563-dual-stack ([#98969](https://github.com/kubernetes/kubernetes/pull/98969), [@khenidak](https://github.com/khenidak)) [SIG API Machinery, Apps, Cloud Provider, Network and Node]


- kubectl edit quota を利用する際に重複するエラメッセージを回避するようになりました。
- ([#98201](https://github.com/kubernetes/kubernetes/pull/98201), [@pacoxu](https://github.com/pacoxu)) [SIG API Machinery and Apps]



### :hammer_and_wrench: ENHANCEMENT（機能改善）


### :bug: BUGFIX(バグ修正)
- Deployment controller が ReplicaSet 削除する際に、 creation timestamp ではなく revision を参照するようにします。([#97407](https://github.com/kubernetes/kubernetes/pull/97407), [@waynepeking348](https://github.com/waynepeking348)) [SIG Apps]
    - :pencil: Deployment controller が revisionHistoryLimit の制限を超えた ReplicaSet 削除する際に、 creation timestamp が古いものを削除するようになっていましたが、ロールバックやアップグレードが行われた環境では意図しないものが削除される可能性があるため、 creation timestamp でソートする前に、 revision ソートするように変更されました。
 
- EndpointSlice controller が FailedToUpdateEndpointSlices イベントを出力する可能性が低くなりました。 ([#99345](https://github.com/kubernetes/kubernetes/pull/99345), [@robscott](https://github.com/robscott)) [SIG Apps and Network]
    - :pencil: EndpointSlice controller 更新されてサービスと同期する前にキャッシュが更新するまで待つように待機するようになりました。


- EndpointSlice controllers　同じ EndpointSlice を作成する可能性が低くなりました。 ([#100103](https://github.com/kubernetes/kubernetes/pull/100103), [@robscott](https://github.com/robscott)) [SIG Apps and Network]


- EndpointSliceMirroring controller が FailedToUpdateEndpointSlices イベントを出力する可能性が低くなりました。  ([#99756](https://github.com/kubernetes/kubernetes/pull/99756), [@robscott](https://github.com/robscott)) [SIG Apps and Network]


- 少なくとも1つ以上のメトリクスが使用できない時に Horizontal Pod Autoscaler がスケールダウンを実行するバグが修正されました。 ([#99514](https://github.com/kubernetes/kubernetes/pull/99514), [@mikkeloscar](https://github.com/mikkeloscar)) [SIG Apps and Autoscaling]
    - :pencil: HPA のドキュメントでは複数のメトリクスを指定した場合に、1つでもメトリクスが取得できない場合はスケールダウンしないように記載されていましが、実際には 1.16 以降ではスケールダウンしていたので修正されました。
    - :pencil: HPA で複数のメトリクスを指定した場合のスケールダウン時の動作に[公式ドキュメントの記載](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#algorithm-details)は以下になります。
    
    > If multiple metrics are specified in a HorizontalPodAutoscaler, this calculation is done for each metric, and then the largest of the desired replica counts is chosen. If any of these metrics cannot be converted into a desired replica count (e.g. due to an error fetching the metrics from the metrics APIs) and a scale down is suggested by the metrics which can be fetched, scaling is skipped. This means that the HPA is still capable of scaling up if one or more metrics give a desiredReplicas greater than the current value.


- 特定のぶら下がっている attachment から CSI volumes が復旧するように修正されました。 ([#96617](https://github.com/kubernetes/kubernetes/pull/96617), [@yuga711](https://github.com/yuga711)) [SIG Apps and Storage]
    - :pencil: attach/detach controller が途中でクラッシュや再起動をすると、不要なノードにボリュームがアタッチされたままになる可能性があるため、attach/detach controller に不要なボリュームを確認して切り離す処理が追加されました。

- Fixed an issue with garbage collection failing to clean up namespaced children of an object also referenced incorrectly by cluster-scoped children ([#98068](https://github.com/kubernetes/kubernetes/pull/98068), [@liggitt](https://github.com/liggitt)) [SIG API Machinery and Apps]


- 障害が発生したノードに NoExecute taint が正しく付与されないバグが修正されました。 ([#96876](https://github.com/kubernetes/kubernetes/pull/96876), [@howieyuen](https://github.com/howieyuen)) [SIG Apps and Node]


- alwaysPullImages admission controller で新しいイメージがない Pod の更新を無視するように変更されました。([#96668](https://github.com/kubernetes/kubernetes/pull/96668), [@pacoxu](https://github.com/pacoxu)) [SIG Apps, Auth and Node]
    - :pencil: AlwaysPullImages が有効化される前に、デプロイした Pod(e.g. ImagePullPolicy=IfNotPresent) に対して、 image 以外について更新をした際に、 alwaysPullImages admission controller が ImagePullPolicy を変更せずに無視するようになります。
    - :pencil: alwaysPullImages admission controller については詳しく知りたい方を[こちら](https://qiita.com/tkusumi/items/f71882f47e2d87701223#alwayspullimages)について詳しく書いてあります。

- Kube-apiserver: generic ephemeral volume を使用した Pod を作成した後に、 generic ephemeral volume 無効化して該当の Pod を更新した際に、 ephemeral volume 削除されるようになりました。e ([#99446](https://github.com/kubernetes/kubernetes/pull/99446), [@pohly](https://github.com/pohly)) [SIG Apps, Node and Storage]
    - :pencil: generic ephemeral inline volumes の [KEP](https://github.com/kubernetes/enhancements/blob/master/keps/sig-storage/1698-generic-ephemeral-volumes/README.md) 


- single-stack(IPv4 の IPv6 どちらかのみを利用) のクラスタで Headless Service と Selector-Less Service の両方が `ipFamilyPolicy RequireDualStack` を出力し、IPv4 と IPv6 の両方のエントリを`ipFamilies[]` に持ちます。 この変更はアルファであり、手動で作成した Service の Endpoints と EndpointSlices には影響がありません。 ([#99555](https://github.com/kubernetes/kubernetes/pull/99555), [@thockin](https://github.com/thockin)) [SIG Apps and Network]
    - :pencil: `Selector-Less Service` は selector を指定せずに Service を作成し、作成された Endpoint の接続先を手動で変更して Pod から Service を利用する方法になります。詳細について知りたい方は [Kubernetes Best Practices](https://www.oreilly.com/library/view/kubernetes-best-practices/9781492056461/) の Chapter 13 の `Selector-Less Services for Stable IP Addresses` をご参照ください。 

- cluster-scoped children によって誤って参照されている namespaced children を garbage collection で削除できない問題を修正しました。([#98068](https://github.com/kubernetes/kubernetes/pull/98068), [@liggitt](https://github.com/liggitt)) [SIG API Machinery and Apps]


### :microscope: Other (その他の修正)
- v1.17 から GA となり無条件で有効になっている `CSINodeInfo` が feature gate から削除されます。 ([#96561](https://github.com/kubernetes/kubernetes/pull/96561), [@ialidzhikov](https://github.com/ialidzhikov)) [SIG Apps, Auth, Scheduling, Storage and Testing]

- `ServiceNodeExclusion`, `NodeDisruptionExclusion`  `LegacyNodeRoleBehavior`(locked to false) が GA になりました。 control plane node が自動でロードバランサーに追加されないようにするには、 "node.kubernetes.io/exclude-from-external-load-balancers" ラベルを control plane node につける必要があります。 ([#97543](https://github.com/kubernetes/kubernetes/pull/97543), [@pacoxu](https://github.com/pacoxu)) [SIG API Machinery, Apps, Cloud Provider and Network]


- CSINodeIDMaxLength が 128  bytes から 192 bytes に増加しました。 ([#98753](https://github.com/kubernetes/kubernetes/pull/98753), [@Jiawei0227](https://github.com/Jiawei0227)) [SIG Apps and Storage]

## 所感
今回は DaemonSet, Job, ReplicaSet にと新しい機能の追加が多いリリースだったかなと思います。特に DaemonSet の MaxSurge については、この機能がベータになった以降では、デフォルトでつけるのが一般的になる予感がします。Job に関しても Kubernetes 上で様々な Job を扱うユースケースが増えたのか開発が活発になってきたなという印象があるので今後の開発にも期待しています。