Kubernetes 新功能优先获取: InPlacePodVerticalScaling 功能开关

自从2019年6月18日(星期二)在东京举行的Kubernetes Meetup上作为引人注目的演讲之后,这个功能已经过去了3年,但终于感觉到它可能会被合并了。
我原以为它会进入Kubernetes 1.26版本,但遗憾的是它似乎要等到1.27版本才能实现…

我希望在本文中介绍最终版本的规格、用法和机制。

预计截至2022年12月1日尚未合并,也尚未发布为Alpha版本。目前正在按计划进行1.27版本的Alpha追加工作。

请注意:这是作者根据 KEP 和 Feature PR 进行独自解释后的内容,可能存在错误。如果发现错误,请留下评论,谢谢!

InPlacePodVerticalScaling 是什么意思?

Pod またはそのコンテナを再起動・再作成することなく、Pod リソースの Request を変更する機能です。
これは現在(1.25)の Kubernetes では Pod のリソースを動的に変更する事はできず、リソースを変更したい場合は Pod を再作成する必要がありました。

请提供用例思路

    • ステートフルやバッチワークロードなどの Pod の再作成が高コストになる Pod

VerticalPodAutoscaler などでPod の再作成を伴わずにスケールしたいケース

使い方イメージ

例としてすでに Pod を作成済みで、その Pod の pod.spec.resources.request.cpu を 1 から 2 に変更したいケースとします。

[User] リサイズリクエストを投げる

apiserver の Pod オブジェクトに対して以下のような PUT or PATCH リクエストを送ることで変更をリクエストできます。

$ kubectl patch pod ${POD_NAME} -p --type='json' -p='[{"op": "replace", "path": "/spec/containers/0/resources/requests/cpu", "value": "2"}]'

beta では権限を細かく分けるために resize サブリソースが作られる計画がありますが現時点では実装はありません。

正常にスケールアップされる場合はこのまま待っていれば自動的に適応されていきますが、エラーが発生するケースなどこのスケールアップの状況を確認できるステータスが追加されましたので、この後の処理される流れに合わせてそれらを紹介していきます。

【API服务器】接收调整大小请求并记录资源的接受状态。

リクエストを送ると正常に apiserver に受け付けられた場合は以下のように pod.status に記録されます。

当收到请求时,apiserver会将pod.status.resize[cpu]设置为“ Proposed”。

$ kubectl get pod ${POD_NAME} -o jsonpath='{.status.resize[cpu]}'
Proposed

[kubelet] リサイズリクエストを受け付ける

次に kubelet は 自身に割り当てられた Pod を Watch していますが、resize のリクエストを受け取ったらケースに合わせて以下の挙動をします。

Node の Available なリソース量を超えてリクエストされた場合

確保できるリソースがないため、pod.status.resize[cpu] に Infeasible として記録し、リサイズが失敗したことを通知します。

这个时候似乎不会重新尝试。

何らかの理由で Pod のリサイズのリクエストが受け付けられない状態の場合

一時的にリサイズ操作ができないため、pod.status.resize[cpu] に Deferred として記録し、リトライすることを通知します。

事前のチェックでリサイズが受理された場合

pod.status.containerStatuses[i].resourcesAllocated にその値を適応し、受け付けたことを pod.status.resize[cpu] に InProgress として記録します。

$ kubectl get pod ${POD_NAME} -o jsonpath='{.status.containerStatuses[0].resourceAllocated}'
{"cpu": "2"}
$ kubectl get pod ${POD_NAME} -o jsonpath='{.status.resize[cpu]}'
InProgress

ResourcesAllocated は新しく追加されたフィールドで、Nodeリソースのリソースの割当リクエスト状況を記録します。

[kubelet] 受け付けたリサイズのリクエストをコンテナに反映する

一旦接收到调整大小请求后,我们会调用 UpdateContainerResources CRI API 来向运行时(如 containerd)发出所需的扩缩容请求。

無事リサイズできたら pod.status.containerStatuses[0].resources.requests[cpu] に実際に確保した値を設定し、status.resize[cpu] から値を削除します。

$ kubectl get pod ${POD_NAME} -o jsonpath='{.status.containerStatuses[0].resources.requests[cpu]}'
2
$ kubectl get pod ${POD_NAME} -o jsonpath='{.status.resize[cpu]}'
nil

これでリサイズが完了します。

主要的变更点 de

我认为大致的动作已经可以想象出来了,所以我打算简单地查看每个组件实施上的变更点。

变更公关:https://github.com/kubernetes/kubernetes/pull/102884

Kuberentes API

追加された主なフィールドは以下のとおりです。

pod.spec.containers[].resources[].resizePolicy

resourceName: cpu, memory など

policy: RestartNotRequired(default), RestartRequired が指定可能

リサイズのときに再起動するかどうかを指定する

pod.status.containerStatuses[].resourcesAllocated

ResourceList 形式で kubelet がリソースのリクエストを受け付けたリソース量が記録される

pod.status.containerStatuses[].resources

