In-place Pod Vertical Scaling (KEP-2273 & KEP-1287)

> NOTE: 個人的に今一番期待してるKEPの2021/09/17現在の解説です。まだKubernetesのmasterに入っている機能ではないので、今後いろいろ変更が入ると思います。

in-place upgradeとは、Podを垂直スケールさせるための機能。現行(v1.22.0)のKubernetesでは、Podのリソース割当量の変更にPodの再作成が必要だが、この機能が実現すると再作成なしにリソースを再割当できる。

この機能は、以下の2つのKEPから成り立っている。

-   [KEP-2273: Kubelet CRI APIの変更](https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2273-kubelet-container-resources-cri-api-changes)
-   [KEP-1287: Kubernetes APIの変更](https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/1287-in-place-update-pod-resources)

実装は現在(2021/09/16)レビュー中。スケジュール上は、次の1.23にAlpha(Feature Gate)リリース予定と書かれている。(v1.22では延期された)
[In-place Pod Vertical Scaling feature by vinaykul · Pull Request #102884 · kubernetes/kubernetes](https://github.com/kubernetes/kubernetes/pull/102884)

## 正常系Resizeの流れ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26683/336245a8-2bf1-80cd-0c0a-b790f2c2f908.png)

2つのKEPを合わせるとこのような流れになる。主に関わってくるコンポーネントはAPI Server, Scheduler, Kubelet, Runtimeの4つ。(LimitRangerやResourceQuotaにも影響があるがここでは省略した。)

## KEP 2273: kubelet container resources CRI API changes

CRI APIのCPUとMemoryリソース設定の変更の提案。これにより `UpdateContainerResource` と `ContainerStatus` APIの2つに変更が入る。前者はコンテナリソースの割当量を変更するAPIで、後者はKubeletがcontainerのコンテナの状態を取得するためのAPI。


### CRI APIの変更内容

`UpdateContainerResource` のパラメータは既存の `runtimeapi.LinuxContainerResources` から **Windows** にも対応した `runtimeapi.ContainerResource` に変更される。ContainerStatusにはリソース割当量を保持するためのContainerResourceが追加される。


## KEP 1287: in-place update pod resources

この提案が実現すると、Podのresource request & limitsの変更時に、コンテナの再起動が不要になる。これにより、Statefulやバッチのワークロードや、再起動コストが大きい場合でも適切なリソース設定が可能になる。


### APIの変更

-   **Spec**:
    -   `.spec.containers[i].resizePolicy` ([]ContainerResizePolicy): 各リソース変更時のポリシーを設定する
        -   `RestartNotRequred` (default): リソース変更時に再起動しない
        -   `Restart`: リソース変更時に再起動する (`-xmxN` フラグを持つJavaアプリケーションなどのリソース変更に再起動を要するものを想定している)
-   **Status**:
    -   `.status.containerStatuses[i].resourcesAllocated` (ResourceList): コンテナに対するNodeのリソース割当状況
    -   `.status.containerStatuses[i].recources` (\*ResourceRequirements): Resource requests/limits状況
    -   `.status.resize` (PodResizeStatus): コンテナのリソース割当状況
        -   `Proposed`: リソースのリサイズがリクエストされ、Nodeによる評価待ちの状態
        -   `InProgress`: Nodeにリサイズが受理され、処理が開始した状態
        -   `Deferred`: 一時的にリサイズができず、再試行している状態
        -   `Infeasible`: リソース的にリサイズができず、また再評価もできない状態
-   Subresource:
    -   `/resize`: beta以降でresize subresourceが実装される予定だが詳細は未定


### Schedulerへの影響

Pod作成時のScheduling時の挙動は変わらず、PodのResource Requestが使われる。ただし、Nodeのリソース割当量計算するときにはpending resizeのPodも対象になる。また、Podの消費リソースはstatusのresourcesAllocatedの値が使われる。


### 参考

初期のProposals:

-   [Vertical Scaling Proposal - Google Docs](https://docs.google.com/document/d/1Q_Aq4khL2Kjbvmwzok8jukF2HQl31LyM65jK93yfTII/edit#heading=h.qb2t0ak4gvki)
-   [KubernetesPodVerticalScaling - Google Docs](https://docs.google.com/document/d/18K-bl1EVsmJ04xeRq9o_vfY2GDgek6B6wmLjXw-kos4/edit)


## 現実装の検証 (2021/09/16)

```yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
featureGates:
  InPlacePodVerticalScaling: true
```

```bash
$ gh pr checkout 102884
$ kind build node-image --image kindest/node:inplace-20210916
$ kind create cluster --image kindest/node:inplace-20210916 --config cluster.yaml
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.1", GitCommit:"632ed300f2c34f6d6d15ca4cef3d3c7073412212", GitTreeState:"clean", BuildDate:"2021-08-19T15:38:26Z", GoVersion:"go1.16.6", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"23+", GitVersion:"v1.23.0-alpha.1.33+231427f6c9dca9", GitCommit:"231427f6c9dca9a7df0e48bb34b016245b03bca4", GitTreeState:"clean", BuildDate:"2021-09-16T07:22:49Z", GoVersion:"go1.16.7", Compiler:"gc", Platform:"linux/amd64"}
```

```diff
--- pod-api-org.yaml        2021-09-17 10:58:38.000000000 +0900
+++ pod-api-new.yaml        2021-09-17 10:58:44.000000000 +0900
...
@@ -150,2 +151,2 @@
 status:
   conditions:
...
     lastState: {}
     name: kube-apiserver
     ready: true
+    resources:
+      requests:
+        memory: "0"
+    resourcesAllocated:
+      cpu: 250m
+      memory: "0"
     restartCount: 0
     started: true
     state:
       running:
```