LabHub

ブログ

CPU、メモリ、NUMA、HugePages:KubeVirtはリソースモデルをどう合わせるか

한국어English日本語

はじめに

VMのリソースモデルはコンテナよりも要求が厳しい。ユーザーはゲストに4 vCPUと16 GiBのメモリを割り当てたいと思うが、実際にはlauncher Pod、QEMUオーバーヘッド、エミュレータスレッド、hugepages、NUMAローカリティまで一緒に考慮する必要がある。KubeVirtはこのギャップを埋めるために、ゲストリソースモデルとPodリソースモデルを同時に管理している。

本記事では、staging/src/kubevirt.io/api/core/v1/schema.gopkg/virt-controller/services/template.gopkg/virt-launcher/virtwrap/manager.goを中心に、このリソース変換レイヤーを見ていく。

ゲストリソースとPodリソースはなぜ異なるのか

コンテナの場合、プロセスが使うリソースがそのままPodリソースになることが多い。しかしVMは異なる。

これらの要因により、launcher Podはゲストメモリよりも多くのメモリをリクエストする必要がある場合がある。

つまり、KubeVirtがこれを処理しなければ、スケジューラはVMを過度に楽観的に配置してしまう。

APIスキーマがすでにこの問題を示している

schema.goを見ると、CPUとメモリ関連のフィールドがかなり豊富であることがわかる。

これはKubeVirtが「CPUをいくつかください」程度の単純な抽象化に留まらず、実行パフォーマンスと配置の安定性までAPIで扱おうとするシステムであることを意味する。

launcher Podのリソースは誰が計算するのか

この役割は主にpkg/virt-controller/services/template.goが担う。ここでCalculateMemoryOverheadが呼び出され、launcher Podに必要な実際のリソースrequestとlimitが生成される。

重要なポイントは以下の通り。

つまり、VMI specがそのままPod specにはならない。間にリソース補正段階がある。

メモリオーバーヘッドはなぜ重要なのか

schema.goにはMemoryOverheadの説明があり、template.goはメモリオーバーヘッドをアノテーションやstatusでも扱う。マイグレーション状態にはターゲットメモリオーバーヘッドも別途ある。

これは非常に重要である。例えば、ゲストが8 GiBしか見えないのに、launcher Podも8 GiBだけリクエストすると:

つまり、KubeVirtは「ゲストメモリ」と「launcherエンベロープメモリ」を分離して見ている。

CPUトポロジーがゲストの数値と異なる場合があるのはなぜか

KubeVirtのCPUTopologyはソケット、コア、スレッドを表現する。しかし、Kubernetesスケジューラが見るのは結局launcher PodのCPU requestとlimitである。

ここで重要なケースがdedicated CPUである。dedicated CPUをリクエストすると:

manager.goUpdateVCPUsを見ると、dedicated CPUの場合にdomain specとpod cpusetを読み取ってPinVcpuFlagsPinEmulatorを呼び出している。つまりこれは単純なクォータの問題ではなく、pCPU配置の問題である。

NUMAはなぜAPIに含まれているのか

schema.goNUMANUMAGuestMappingPassthroughの説明は非常に意味深い。KubeVirtはゲストNUMAトポロジーをホストCPUピニングと互換性があるようにモデル化しようとしている。

これが重要な理由はパフォーマンスである。

つまり、KubeVirtはNUMAを「高度なオプション」ではなく、高パフォーマンスVM運用に必須のトポロジー制約として扱っている。

HugePagesで何が変わるのか

HugePagesを有効にすると、メモリは通常のページとは異なるリソースクラスとして扱われる。schema.gotemplate.goはhugepagesのページサイズをPodリソースにも反映する。

これは次のことを意味する:

つまり、hugepagesは「パフォーマンスのチェックボックス」ではなく、スケジューリングとカーネルメモリモデル全体を変える選択である。

マイグレーションとリソースモデルはどう繋がるのか

マイグレーション時、ターゲットノードはソースと同じゲストを収容する必要がある。しかし、dedicated CPU、NUMA、hugepages、メモリオーバーヘッドがあるとターゲット条件はかなり厳しくなる。

実際にマイグレーションstatusには:

などの情報が含まれる。これはマイグレーションが単に「空いているノードならどこでも」という作業ではなく、同じパフォーマンス特性を維持できるノードへ移す作業であることを示している。

よくある誤解

誤解1:ゲストが8 GiBならPodも8 GiBで十分

いいえ。仮想化オーバーヘッドがあり、バインディングプラグインや付加機能も追加メモリを消費する可能性がある。

誤解2:CPUリクエストさえ合えばdedicated CPUも問題ない

いいえ。ピニング、トポロジー、cpusetが合っている必要がある。

誤解3:NUMAとhugepagesはパフォーマンスチューニング用のオプションに過ぎない

いいえ。スケジューリング条件とマイグレーションの可否まで変わる。

運用者がまず見るべきこと

まとめ

KubeVirtはVMIのCPUとメモリリクエストをそのままPod requestとして投げるわけではない。代わりにメモリオーバーヘッドを加算し、dedicated CPUとNUMA、hugepagesを反映してlauncher Podとゲストハードウェアモデルを同時に合わせる。この構造のおかげで、KubernetesスケジューラはVMをある程度正しく配置でき、ゲストはより予測可能なパフォーマンス特性を得られる。

次の記事では、このリソースモデルを実際に可能にするホストプリミティブ、すなわち/dev/kvm、namespace、cgroup、TAP、netlinkといったカーネル技術を見ていく。

コメント

まだコメントはありません。

ログインするとコメントできます