ResourceRequirements 形式で kubelet が確保したリソース量が記録される

pod.status.resize

リサイズの進行状況が記録される

Proposed, InProgress, Deferred, Infeasible

詳細はこちらを参照してください。

API服务器

    • resizePolicy のバリデーション

リソースの変更時に pod.status.resize を自動リセット

spec.containers.resource.requests が変更されたときに Proposed を設定する

日程安排。

ResourcesAllocated を使用してリソース割り当てを計算します

cheduler はあまりコードを追ったことがないのでこれで置き換わっているかは未確認です

kubelet – kubelet是Kubernetes集群中的一个核心组件。

以下是关于 https://github.com/kubernetes/kubernetes/pull/102884/commits/f7844496573c2615e8ebc64037942490cd2e1266 的提交,但由于提交内容太多,在 Github 上无法完全显示…

我主要做以下工作:

pod.status.resize および pod.status.resourcesAllocated をサイズ変更時に更新する

https://github.com/kubernetes/kubernetes/blob/3388ce5528fb4fe658ef879f39ef58d758475f51/pkg/kubelet/kubelet.go#L2571 で実施しています

ノードに新しい Pod を配置する際に、pod.status.containerStatuses[i].resources をコンテナに設定する

https://github.com/kubernetes/kubernetes/blob/3388ce5528fb4fe658ef879f39ef58d758475f51/pkg/kubelet/kuberuntime/kuberuntime_manager.go#L735

リサイズの判定と実行を行う

https://github.com/kubernetes/kubernetes/blob/3388ce5528fb4fe658ef879f39ef58d758475f51/pkg/kubelet/kuberuntime/kuberuntime_manager.go#L525
https://github.com/kubernetes/kubernetes/blob/3388ce5528fb4fe658ef879f39ef58d758475f51/pkg/kubelet/kuberuntime/kuberuntime_manager.go#L637

Linux と Windows の両方で機能するように UpdateContainerResources CRI API を変更

https://github.com/kubernetes/kubernetes/blob/3388ce5528fb4fe658ef879f39ef58d758475f51/pkg/kubelet/cri/remote/remote_runtime.go#L434

请各位注意

    • 競合を避けるためにすべてのコンポーネントは、Pod が使用するリソースを計算するときに、Pod の Status.ContainerStatuses[i].ResourcesAllocated を使用してください

scheduler は対応しましたが他のコンポーネントはまだ対応できていないと思うのでこれから対応を進めていく必要がありそうです

メトリクス辺りもどの値を利用するか考えていく必要がありそうに思っています

アプリケーションがページを保持している場合、メモリ制限の引き下げが常にすぐに有効になるとは限りません

ページの開放は強制的は行わずに解放を促しつつ開放されるのを InProgress の状態にして待つということだと思われます

未来的计划

资料: https://github.com/kubernetes/enhancements/tree/313ad8b59c80819659e1fbf0f165230f633f2b22/keps/sig-node/1287-in-place-update-pod-resources#future-enhancements

请提供以下内容的中文翻译:

未来增强功能

    • kubelet (またはscheduler) は、ノードから優先度の低い Pod を削除して、リサイズの余地を作ります。kubelet によるプリエンプションはより簡単で、待ち時間が短くなる可能性があります。

 

    • Pod スコープでの resizePolicy の設定を許可し、(一部の) コンテナで独自に設定されていない場合にデフォルトとして機能します

 

    • resizePolicy を拡張して、リソースの増減を個別に制御します

メモリを下げるときのみ再起動するなどの細かい設定ということらしい

ノード情報 API を拡張して、ノードの CPU Manager ポリシーを報告し、Static CPU Manager ポリシーを持つノードの統合 CPU サイズ変更の検証を有効にします
Job、Deployment などのテンプレートリソースの更新を実行中の Pod に伝達します
ephemeral storage のリサイズ対応
resouces.limit への対応
Pod スコープのリソース対応 #1592

まとめ

現時点 (2022/12/1) での InPlacePodVerticalScaling の仕様をまとめました。この後大きく変わることはないとは思いますが、まだ alpha でもないため変更がある可能性はありますのでご注意ください。
筆者は逐次変更はウォッチしていなかったので長引いた背景などは把握しきれていませんが、Implementation History を見ると構想から約4年間もかかっており、大変だったのかと思います。当初の予定よりもスケジューラが関わる部分が減り、思っていたよりシンプルな仕様に落ち着いたように感じました。
久々に根幹部分に関わる大きな変更だと思うので多数のバグなども出そうですが、昔よりは安全に追加していくための仕組みやルールが整いつつあると思うので無事リリースできることを期待しています。

参考资料

    • KEP: https://github.com/kubernetes/enhancements/tree/313ad8b59c80819659e1fbf0f165230f633f2b22/keps/sig-node/1287-in-place-update-pod-resources

enhancement issue: https://github.com/kubernetes/enhancements/issues/1287

PR: https://github.com/kubernetes/kubernetes/pull/102884

bannerAds