そもそもKubernetesというのは、巨大なシステムだ。そして、その巨大なシステムを管理すること、特にMLトレーニングファーム、超低遅延トレードシステム、あるいは文字通り呼吸しているようなデータベースといった、パフォーマンスがクリティカルなワークロードの話になると、常に繊細なダンスを強いられてきた。予測可能なパフォーマンスが欲しい。そのためには、メインイベントのために排他的で、NUMAアライメントされたリソースを切り出す必要がある。しかし、Podはもはや孤独な単一コンテナではない。それらはエコシステムなのだ。ロギング、モニタリング、サービスメッシュ、データインジェストのためのサイドカー――あらゆるものが揃っている。
歴史的に、プライマリーアプリケーションのためにそれらの純粋で排他的なリソースを確保するには、すべてを捧げる必要があった。Pod内のすべてのコンテナが、専用の整数CPUスライスを割り当てられていた。無駄か?Absolutely。特にCPUをほとんど消費しない小さなメトリクスエクスポーターにとっては。もしその厳格な割り当てをスキップすれば、Podの貴重なGuaranteed Quality of Service (QoS) クラスを放棄することになり、それと同時に、一貫したトップクラスのパフォーマンスの希望も失うことになった。要求の厳しいアプリケーションを実行する者にとっては、まさにソフィーの選択だった。
新たな希望:Podレベルマネージャーの登場
しかし、Kubernetes v1.36は、Pod-Level Resource Managersのアルファ版導入によって、状況を動かしている。これは単なる微調整ではない。kubeletのTopology Manager, CPU Manager, Memory Managerの機能を拡張する、根本的なアーキテクチャシフトなのだ。ビッグニュースは?これらが.spec.resourcesでPodレベルのリソース仕様をサポートするようになったことだ。我々は、厳格なコンテナごとの割り当てモデルから、明らかにPod中心のモデルへと移行している。
これらの新しいフィーチャーゲート(PodLevelResourceManagersとPodLevelResources)を有効にすることで、kubeletはハイブリッドリソース割り当てモデルをオーケストレーションできるようになる。これにより、要求の少ないコンパニオンにCPUコアを浪費することなく、スターパフォーマーのためにNUMAアライメントと排他的リソース割り当てを実現できる。柔軟性と効率性が、ついに融合したのだ。
実世界のシナリオ:ゴムがNUMAに当たる場所
この新しいアプローチの美しさは、実用的なユースケースで輝く。それはTopology Managerのスコープ設定に大きく依存する。レイテンシに敏感なデータベースPodを考えてみよう。メインコンテナ、ローカルメトリクスエクスポーター、バックアップエージェントサイドカーがすべて含まれている。
Topology Managerをpodスコープで設定した場合、kubeletはPod全体の |リソース予算に基づいて単一のNUMAアライメントを実行する。クリティカルなデータベースコンテナは、その特定のNUMAノードから排他的なCPUおよびメモリのスライスを掴む。残りは?それはpod共有プールを形成する。ここにメトリクスエクスポーターとバックアップエージェントが配置される。それらは互いにリソースを共有するが、決定的なのは、それらがデータベース専用スライスやノードの他の部分から分離されていることだ。これは大きい。補助コンテナを同じNUMAノードに配置しながら、専用コアを無駄にすることがないのだ。
podTopology Managerスコープで設定した場合、kubeletはPod全体の |予算に基づいて単一のNUMAアライメントを実行する。データベースコンテナは、そのNUMAノードから排他的なCPUおよびメモリのスライスを取得する。Podの |予算からの残りのリソースが、新しいpod共有プールを形成する。
YAMLでの表示は次のようになるだろう:
apiVersion: v1
kind: Pod
metadata:
name: tightly-coupled-database
spec:
# Podレベルのリソースが、全体的な |予算とNUMAアライメントサイズを確立する。
resources:
requests:
cpu: "8"
memory: "16Gi"
limits:
cpu: "8"
memory: "16Gi"
initContainers:
- name: metrics-exporter
image: metrics-exporter:v1
restartPolicy: Always
- name: backup-agent
image: backup-agent:v1
restartPolicy: Always
containers:
- name: database
image: database:v1
# このGuaranteedコンテナは、Podの |予算から排他的な6CPUスライスを取得する。
# 残りの2CPUと4Giメモリは、サイドカーのためのpod共有プールを形成する。
resources:
requests:
cpu: "6"
memory: "12Gi"
limits:
cpu: "6"
memory: "12Gi"
あるいは、インフラストラクチャサイドカーを持つMLワークロードを考えてみよう。ここでは、おそらくcontainer Topology Managerスコープを重視するだろう。kubeletは各コンテナを個別に評価する。最大パフォーマンスを求めるMLトレーニングコンテナは、排他的でNUMAアライメントされたCPUとメモリを受け取る。サービスメッシュサイドカーは?特別な扱いは必要ない。ノード全体の共有プールで問題なく動作する。 |リソース消費の総量は依然としてPod全体の |制限によって |制限されるが、排他的でNUMAアライメントされたリソースは、本当に必要な場所にのみ、賢く適用されている。
apiVersion: v1
kind: Pod
metadata:
name: ml-workload
spec:
# Podレベルのリソースが、全体的な |予算の制約を確立する。
resources:
requests:
cpu: "4"
memory: "8Gi"
limits:
cpu: "4"
memory: "8Gi"
initContainers:
- name: service-mesh-sidecar
image: service-mesh:v1
restartPolicy: Always
containers:
- name: ml-training
image: ml-training:v1
# 'container'スコープの下では、このGuaranteedコンテナは排他的な
# NUMAアライメントされたリソースを取得し、サイドカーはノードの共有プールで実行される。
resources:
requests:
cpu: "3"
memory: "6Gi"
limits:
cpu: "3"
memory: "6Gi"
CPUクォータと分離の技術
分離が鍵であり、これらの混合ワークロードでは異なって処理される。排他的なCPUスライスを取得するコンテナの場合、CPU CFSクォータ強制はコンテナレベルで無効になる。これは、カーネルのCompletely Fair Scheduler (CFS) によって通常課されるスロットリングなしで動作することを意味し、無制限にバーストおよびパフォーマンスを発揮できることを保証する。
排他的なCPUスライスを取得しないコンテナは、Podレベルの共有プールまたはノード全体共有プールのいずれかに属する共有プールの一部となる。これらのコンテナにはCFSクォータ強制が有効になる。それらはCFSスケジューリングポリシーに従ってリソースを共有する。これは、暴走プロセスが必須プロセスを飢えさせないように設計された微妙なシステムでありながら、ハイリスクなアプリケーションに専用レーンを提供している。
根本的なシフト:コンテナからPodへ
Podレベルのリソース管理へのこの移行は、単なる最適化以上のものである。これはKubernetes内の哲学的なシフトだ。長年、スケジューリングとリソース割り当ての基本単位はコンテナだった。この新しい機能は、現代のアプリケーションがしばしばPod内で分散されており、それらの分散コンポーネントを統一されたユニットとして管理することが、パフォーマンスと効率性のために重要であることを認識している。それは、Podを独立したプロセスの集まりとしてではなく、単一の、しかし複雑なアプリケーションインスタンスとして扱うことなのだ。
これは、高性能アプリケーションの設計とデプロイ方法に魅力的な可能性を開く。個々のコンテナのリソースニーズを綿密に計算し、QoSへの影響と格闘する代わりに、Pod全体の |リソースフットプリントを定義し、その |予算内でインテリジェントに委任できるようになる。運用が合理化され、さらに重要なことに、パフォーマンスのペナルティなしで、よりタイトな |リソース利用が可能になる。これはFinOpsチームと、それらの捉えどころのないパフォーマンスメトリクスを追いかけるエンジニアにとっての勝利だ。
開発者とオペレーターにとっての意味
開発者にとっては、複雑なPodのリソース要件を指定するための、より直感的な方法を意味する。パフォーマンスがクリティカルなコンポーネントとそのサポートキャストを明確に区別できる。オペレーターにとっては、ノードの利用効率の向上と、潜在的なコスト削減につながる。なぜなら、メインアプリケーションのQoSを維持するためだけに、サイドカーのためにリソースを過剰にプロビジョニングする必要がなくなるからだ。これは、Kubernetesを最も要求の厳しいワークロードにとって、より実行可能なプラットフォームにするための重要な一歩だ。
もちろん、これはアルファ版だ。荒削りな部分、変更、そして当然ながら、成熟するにつれてさらなる掘り下げた質問が予想される。しかし、方向性は明確だ。Kubernetesは、基盤となるハードウェアの有限なリソースをどのように割り当てるかについて、より賢くなっている。そして、それは注目に値する進歩だ。