<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Kueue on lo0 — Tech Blog</title><link>https://blog.lo0.es/en/tags/kueue/</link><description>Recent content in Kueue on lo0 — Tech Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Tue, 16 Jun 2026 13:00:00 +0200</lastBuildDate><atom:link href="https://blog.lo0.es/en/tags/kueue/index.xml" rel="self" type="application/rss+xml"/><item><title>Volcano and Kueue: gang scheduling, queues and GPU quotas for distributed workloads on Kubernetes</title><link>https://blog.lo0.es/en/posts/volcano-kueue-gang-scheduling-gpu-quotas-kubernetes/</link><pubDate>Tue, 16 Jun 2026 13:00:00 +0200</pubDate><guid>https://blog.lo0.es/en/posts/volcano-kueue-gang-scheduling-gpu-quotas-kubernetes/</guid><description>&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>&lt;strong>Volcano&lt;/strong> (volcano-sh, CNCF incubating) is a &lt;strong>complete batch scheduler&lt;/strong> that replaces or complements the kube-scheduler: it places pods with gang semantics (all-or-nothing via &lt;code>PodGroup&lt;/code>/&lt;code>minMember&lt;/code>), manages queues with priority, DRF fair-share and preemption between queues, and understands network and NUMA topology.&lt;/p>
&lt;p>&lt;strong>Kueue&lt;/strong> (kubernetes-sigs/kueue) is a &lt;strong>queue and quota manager at the Job level&lt;/strong>: it does NOT place pods (it delegates to the kube-scheduler or to Volcano), but it decides when a workload can be admitted according to available quota (&lt;code>ClusterQueue&lt;/code>/&lt;code>LocalQueue&lt;/code>/&lt;code>Cohort&lt;/code>), with fair sharing, borrowing between teams and preemption by priority. It natively integrates Job, JobSet, RayJob, all the Kubeflow operators and more.&lt;/p>
&lt;p>The winning combination in production for multi-tenant GPU workloads is: &lt;strong>Kueue for quota and queues + Volcano (or the sig-scheduler coscheduling plugin) for the job&amp;rsquo;s gang&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="the-analogy">The analogy&lt;/h2>
&lt;p>Imagine a club with limited capacity and a dance floor inside.&lt;/p>
&lt;p>&lt;strong>Kueue is the doorman and the booking manager&lt;/strong>: it checks whether the team&amp;rsquo;s quota (its reserved capacity) allows the group in, applies the fair waiting list, borrows capacity from other teams if any are idle, and takes the space back when the owner needs it. But the doorman does not decide where each person sits inside the venue.&lt;/p>
&lt;p>&lt;strong>Volcano is the head waiter&lt;/strong>: once the group has permission to come in, he decides which tables they sit at, makes sure the whole group sits down at once or nobody comes in (gang), picks the tables according to topology (who needs to talk to whom) and throws out lower-priority groups to make room if necessary.&lt;/p>
&lt;p>Without a doorman (Kueue), the head waiter does not know how many groups he can take at once or whether a team is exceeding its capacity. Without a head waiter (Volcano), the doorman lets the group in but its members scatter across the available tables on their own, and the party of 8 that needs to sit together never manages it.&lt;/p>
&lt;hr>
&lt;h2 id="the-problem-neither-solves-by-default-the-kube-scheduler">The problem neither solves by default: the kube-scheduler&lt;/h2>
&lt;p>Kubernetes&amp;rsquo; &lt;code>kube-scheduler&lt;/code> is a pod scheduler, not a job scheduler. It assigns pods one by one to the most suitable node according to available resources and affinity constraints. For a distributed training workload that needs, say, 8 pods with 4 GPUs each (32 GPUs in total across 8 nodes of 4×H100), the standard scheduler does the following:&lt;/p>
&lt;ol>
&lt;li>It looks for a node with 4 available GPUs. It finds one. It schedules pod 1.&lt;/li>
&lt;li>It looks for another node with 4 GPUs. It finds one. It schedules pod 2.&lt;/li>
&lt;li>It carries on until it reaches pod 6 and it turns out there are no longer any nodes with 4 free GPUs: the cluster has exactly 32 GPUs and other workloads are using some of them.&lt;/li>
&lt;li>Pods 1–5 are &lt;code>Running&lt;/code>. Pods 6–8 are &lt;code>Pending&lt;/code>.&lt;/li>
&lt;li>Pods 1–5 can do nothing without the others: a distributed PyTorch job needs all the workers to start before the &lt;code>torchrun&lt;/code> process can begin. &lt;strong>It waits with the resources occupied. Deadlock.&lt;/strong>&lt;/li>
&lt;/ol>
&lt;p>This is not a bug, it is the design: the kube-scheduler has no concept of &amp;ldquo;schedule this group of pods only if you can schedule all of them&amp;rdquo;. As a result:&lt;/p>
&lt;ul>
&lt;li>The resources of pods 1–5 are locked up without producing work.&lt;/li>
&lt;li>Other jobs that could run with the partial resources also wait.&lt;/li>
&lt;li>If several jobs are in this situation, the cluster can end up with fragmented resources, no job running and everyone in circular deadlock.&lt;/li>
&lt;/ul>
&lt;p>On top of that, the kube-scheduler has no notion of:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Queues&lt;/strong> per team or project with relative priority.&lt;/li>
&lt;li>&lt;strong>Quotas&lt;/strong> of resources per team with the ability to borrow from idle teams.&lt;/li>
&lt;li>&lt;strong>Fair-share&lt;/strong>: if team A has spent weeks using 80 % of the cluster, it should wait longer than team B, which has spent weeks idle.&lt;/li>
&lt;li>&lt;strong>Inter-queue preemption&lt;/strong>: evicting a lower-priority job from another team to make room for this team&amp;rsquo;s urgent job.&lt;/li>
&lt;/ul>
&lt;p>Solving any of these problems requires adding a layer on top of the scheduler. Volcano and Kueue are the two dominant OSS solutions in 2026, with complementary architectural approaches.&lt;/p>
&lt;hr>
&lt;h2 id="volcano-the-batch-scheduler">Volcano: the batch scheduler&lt;/h2>
&lt;h3 id="what-it-is-and-what-it-replaces">What it is and what it replaces&lt;/h3>
&lt;p>Volcano (volcano-sh) is a &lt;strong>Kubernetes-native batch scheduler&lt;/strong> accepted by the CNCF as its first and only official container batch scheduling project (&lt;a href="https://volcano.sh/en/docs/">volcano.sh/en/docs&lt;/a>). At version v1.15.x as of June 2026, with CNCF incubating status.&lt;/p>
&lt;p>Volcano &lt;strong>is not an addon to the kube-scheduler&lt;/strong>: it is an alternative scheduler (or a complementary one, depending on the configuration) that places pods. It is installed as a deployment, and jobs that want to benefit from its capabilities must use the &lt;code>volcano&lt;/code> scheduler class in their pod spec (&lt;code>schedulerName: volcano&lt;/code>) or use the &lt;code>VolcanoJob&lt;/code> CRD.&lt;/p>
&lt;p>Volcano&amp;rsquo;s central value proposition is that it treats groups of pods as atomic scheduling units, not individual pods. That is what makes it possible to solve the deadlock described above.&lt;/p>
&lt;h3 id="gang-scheduling-via-podgroup">Gang scheduling via PodGroup&lt;/h3>
&lt;p>Volcano&amp;rsquo;s central mechanism is the &lt;code>PodGroup&lt;/code>: a CRD that groups a job&amp;rsquo;s pods and defines how many must be schedulable before Volcano starts any of them.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># PodGroup for a distributed PyTorch training job: 8 workers, minimum 8&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">scheduling.volcano.sh/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">PodGroup&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">pytorch-train-pg&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ml-training&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">minMember: 8 # all-or-nothing&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">if there is no room for 8, none starts&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">minResources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;32&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 8 pods × 4 GPUs = 32 GPUs minimum in the cluster&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">queue&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">team-datos &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># which Volcano queue this job is assigned to&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">priorityClassName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">high-priority&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The &lt;code>minMember&lt;/code> parameter implements &lt;strong>all-or-nothing&lt;/strong> semantics: Volcano only assigns nodes to the group&amp;rsquo;s pods when it can assign at least &lt;code>minMember&lt;/code> pods simultaneously. If the cluster does not have capacity for 8 GPU pods at this moment, no pod in the group moves out of &lt;code>Pending&lt;/code>. Nothing is blocked, nothing is fragmented.&lt;/p>
&lt;p>&lt;code>minMember&lt;/code> can be lower than the job&amp;rsquo;s total pod count: this allows &lt;strong>elastic gang scheduling&lt;/strong>, where the job can start with fewer workers and scale up, useful for jobs that tolerate a reduced worker count.&lt;/p>
&lt;p>For a job&amp;rsquo;s pods to be associated with the PodGroup, they carry the annotation:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Pod spec of the PyTorch worker&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">annotations&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">scheduling.volcano.sh/pod-group-name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">pytorch-train-pg&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">schedulerName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">volcano&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">containers&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">trainer&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">pytorch/pytorch:2.5-cuda12.4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">limits&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;4&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="queue-queues-with-quotas-and-priority">Queue: queues with quotas and priority&lt;/h3>
&lt;p>Volcano introduces the &lt;code>Queue&lt;/code> CRD to manage multiple tenants with independent quotas:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">scheduling.volcano.sh/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Queue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">team-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">weight&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">4&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># relative weight for fair-share between queues (proportion plugin)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">capability&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># absolute ceiling of resources this queue can use&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;16&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">guarantee&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># guaranteed resource, never lent to other queues&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resource&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;8&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">reclaimable&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># if true, others can reclaim the resources it lends when they need them&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">scheduling.volcano.sh/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Queue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">team-ia&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">weight&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">capability&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;8&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">guarantee&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resource&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;4&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">reclaimable&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The &lt;code>weight&lt;/code> field feeds the &lt;strong>proportion plugin&lt;/strong>: queues compete for the cluster&amp;rsquo;s available resources in proportion to their weight. A cluster with 32 GPUs and two queues of weight 4 and 2 splits the GPUs in a 4:2 ratio (≈21 and 11 GPUs respectively) when both are saturated.&lt;/p>
&lt;h3 id="scheduler-plugins-drf-binpack-topology-aware">Scheduler plugins: DRF, binpack, topology-aware&lt;/h3>
&lt;p>Volcano implements its scheduling logic as a pipeline of actions and plugins:&lt;/p>
&lt;p>&lt;strong>Actions&lt;/strong> (what the scheduler does in each cycle):&lt;/p>
&lt;ul>
&lt;li>&lt;code>enqueue&lt;/code>: moves jobs from the waiting queue to schedulable when quota is available.&lt;/li>
&lt;li>&lt;code>allocate&lt;/code>: assigns nodes to schedulable pods.&lt;/li>
&lt;li>&lt;code>preempt&lt;/code>: evicts lower-priority pods to make room for higher-priority ones within the same queue.&lt;/li>
&lt;li>&lt;code>reclaim&lt;/code>: evicts pods from other queues that are using more than their &lt;code>guarantee&lt;/code> to return resources to the owner.&lt;/li>
&lt;li>&lt;code>backfill&lt;/code>: fills idle resources with best-effort jobs that do not interfere with the rest.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Plugins&lt;/strong> relevant to GPU workloads:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Plugin&lt;/th>
&lt;th>What it does&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>gang&lt;/code>&lt;/td>
&lt;td>Implements the PodGroup&amp;rsquo;s all-or-nothing semantics&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>proportion&lt;/code>&lt;/td>
&lt;td>Fair-share by queue weight (proportional quota)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>capacity&lt;/code>&lt;/td>
&lt;td>Quotas with &lt;code>guarantee&lt;/code>/&lt;code>capability&lt;/code> and reclaim; a more expressive alternative to proportion&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>drf&lt;/code>&lt;/td>
&lt;td>Dominant Resource Fairness: multi-dimensional fair-share (CPU, memory, GPU)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>binpack&lt;/code>&lt;/td>
&lt;td>Packs pods onto the fullest nodes; reduces GPU fragmentation&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>priority&lt;/code>&lt;/td>
&lt;td>Orders jobs by priority within the same queue&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>nodeorder&lt;/code>&lt;/td>
&lt;td>Node scoring according to multiple criteria (affinity, resources, spread)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>task-topology&lt;/code>&lt;/td>
&lt;td>Affinity between pods of the same job (inter-GPU communication)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>numa-aware&lt;/code>&lt;/td>
&lt;td>NUMA affinity: aligns pods with the node&amp;rsquo;s NUMA socket to reduce memory latency&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="network-and-numa-topology-v111">Network and NUMA topology (v1.11+)&lt;/h3>
&lt;p>Volcano v1.11 (February 2025) introduced &lt;strong>Network Topology Aware Scheduling&lt;/strong> as a first-class feature (&lt;a href="https://www.cncf.io/blog/2025/03/05/volcano-v1-11-released-a-new-era-of-cloud-native-scheduling-for-ai-and-big-data/">CNCF blog, March 2025&lt;/a>). Distributed training jobs in a datacenter with a hierarchical network structure (spine/leaf, blocks of nodes with NVSwitch) can declare topology constraints:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># VolcanoJob with a network topology constraint&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">batch.volcano.sh/v1alpha1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Job&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">llm-pretrain&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ml-training&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">minAvailable&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">8&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">schedulerName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">volcano&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">queue&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">team-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">plugins&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ssh&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">env&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">svc&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">networkTopology&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">mode: hard # hard&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">the job MUST satisfy the constraint&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">highestTierAllowed&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">block &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># pods cannot span beyond a network &amp;#34;block&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">replicas&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">8&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">worker&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">template&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">containers&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">trainer&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">nvcr.io/nvidia/pytorch:25.01-py3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">limits&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;4&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The &lt;code>highestTierAllowed: block&lt;/code> semantics instruct Volcano to place the 8 pods within the same network block (for example, all the nodes under the same access switch), minimising the inter-block traffic that degrades a distributed all-reduce.&lt;/p>
&lt;p>NUMA awareness works in a similar way: with the &lt;code>numa-aware&lt;/code> plugin, pods request a NUMA policy (&lt;code>single-numa-node&lt;/code>, &lt;code>restricted&lt;/code>, &lt;code>best-effort&lt;/code>) and Volcano selects nodes where the requested CPU, memory and GPU resources are in the same NUMA domain, avoiding the remote memory access overhead (NUMA-crossing) that can degrade training throughput by 15-30 % on multi-socket nodes.&lt;/p>
&lt;h3 id="gpu-virtualization-in-v111">GPU virtualization in v1.11+&lt;/h3>
&lt;p>Volcano v1.11 also introduces support for &lt;strong>dynamic MIG and vCUDA&lt;/strong>: instead of declaring &lt;code>nvidia.com/gpu: 1&lt;/code> for a whole GPU, workloads can declare &lt;code>nvidia.com/gpu-memory: 20Gi&lt;/code> and Volcano (with the corresponding device plugin) dynamically provisions the MIG instance or the vCUDA partition. This is [project marketing with no independent benchmarks published as of June 2026], but the feature&amp;rsquo;s architecture is documented in the code.&lt;/p>
&lt;h3 id="what-it-replaces-or-adds-to-the-default-scheduler">What it replaces or adds to the default scheduler&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Capability&lt;/th>
&lt;th>kube-scheduler&lt;/th>
&lt;th>Volcano&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Placing pods on nodes&lt;/td>
&lt;td>Yes&lt;/td>
&lt;td>Yes (it replaces it for workloads marked with &lt;code>schedulerName: volcano&lt;/code>)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Gang scheduling (all-or-nothing)&lt;/td>
&lt;td>No&lt;/td>
&lt;td>Yes (PodGroup + minMember)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Queues with priority&lt;/td>
&lt;td>No&lt;/td>
&lt;td>Yes (Queue CRD)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Inter-queue fair-share&lt;/td>
&lt;td>No&lt;/td>
&lt;td>Yes (DRF, proportion, capacity plugins)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Inter-queue preemption&lt;/td>
&lt;td>No&lt;/td>
&lt;td>Yes (reclaim action)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Topology-aware (NUMA, network)&lt;/td>
&lt;td>Partial (node affinity)&lt;/td>
&lt;td>Yes (dedicated plugins)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Elastic gang (minMember &amp;lt; total)&lt;/td>
&lt;td>No&lt;/td>
&lt;td>Yes&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Best-effort backfill&lt;/td>
&lt;td>No&lt;/td>
&lt;td>Yes&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Framework integrations&lt;/td>
&lt;td>Partial&lt;/td>
&lt;td>MPI, PyTorch, Ray, TensorFlow, Spark, Flink, Horovod&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="kueue-the-queue-and-quota-manager">Kueue: the queue and quota manager&lt;/h2>
&lt;h3 id="what-it-is-and-what-it-does-not-do">What it is and what it does NOT do&lt;/h3>
&lt;p>Kueue (kubernetes-sigs/kueue) is a &lt;strong>Kubernetes-native system that manages quotas and how jobs consume them&lt;/strong> (&lt;a href="https://kueue.sigs.k8s.io/docs/overview/">kueue.sigs.k8s.io&lt;/a>). Kueue decides when a job must wait, when it should be admitted (pods can be created) and when it should be evicted (active pods must be deleted).&lt;/p>
&lt;p>Kueue&amp;rsquo;s central design principle is explicit in its documentation: &lt;strong>avoid duplicating mature functionality of Kubernetes components&lt;/strong>. Autoscaling is the cluster-autoscaler&amp;rsquo;s responsibility. Pod-to-node scheduling is the kube-scheduler&amp;rsquo;s responsibility. Job lifecycle management is the kube-controller-manager&amp;rsquo;s responsibility. Kueue replaces none of them: it sits on top as a layer of &lt;strong>admission control and quota management at the Job level&lt;/strong>.&lt;/p>
&lt;p>This is the fundamental distinction: &lt;strong>Kueue does not place pods on nodes&lt;/strong>. When Kueue admits a workload, it simply allows the corresponding job controller to create the pods, and those pods are scheduled by the kube-scheduler (or by Volcano, if it is configured as the scheduler).&lt;/p>
&lt;h3 id="the-four-core-objects">The four core objects&lt;/h3>
&lt;p>&lt;strong>ResourceFlavor&lt;/strong>: maps abstract resources to concrete groups of physical nodes.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kueue.x-k8s.io/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ResourceFlavor&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">h100-sxm&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nodeLabels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">accelerator&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">h100-sxm&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">node-pool&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">gpu-training&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tolerations&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">key&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;nvidia.com/gpu&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">operator&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Exists&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">effect&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;NoSchedule&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>ClusterQueue&lt;/strong>: defines the resource quota per flavor for a tenant. A cluster-scoped object.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kueue.x-k8s.io/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ClusterQueue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">cq-team-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cohort&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">llm-platform &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># cohort it belongs to (can lend/borrow)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">queueingStrategy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">BestEffortFIFO&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespaceSelector&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">matchLabels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kubernetes.io/metadata.name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ns-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resourceGroups&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">coveredResources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;nvidia.com/gpu&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;cpu&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;memory&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">flavors&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">h100-sxm&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;nvidia.com/gpu&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nominalQuota&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">16&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># GPUs guaranteed for this team&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">borrowingLimit&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">8&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># can take up to 8 additional GPUs from the cohort&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">lendingLimit&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">8&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># can lend up to 8 of its 16 nominal GPUs&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;cpu&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nominalQuota&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;128&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;memory&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nominalQuota&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;512Gi&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">preemption&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">reclaimWithinCohort&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">LowerPriority &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># reclaims lent quota by evicting lower-priority jobs&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">borrowWithinCohort&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">policy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">LowerPriority&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">withinClusterQueue&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">LowerPriority&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>LocalQueue&lt;/strong>: the namespace-scoped entry point for a team&amp;rsquo;s workloads. Jobs point to their LocalQueue; Kueue maps them to the corresponding ClusterQueue.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kueue.x-k8s.io/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">LocalQueue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">lq-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ns-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">clusterQueue&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">cq-team-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Cohort&lt;/strong>: groups ClusterQueues that can lend quota to each other. It is not a standalone CRD; it is declared as a field in the ClusterQueue (&lt;code>spec.cohort: name&lt;/code>). Kueue aggregates the available quota of all the ClusterQueues in the cohort and lets any of them borrow what the others are not using, respecting the &lt;code>borrowingLimit&lt;/code> and &lt;code>lendingLimit&lt;/code>.&lt;/p>
&lt;h3 id="fair-sharing-and-preemption">Fair sharing and preemption&lt;/h3>
&lt;p>Kueue implements &lt;strong>Fair Sharing&lt;/strong> as the ordering policy for the queue of pending workloads (&lt;a href="https://kueue.sigs.k8s.io/docs/concepts/fair_sharing/">kueue.sigs.k8s.io/docs/concepts/fair_sharing&lt;/a>): when several workloads compete for quota in the cohort, those belonging to ClusterQueues with higher accumulated historical usage have lower admission priority. This implements equitable sharing without permanently blocking any team.&lt;/p>
&lt;p>Preemption in Kueue operates along two dimensions:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>reclaimWithinCohort&lt;/code>&lt;/strong>: the ClusterQueue that lends quota reclaims it by evicting workloads that are using it on loan, according to a priority policy.&lt;/li>
&lt;li>&lt;strong>&lt;code>withinClusterQueue&lt;/code>&lt;/strong>: within the same ClusterQueue, lower-priority workloads are evicted to make way for higher-priority workloads from the same team.&lt;/li>
&lt;/ul>
&lt;h3 id="gang-semantics-in-kueue-all-or-nothing-with-ready-pods">Gang semantics in Kueue: all-or-nothing with ready Pods&lt;/h3>
&lt;p>Kueue provides gang admission at the Job level: it admits the complete workload only when all the necessary quota is available. If a RayJob needs 8 GPUs (1 head + 7 workers), Kueue does not admit the workload until 8 GPUs are available in the ClusterQueue (or borrowed from the cohort). &lt;code>waitForPodsReady&lt;/code> with a timeout adds a second guarantee: if the created pods do not become &lt;code>Ready&lt;/code> within the configured time, Kueue re-queues the workload and releases the quota (&lt;a href="https://kueue.sigs.k8s.io/docs/tasks/manage/setup_wait_for_pods_ready/">kueue.sigs.k8s.io/docs/tasks/manage/setup_wait_for_pods_ready&lt;/a>).&lt;/p>
&lt;p>This is &lt;strong>gang semantics at the admission level&lt;/strong>, not at the pod placement level. It guarantees that the quota is available before creating the pods, but it does not guarantee that the kube-scheduler can place them all on concrete nodes at the same time. For that second guarantee you need Volcano or the coscheduling plugin.&lt;/p>
&lt;h3 id="topology-aware-scheduling-tas">Topology-Aware Scheduling (TAS)&lt;/h3>
&lt;p>Kueue v0.10+ introduces &lt;strong>Topology-Aware Scheduling&lt;/strong> (&lt;a href="https://kueue.sigs.k8s.io/docs/concepts/topology_aware_scheduling/">kueue.sigs.k8s.io/docs/concepts/topology_aware_scheduling&lt;/a>): it allows node topologies (blocks, subblocks, hosts) to be defined and workloads to request co-location levels. Kueue only admits the workload when it can satisfy the topological constraint, and it adds node selectors and taints at admission time so that the scheduler places the pods in the right topology.&lt;/p>
&lt;p>TAS is configured with the &lt;code>Topology&lt;/code> CRD:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kueue.x-k8s.io/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Topology&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">datacenter-topology&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">levels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">nodeLabel&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;topology.kubernetes.io/block&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">nodeLabel&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;topology.kubernetes.io/rack&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">nodeLabel&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;kubernetes.io/hostname&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And the ResourceFlavor references the topology:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kueue.x-k8s.io/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ResourceFlavor&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">h100-sxm&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nodeLabels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">accelerator&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">h100-sxm&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">topologyName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">datacenter-topology&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="framework-integrations">Framework integrations&lt;/h3>
&lt;p>Kueue has built-in integration (no additional code) for the following workload types, activated with an annotation on the job:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">labels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kueue.x-k8s.io/queue-name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">lq-datos &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># points to the team&amp;#39;s LocalQueue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The supported workload types include: &lt;code>batch/Job&lt;/code>, &lt;code>JobSet&lt;/code>, &lt;code>RayJob&lt;/code>, &lt;code>RayCluster&lt;/code>, &lt;code>PytorchJob&lt;/code>, &lt;code>TFJob&lt;/code>, &lt;code>MPIJob&lt;/code>, &lt;code>JAXJob&lt;/code>, &lt;code>PaddleJob&lt;/code>, &lt;code>XGBoostJob&lt;/code>, &lt;code>TrainJob&lt;/code>, &lt;code>AppWrapper&lt;/code>, &lt;code>LeaderWorkerSet&lt;/code>, &lt;code>Deployment&lt;/code>, &lt;code>StatefulSet&lt;/code>, and plain &lt;code>Pod&lt;/code>/&lt;code>PodGroup&lt;/code>.&lt;/p>
&lt;p>For LLM workloads, the directly relevant cases:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>RayJob&lt;/strong> (distributed training with Ray Train): Kueue admits the RayJob when there is quota for the whole Ray cluster (head + workers). Documented at &lt;a href="https://docs.ray.io/en/latest/cluster/kubernetes/examples/rayjob-kueue-gang-scheduling.html">docs.ray.io&lt;/a>.&lt;/li>
&lt;li>&lt;strong>PyTorchJob&lt;/strong> (Kubeflow Training Operator): gang admission of the complete job.&lt;/li>
&lt;li>&lt;strong>JobSet&lt;/strong>: for coordinated multi-replica jobs (LWS, multi-step pipelines).&lt;/li>
&lt;li>&lt;strong>Deployment/StatefulSet&lt;/strong>: for continuous inference, allowing inference GPU quota to be managed the same way as training quota.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="the-key-distinction-volcano-places-kueue-admits">The key distinction: Volcano places, Kueue admits&lt;/h2>
&lt;p>This table sums up the fundamental architectural difference:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Dimension&lt;/th>
&lt;th>Volcano&lt;/th>
&lt;th>Kueue&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Main role&lt;/strong>&lt;/td>
&lt;td>Scheduler (places pods on nodes)&lt;/td>
&lt;td>Admission controller + quota manager (decides when to create pods)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Gang scheduling&lt;/strong>&lt;/td>
&lt;td>Yes, at the placement level (PodGroup/minMember)&lt;/td>
&lt;td>Yes, at the admission level (all-or-nothing on quota)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Multi-tenant quotas&lt;/strong>&lt;/td>
&lt;td>Yes (Queue with capability/guarantee)&lt;/td>
&lt;td>Yes (ClusterQueue with nominalQuota/borrowingLimit)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Cohorts / borrowing&lt;/strong>&lt;/td>
&lt;td>Partial (reclaimable between queues)&lt;/td>
&lt;td>Yes (Cohort with explicit lendingLimit/borrowingLimit)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Fair sharing&lt;/strong>&lt;/td>
&lt;td>Yes (DRF plugin)&lt;/td>
&lt;td>Yes (Fair Sharing based on historical usage)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Preemption&lt;/strong>&lt;/td>
&lt;td>Yes (preempt + reclaim actions)&lt;/td>
&lt;td>Yes (reclaimWithinCohort, withinClusterQueue)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Topology/NUMA&lt;/strong>&lt;/td>
&lt;td>Yes (dedicated plugins, network topology, NUMA-aware)&lt;/td>
&lt;td>Yes (TAS, topology levels in ResourceFlavor)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Framework integrations&lt;/strong>&lt;/td>
&lt;td>Volcano Job (MPI, PyTorch, Ray, TF, Spark, Flink)&lt;/td>
&lt;td>Native: Job, JobSet, RayJob, Kubeflow, LWS, AppWrapper, Deployment, StatefulSet&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Who places the pods&lt;/strong>&lt;/td>
&lt;td>Volcano&lt;/td>
&lt;td>kube-scheduler (or Volcano if configured)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Installation footprint&lt;/strong>&lt;/td>
&lt;td>Medium-high (its own scheduler, CRDs, webhook, metrics)&lt;/td>
&lt;td>Light (controller, CRDs, webhook; does not replace the scheduler)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Maturity / status&lt;/strong>&lt;/td>
&lt;td>CNCF incubating; v1.15 (June 2026); production at Huawei, Baidu, DiDi&lt;/td>
&lt;td>kubernetes-sigs; API v1beta2; production at Google GKE, Red Hat OpenShift 4.20, Runway ML&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Adoption curve&lt;/strong>&lt;/td>
&lt;td>Steeper (requires changing schedulerName or using the VolcanoJob CRD)&lt;/td>
&lt;td>Gentler (adds labels to existing jobs; does not change the scheduler)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="how-they-coexist-the-production-pattern">How they coexist: the production pattern&lt;/h3>
&lt;p>In production, Kueue and Volcano are &lt;strong>complementary, not mutually exclusive&lt;/strong>. The most common pattern in 2026 for multi-tenant GPU clusters is:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Kueue&lt;/strong> manages the global quota: which team can use how many GPUs, how much it can borrow, when a job goes into a queue versus being admitted.&lt;/li>
&lt;li>&lt;strong>Volcano&lt;/strong> does the gang scheduling at the pod level: once Kueue admits the job (the quota is available), Volcano places the pods, making sure they are all placed simultaneously on compatible nodes.&lt;/li>
&lt;/ol>
&lt;p>The integration is configured by specifying &lt;code>schedulerName: volcano&lt;/code> in the pod specs of the workloads managed by Kueue. Kueue sees the Job/RayJob/PyTorchJob and manages its quota; when it admits it, the pods are created and Volcano places them with gang semantics. Volcano&amp;rsquo;s PodGroups are created automatically by the Volcano Job controller or by the Kubeflow Training Operator itself when it detects that the scheduler is Volcano.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># PyTorchJob managed by Kueue (quota) + Volcano (gang placement)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kubeflow.org/v1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">PyTorchJob&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">llm-finetune-70b&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ns-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">labels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kueue.x-k8s.io/queue-name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">lq-datos &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Kueue manages the quota&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">annotations&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">scheduling.volcano.sh/queue-name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">team-datos &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Volcano uses its own Queue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pytorchReplicaSpecs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Master&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">replicas&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">restartPolicy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">OnFailure&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">template&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">schedulerName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">volcano &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Volcano does the placement&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">containers&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">pytorch&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">nvcr.io/nvidia/pytorch:25.01-py3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">limits&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;4&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Worker&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">replicas&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">7&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">restartPolicy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">OnFailure&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">template&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">schedulerName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">volcano&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">containers&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">pytorch&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">nvcr.io/nvidia/pytorch:25.01-py3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">limits&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;4&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="the-third-way-the-sig-scheduler-coscheduling-plugin">The third way: the sig-scheduler coscheduling plugin&lt;/h3>
&lt;p>If you do not want to deploy a complete alternative scheduler but you need gang scheduling, there is the &lt;strong>coscheduling plugin&lt;/strong> from &lt;a href="https://github.com/kubernetes-sigs/scheduler-plugins/blob/master/pkg/coscheduling/README.md">kubernetes-sigs/scheduler-plugins&lt;/a>. This plugin extends the kube-scheduler with a PodGroup mechanism similar to Volcano&amp;rsquo;s, implemented as a scheduling framework plugin (permit plugin). The advantage is that it does not replace the scheduler; the disadvantage is that it has less functionality than Volcano (no DRF, no Queue/fair-share, no network topology). It is the right option for simple clusters that only need gang and do not want Volcano&amp;rsquo;s operational complexity. Kueue can also work alongside this plugin.&lt;/p>
&lt;hr>
&lt;h2 id="complete-yaml-examples">Complete YAML examples&lt;/h2>
&lt;h3 id="volcano-queue--podgroup--volcanojob">Volcano: Queue + PodGroup + VolcanoJob&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 1. Queue for the data team (16 nominal GPUs, ceiling at 24)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">scheduling.volcano.sh/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Queue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">team-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">weight&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">capability&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;24&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;192&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">memory&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;768Gi&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">guarantee&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resource&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;16&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">reclaimable&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># 2. Queue for the AI team (8 nominal GPUs, ceiling at 16)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">scheduling.volcano.sh/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Queue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">team-ia&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">weight&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">capability&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;16&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;64&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">memory&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;256Gi&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">guarantee&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resource&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;8&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">reclaimable&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># 3. PodGroup: 70B fine-tuning job, 8 workers × 4 GPUs = 32 GPUs&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">scheduling.volcano.sh/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">PodGroup&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">finetune-70b-pg&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ns-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">minMember&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">8&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">minResources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;32&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">queue&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">team-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">priorityClassName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">training-high&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># 4. VolcanoJob (wrapper that Volcano understands natively)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">batch.volcano.sh/v1alpha1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Job&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">finetune-70b&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ns-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">minAvailable&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">8&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">schedulerName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">volcano&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">queue&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">team-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">priorityClassName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">training-high&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">plugins&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">env&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">svc&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">policies&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">event&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">PodEvicted&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">action&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">RestartJob&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">replicas&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">8&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">worker&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">policies&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">event&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">TaskCompleted&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">action&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">CompleteJob&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">template&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">annotations&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">scheduling.volcano.sh/pod-group-name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">finetune-70b-pg&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">schedulerName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">volcano&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">containers&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">trainer&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">nvcr.io/nvidia/pytorch:25.01-py3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;torchrun&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;--nproc_per_node=4&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;--nnodes=8&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;--node_rank=$(RANK)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;--master_addr=$(MASTER_ADDR)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;--master_port=23456&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;train.py&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">env&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">NCCL_DEBUG&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">value&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;INFO&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">requests&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;4&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;16&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">memory&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;64Gi&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">limits&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;4&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;16&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">memory&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;64Gi&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">restartPolicy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Never&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="kueue-resourceflavor--clusterqueue--localqueue--annotated-job">Kueue: ResourceFlavor + ClusterQueue + LocalQueue + annotated Job&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 1. ResourceFlavor: nodes with H100 SXM&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kueue.x-k8s.io/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ResourceFlavor&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">h100-sxm&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nodeLabels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">accelerator&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">h100-sxm&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tolerations&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">key&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;nvidia.com/gpu&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">operator&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Exists&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">effect&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;NoSchedule&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># 2. ClusterQueue for the data team: 16 nominal GPUs, can borrow 8&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kueue.x-k8s.io/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ClusterQueue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">cq-team-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cohort&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">llm-platform&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">queueingStrategy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">BestEffortFIFO&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespaceSelector&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">matchLabels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kubernetes.io/metadata.name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ns-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resourceGroups&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">coveredResources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;nvidia.com/gpu&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;cpu&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;memory&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">flavors&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">h100-sxm&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;nvidia.com/gpu&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nominalQuota&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">16&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">borrowingLimit&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">8&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">lendingLimit&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">8&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;cpu&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nominalQuota&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;128&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;memory&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nominalQuota&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;512Gi&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">preemption&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">reclaimWithinCohort&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">LowerPriority&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">borrowWithinCohort&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">policy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">LowerPriority&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">withinClusterQueue&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">LowerPriority&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># 3. ClusterQueue for the AI team: 8 nominal GPUs&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kueue.x-k8s.io/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ClusterQueue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">cq-team-ia&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cohort&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">llm-platform&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">queueingStrategy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">BestEffortFIFO&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespaceSelector&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">matchLabels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kubernetes.io/metadata.name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ns-ia&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resourceGroups&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">coveredResources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;nvidia.com/gpu&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;cpu&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;memory&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">flavors&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">h100-sxm&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;nvidia.com/gpu&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nominalQuota&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">8&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">borrowingLimit&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">8&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">lendingLimit&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;cpu&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nominalQuota&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;64&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;memory&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nominalQuota&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;256Gi&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">preemption&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">reclaimWithinCohort&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">LowerPriority&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">withinClusterQueue&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">LowerPriority&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># 4. LocalQueue in the data team&amp;#39;s namespace&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kueue.x-k8s.io/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">LocalQueue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">lq-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ns-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">clusterQueue&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">cq-team-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># 5. LocalQueue in the AI team&amp;#39;s namespace&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kueue.x-k8s.io/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">LocalQueue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">lq-ia&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ns-ia&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">clusterQueue&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">cq-team-ia&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># 6. Batch inference RayJob managed by Kueue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ray.io/v1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">RayJob&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">batch-eval-llama70b&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ns-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">labels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kueue.x-k8s.io/queue-name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">lq-datos &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Kueue manages the admission&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">entrypoint&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;python batch_eval.py --model /models/llama-70b&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">rayClusterSpec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">headGroupSpec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">rayStartParams&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">num-gpus&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;4&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">template&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">containers&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ray-head&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">rayproject/ray-ml:2.40.0-gpu&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">limits&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;4&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;16&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">memory&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;64Gi&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">workerGroupSpecs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">replicas&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">minReplicas: 3 # gang&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Kueue does not admit if there is no quota for 3 workers&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">maxReplicas&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">groupName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">gpu-worker&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">rayStartParams&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">num-gpus&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;4&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">template&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">containers&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ray-worker&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">rayproject/ray-ml:2.40.0-gpu&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">limits&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;4&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;16&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">memory&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;64Gi&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="kueue--volcano-together-pytorchjob-with-kueue-quota-and-volcano-gang-placement">Kueue + Volcano together: PyTorchJob with Kueue quota and Volcano gang placement&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># PyTorchJob: Kueue controls the quota, Volcano does the gang placement&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kubeflow.org/v1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">PyTorchJob&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">distributed-finetune&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ns-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">labels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kueue.x-k8s.io/queue-name: lq-datos # Kueue&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">quota and admission&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">annotations&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># Volcano automatically creates the PodGroup when schedulerName=volcano&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">scheduling.volcano.sh/queue-name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">team-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pytorchReplicaSpecs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Master&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">replicas&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">restartPolicy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">OnFailure&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">template&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">schedulerName: volcano # Volcano&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">gang placement&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">containers&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">pytorch&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">nvcr.io/nvidia/pytorch:25.01-py3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">limits&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;4&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;16&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">memory&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;64Gi&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Worker&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">replicas&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">7&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">restartPolicy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">OnFailure&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">template&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">schedulerName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">volcano&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">containers&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">pytorch&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">nvcr.io/nvidia/pytorch:25.01-py3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">limits&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;4&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;16&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">memory&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;64Gi&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="for-llm-workloads-training-fine-tuning-and-batch-inference">For LLM workloads: training, fine-tuning and batch inference&lt;/h2>
&lt;h3 id="distributed-multi-gpu-training-and-fine-tuning">Distributed multi-GPU training and fine-tuning&lt;/h3>
&lt;p>Gang scheduling is &lt;strong>essential&lt;/strong> for any distributed training job that uses NCCL all-reduce (PyTorch DDP, FSDP, DeepSpeed ZeRO). If a single worker in the group does not start, the &lt;code>torchrun&lt;/code> coordinator waits indefinitely; with the standard kube-scheduler this scenario happens every time the cluster is under contention.&lt;/p>
&lt;p>In a generic cluster of 4 nodes of 4×H100 SXM (16 GPUs in total), a fine-tuning job for a 70B model typically requires 8 GPUs in tensor-parallel 8 (TP=8) or 16 GPUs in TP=4 plus data-parallel 4. With Volcano, the &lt;code>PodGroup&lt;/code> with &lt;code>minMember: 8&lt;/code> guarantees that either the 8 pods are placed at once or none blocks resources. With Kueue on top, the quota guarantees that the team does not exceed its 16 nominal GPUs and that other teams with available quota are not blocked by a waiting job.&lt;/p>
&lt;p>The cross-link with &lt;a href="https://blog.lo0.es/en/posts/capacity-planning-on-premise-llm-inference/">inference capacity planning&lt;/a> is direct: the model&amp;rsquo;s VRAM budget (weights plus KV-cache) determines the minimum TP and therefore the PodGroup&amp;rsquo;s &lt;code>minMember&lt;/code>.&lt;/p>
&lt;h3 id="batch-inference-and-evaluations-evals">Batch inference and evaluations (evals)&lt;/h3>
&lt;p>Batch inference jobs, generating responses for an evaluation dataset, processing embeddings in bulk, offline re-ranking, are naturally parallel workloads that do not necessarily require strict gang scheduling (each request is independent), but they do benefit from quota and fair-share.&lt;/p>
&lt;p>For these workloads, &lt;strong>Kueue alone is enough&lt;/strong>: a &lt;code>batch/Job&lt;/code> with multiple independent pods is managed with the ClusterQueue&amp;rsquo;s quota with no need for Volcano. If several teams are submitting evaluation jobs simultaneously, Kueue orders the admission by fair-share and priority, and with cohort borrowing the jobs of teams with free quota do not have to wait for the quota of busy teams.&lt;/p>
&lt;p>The chargeback of these workloads connects directly with what is described in &lt;a href="https://blog.lo0.es/en/posts/gpu-chargeback-showback-multi-tenancy/">GPU chargeback and showback&lt;/a>: the ClusterQueue&amp;rsquo;s &lt;code>nominalQuota&lt;/code> is the expression of the GPU budget in Kubernetes, and OpenCost can attribute the cost per namespace or label for the monthly report.&lt;/p>
&lt;h3 id="multi-tenant-gpu-quota-and-chargeback">Multi-tenant GPU quota and chargeback&lt;/h3>
&lt;p>The alignment between Kueue and the chargeback system is direct:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>FinOps concept&lt;/th>
&lt;th>Kueue mechanism&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Guaranteed GPU budget&lt;/td>
&lt;td>&lt;code>nominalQuota&lt;/code> per ClusterQueue&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Maximum spending ceiling&lt;/td>
&lt;td>&lt;code>nominalQuota + borrowingLimit&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Lending idle capacity&lt;/td>
&lt;td>Cohort + &lt;code>lendingLimit&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Reclaiming your own quota&lt;/td>
&lt;td>&lt;code>preemption.reclaimWithinCohort: LowerPriority&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Fair-share between teams&lt;/td>
&lt;td>Fair Sharing policy in the ClusterQueue&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Chargeback of the loan&lt;/td>
&lt;td>borrowed GPU hours × cost per GPU-hour (OpenCost)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>For the utilisation dimension as a FinOps lever, see &lt;a href="https://blog.lo0.es/en/posts/gpu-idle-cost-not-on-any-invoice/">GPU utilisation as a FinOps lever&lt;/a>: Kueue and Volcano together make it possible to maximise utilisation without sacrificing the quota guarantees, which is exactly the FinOps objective.&lt;/p>
&lt;p>Managing MIG partitions within this system (declaring &lt;code>nvidia.com/mig-4g.40gb&lt;/code> as a resource in the ClusterQueue) integrates naturally: the ResourceFlavor can map to nodes with a specific MIG profile, as explained in &lt;a href="https://blog.lo0.es/en/posts/sharing-one-gpu-time-slicing-mps-mig/">sharing a GPU: time-slicing, MPS and MIG&lt;/a>.&lt;/p>
&lt;hr>
&lt;h2 id="diagram-the-flow-of-a-training-job-with-kueue--volcano">Diagram: the flow of a training job with Kueue + Volcano&lt;/h2>
&lt;div class="diagram" style="max-width:800px;margin:1rem auto;">
&lt;svg viewBox="0 0 800 380" role="img" aria-label="Admission and scheduling flow of a distributed training job with Kueue and Volcano on Kubernetes" xmlns="http://www.w3.org/2000/svg">
&lt;style>.bx{fill:none;stroke:currentColor;stroke-width:1.4}.dsh{fill:none;stroke:currentColor;stroke-width:1.4;stroke-dasharray:5 3}.tl{font:600 12px sans-serif;fill:currentColor}.ts{font:11px sans-serif;fill:currentColor}.ar{fill:none;stroke:currentColor;stroke-width:1.4;marker-end:url(#arm)}&lt;/style>
&lt;defs>&lt;marker id="arm" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">&lt;path d="M0,0 L10,5 L0,10 z" fill="currentColor"/>&lt;/marker>&lt;/defs>
&lt;text x="400" y="22" text-anchor="middle" font-size="13" font-weight="700" fill="currentColor">Distributed training job: Kueue (quota) + Volcano (gang placement)&lt;/text>
&lt;rect class="bx" x="20" y="40" width="140" height="52" rx="5"/>
&lt;text x="90" y="62" text-anchor="middle" class="tl">User / CI&lt;/text>
&lt;text x="90" y="78" text-anchor="middle" class="ts">kubectl apply PyTorchJob&lt;/text>
&lt;path class="ar" d="M160,66 L200,66"/>
&lt;rect class="bx" x="200" y="40" width="155" height="52" rx="5"/>
&lt;text x="277" y="62" text-anchor="middle" class="tl">Kueue controller&lt;/text>
&lt;text x="277" y="78" text-anchor="middle" class="ts">quota available in the CQ?&lt;/text>
&lt;path class="ar" d="M277,92 L277,130"/>
&lt;rect class="dsh" x="200" y="130" width="155" height="40" rx="5"/>
&lt;text x="277" y="146" text-anchor="middle" class="tl">Waiting queue&lt;/text>
&lt;text x="277" y="162" text-anchor="middle" class="ts">fair-share / priority&lt;/text>
&lt;path class="ar" d="M355,66 L400,66"/>
&lt;rect class="bx" x="400" y="40" width="155" height="52" rx="5"/>
&lt;text x="477" y="62" text-anchor="middle" class="tl">Admission (quota OK)&lt;/text>
&lt;text x="477" y="78" text-anchor="middle" class="ts">pods allowed; CQ reserves GPU&lt;/text>
&lt;path class="ar" d="M477,92 L477,140"/>
&lt;rect class="bx" x="400" y="140" width="155" height="52" rx="5"/>
&lt;text x="477" y="162" text-anchor="middle" class="tl">Volcano scheduler&lt;/text>
&lt;text x="477" y="178" text-anchor="middle" class="ts">PodGroup: minMember=8 gangs&lt;/text>
&lt;path class="ar" d="M477,192 L477,240"/>
&lt;rect class="bx" x="400" y="240" width="155" height="52" rx="5"/>
&lt;text x="477" y="262" text-anchor="middle" class="tl">4×H100 SXM nodes&lt;/text>
&lt;text x="477" y="278" text-anchor="middle" class="ts">8 pods × 4 GPU — all at once&lt;/text>
&lt;path class="ar" d="M555,166 L625,166"/>
&lt;rect class="dsh" x="625" y="140" width="150" height="52" rx="5"/>
&lt;text x="700" y="162" text-anchor="middle" class="tl">If there are no nodes&lt;/text>
&lt;text x="700" y="178" text-anchor="middle" class="ts">no pod is placed → it waits&lt;/text>
&lt;text x="90" y="320" class="ts">Kueue: manages quota, cohorts, fair-share, preemption between queues&lt;/text>
&lt;text x="90" y="338" class="ts">Volcano: gang placement (all-or-nothing), topology-aware, NUMA, DRF between Queues&lt;/text>
&lt;text x="90" y="356" class="ts">The two levels are orthogonal: Kueue sees no nodes, Volcano sees no team quota&lt;/text>
&lt;/svg>
&lt;/div>
&lt;hr>
&lt;h2 id="full-comparison-table">Full comparison table&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Criterion&lt;/th>
&lt;th>Volcano&lt;/th>
&lt;th>Kueue&lt;/th>
&lt;th>Coscheduling plugin&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Role&lt;/strong>&lt;/td>
&lt;td>Scheduler (placement)&lt;/td>
&lt;td>Admission + quota (no placement)&lt;/td>
&lt;td>kube-scheduler plugin (placement)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Gang scheduling&lt;/strong>&lt;/td>
&lt;td>Yes, pod level (PodGroup/minMember)&lt;/td>
&lt;td>Yes, admission level (quota gang)&lt;/td>
&lt;td>Yes, pod level (PodGroup)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Multi-tenant quotas&lt;/strong>&lt;/td>
&lt;td>Yes (Queue capability/guarantee)&lt;/td>
&lt;td>Yes (ClusterQueue nominalQuota)&lt;/td>
&lt;td>No&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Cohorts / borrowing&lt;/strong>&lt;/td>
&lt;td>Limited (reclaimable)&lt;/td>
&lt;td>Yes (Cohort with borrowingLimit/lendingLimit)&lt;/td>
&lt;td>No&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Fair-share&lt;/strong>&lt;/td>
&lt;td>Yes (DRF, proportion)&lt;/td>
&lt;td>Yes (Fair Sharing by historical usage)&lt;/td>
&lt;td>No&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Inter-queue preemption&lt;/strong>&lt;/td>
&lt;td>Yes (reclaim action)&lt;/td>
&lt;td>Yes (reclaimWithinCohort)&lt;/td>
&lt;td>No&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Network / NUMA topology&lt;/strong>&lt;/td>
&lt;td>Yes (v1.11+, dedicated plugins)&lt;/td>
&lt;td>Yes (TAS, Topology CRD)&lt;/td>
&lt;td>No&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Native integrations&lt;/strong>&lt;/td>
&lt;td>MPI, PyTorch, Ray, TF, Spark, Flink, Horovod&lt;/td>
&lt;td>Job, JobSet, RayJob, Kubeflow, LWS, AppWrapper, Deployment, StatefulSet&lt;/td>
&lt;td>Any job with a PodGroup&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Who places the pods&lt;/strong>&lt;/td>
&lt;td>Volcano&lt;/td>
&lt;td>kube-scheduler (or Volcano)&lt;/td>
&lt;td>kube-scheduler&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Elastic gang&lt;/strong>&lt;/td>
&lt;td>Yes (minMember &amp;lt; total replicas)&lt;/td>
&lt;td>Partial (partial admission in batch/Job)&lt;/td>
&lt;td>Limited&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Footprint&lt;/strong>&lt;/td>
&lt;td>Medium-high (its own scheduler)&lt;/td>
&lt;td>Light (an additional controller)&lt;/td>
&lt;td>Minimal (a scheduler plugin)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Compatibility with Kueue&lt;/strong>&lt;/td>
&lt;td>Yes (as the scheduler under Kueue)&lt;/td>
&lt;td>—&lt;/td>
&lt;td>Yes (a complementary option)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>CNCF status / maturity&lt;/strong>&lt;/td>
&lt;td>CNCF incubating, v1.15&lt;/td>
&lt;td>kubernetes-sigs, v1beta2, adopted in GKE/OpenShift&lt;/td>
&lt;td>kubernetes-sigs/scheduler-plugins, experimental&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>When to choose it&lt;/strong>&lt;/td>
&lt;td>HPC-like distributed training, NUMA, network topology, MPI&lt;/td>
&lt;td>Multi-tenancy with flexible quota, heterogeneous workloads, inference + batch together&lt;/td>
&lt;td>Simple clusters that only need gang without their own scheduler&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="operational-pitfalls-and-honest-scepticism">Operational pitfalls and honest scepticism&lt;/h2>
&lt;h3 id="1-deadlock-from-a-badly-configured-gang">1. Deadlock from a badly configured gang&lt;/h3>
&lt;p>The most frequent scenario: &lt;code>minMember&lt;/code> set equal to the total replica count in a cluster where several jobs compete for the same resources. If two jobs of 8 pods each try to use a cluster with 8 GPU nodes and job A has 4 pods placed (not 8, so Volcano holds them pending), and job B also has 4 pods held, &lt;strong>nobody moves forward&lt;/strong>. Volcano is doing its job properly: it places none of them until there is room for all 8. But if the queues&amp;rsquo; &lt;code>nominalQuota&lt;/code> values are badly sized against the cluster&amp;rsquo;s real capacity, this produces indefinite waits.&lt;/p>
&lt;p>Solution: size the queue quotas so that the sum of &lt;code>guarantee&lt;/code> does not exceed the real capacity, and so that the &lt;code>minMember&lt;/code> values of the active jobs fit inside the available quota. Node autoscaling with ProvisioningRequest (Kueue + cluster-autoscaler) helps, but it introduces provisioning latency that has to be taken into account in the job&amp;rsquo;s SLA.&lt;/p>
&lt;h3 id="2-quota-versus-real-capacity-the-silent-drift">2. Quota versus real capacity: the silent drift&lt;/h3>
&lt;p>Kueue&amp;rsquo;s &lt;code>nominalQuota&lt;/code> and Volcano&amp;rsquo;s &lt;code>guarantee&lt;/code> are administrative declarations. They do not guarantee that the nodes with those GPUs are available, healthy or that the device plugin has registered them correctly. A node in &lt;code>NotReady&lt;/code> with 4 GPUs reduces the real capacity without Kueue knowing: the ClusterQueue will carry on admitting workloads that then cannot be placed.&lt;/p>
&lt;p>Recommended monitoring: cross Kueue&amp;rsquo;s metrics (&lt;code>kueue_admitted_workloads_total&lt;/code>, &lt;code>kueue_pending_workloads&lt;/code>) with the cluster&amp;rsquo;s real capacity metrics (GPUs registered in the device plugin) to detect the drift. Kueue exposes native Prometheus metrics; so does Volcano.&lt;/p>
&lt;h3 id="3-gpu-resource-naming-mig-time-slicing-and-resourceflavor">3. GPU resource naming: MIG, time-slicing and ResourceFlavor&lt;/h3>
&lt;p>If the cluster uses MIG, the resources in the pod specs change from &lt;code>nvidia.com/gpu&lt;/code> to &lt;code>nvidia.com/mig-Xg.Ygb&lt;/code> (for example, &lt;code>nvidia.com/mig-3g.40gb&lt;/code>). Kueue&amp;rsquo;s ResourceFlavors and Volcano&amp;rsquo;s Queues must declare the right resource, or the quota will not match the pods. With time-slicing, the resource is still &lt;code>nvidia.com/gpu&lt;/code> but the device plugin advertises more instances than there are physical GPUs; the quota is expressed in virtual replicas, which can lead to over-admission if the VRAM budget is not taken into account (see &lt;a href="https://blog.lo0.es/en/posts/sharing-one-gpu-time-slicing-mps-mig/">sharing a GPU: time-slicing, MPS and MIG&lt;/a>).&lt;/p>
&lt;h3 id="4-preemption-in-production-the-evicted-workload-loses-progress">4. Preemption in production: the evicted workload loses progress&lt;/h3>
&lt;p>When Kueue or Volcano evicts a training job that has been running for hours, that job loses its progress if it has no checkpointing configured. The preemption is correct from the quota point of view, but it destroys work if the job is not prepared for it. Before enabling aggressive preemption, verify that all training jobs have periodic checkpointing with automatic restoration. PyTorch plus Torchrun have native support; so does DeepSpeed. Stateless batch inference jobs do not have this problem.&lt;/p>
&lt;h3 id="5-volcano-as-the-sole-scheduler-versus-coexistence-with-the-kube-scheduler">5. Volcano as the sole scheduler versus coexistence with the kube-scheduler&lt;/h3>
&lt;p>Volcano can be configured as the cluster&amp;rsquo;s default scheduler (all pods go through it) or as an alternative scheduler (only pods with &lt;code>schedulerName: volcano&lt;/code>). The first option simplifies the configuration but breaks system pods that assume kube-scheduler behaviour. The second, the recommended one, requires ML jobs to explicitly set &lt;code>schedulerName: volcano&lt;/code>, which can be a non-trivial operator or chart change for existing workloads. Kueue solves this more transparently: it only requires a label on the job, with no change of scheduler.&lt;/p>
&lt;h3 id="6-real-operational-complexity-in-2026">6. Real operational complexity in 2026&lt;/h3>
&lt;p>Running Kueue plus Volcano plus the Training Operator plus the GPU Operator in production means four components with their own CRDs, webhooks, versions and release cycles. A Kubernetes upgrade may require updating all four in sequence. The operational debt is real. For a small team without the capacity to maintain this stack, a managed Kubernetes provider (GKE with native Kueue, OpenShift with the Red Hat build of Kueue) may be more pragmatic than assembling the full stack from scratch.&lt;/p>
&lt;p>The sig-scheduler coscheduling plugin is a deliberately simpler option when all you need is gang: fewer features, less complexity, fewer things to maintain.&lt;/p>
&lt;hr>
&lt;h2 id="see-also">See also&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/gpu-chargeback-showback-multi-tenancy/">GPU chargeback and showback in multi-tenancy&lt;/a> — how to connect Kueue&amp;rsquo;s &lt;code>nominalQuota&lt;/code> with the monthly OpenCost report per team.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/gpu-idle-cost-not-on-any-invoice/">GPU utilisation as a FinOps lever&lt;/a> — gang scheduling plus quotas as a tool for raising utilisation without idle capacity blocked by deadlocks.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/sharing-one-gpu-time-slicing-mps-mig/">Sharing a GPU: time-slicing, MPS and MIG&lt;/a> — how to declare MIG resources in a Kueue ResourceFlavor and in a Volcano Queue.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/capacity-planning-on-premise-llm-inference/">Capacity planning for on-premise LLM inference&lt;/a> — the model&amp;rsquo;s VRAM budget determines the PodGroup&amp;rsquo;s minMember and the minimum viable nominalQuota.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/llm-inference-autoscaling-kubernetes-hpa-keda/">LLM autoscaling on Kubernetes with KEDA&lt;/a> — how to combine autoscaling of inference replicas with Kueue quotas so as not to exceed the GPU budget.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/llm-inference-operators-kubernetes/">LLM operators on Kubernetes&lt;/a> — the Training Operator (Kubeflow) is the controller that creates the PyTorchJob/TFJob objects managed by Kueue + Volcano.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/gpu-cluster-as-multi-tenant-platform/">H100 cluster: multi-tenant platform&lt;/a> — the complete architecture of a multi-tenant GPU cluster where Volcano and Kueue are pieces of the scheduling stack.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="sources">Sources&lt;/h2>
&lt;ul>
&lt;li>Volcano — Introducción y features (CNCF incubating, v1.15) — &lt;a href="https://volcano.sh/en/docs/">https://volcano.sh/en/docs/&lt;/a>&lt;/li>
&lt;li>Volcano — Volcano v1.11 Released: A New Era of Cloud-Native Scheduling (CNCF blog, marzo 2025) — &lt;a href="https://www.cncf.io/blog/2025/03/05/volcano-v1-11-released-a-new-era-of-cloud-native-scheduling-for-ai-and-big-data/">https://www.cncf.io/blog/2025/03/05/volcano-v1-11-released-a-new-era-of-cloud-native-scheduling-for-ai-and-big-data/&lt;/a>&lt;/li>
&lt;li>Volcano — Release v1.11.0 (GitHub) — &lt;a href="https://github.com/volcano-sh/volcano/releases/tag/v1.11.0">https://github.com/volcano-sh/volcano/releases/tag/v1.11.0&lt;/a>&lt;/li>
&lt;li>Volcano — Network Topology Aware Scheduling design doc — &lt;a href="https://github.com/volcano-sh/volcano/blob/master/docs/design/Network%20Topology%20Aware%20Scheduling.md">https://github.com/volcano-sh/volcano/blob/master/docs/design/Network%20Topology%20Aware%20Scheduling.md&lt;/a>&lt;/li>
&lt;li>Volcano — NUMA-aware scheduling design — &lt;a href="https://github.com/volcano-sh/volcano/blob/master/docs/design/numa-aware.md">https://github.com/volcano-sh/volcano/blob/master/docs/design/numa-aware.md&lt;/a>&lt;/li>
&lt;li>Volcano — Unified Scheduling (docs oficiales) — &lt;a href="https://volcano.sh/en/docs/unified_scheduling/">https://volcano.sh/en/docs/unified_scheduling/&lt;/a>&lt;/li>
&lt;li>Volcano — Capacity scheduling design — &lt;a href="https://github.com/volcano-sh/volcano/blob/master/docs/design/capacity-scheduling.md">https://github.com/volcano-sh/volcano/blob/master/docs/design/capacity-scheduling.md&lt;/a>&lt;/li>
&lt;li>NVIDIA Technical Blog — Practical Tips for Preventing GPU Fragmentation for Volcano Scheduler — &lt;a href="https://developer.nvidia.com/blog/practical-tips-for-preventing-gpu-fragmentation-for-volcano-scheduler/">https://developer.nvidia.com/blog/practical-tips-for-preventing-gpu-fragmentation-for-volcano-scheduler/&lt;/a>&lt;/li>
&lt;li>Kueue — Overview (kueue.sigs.k8s.io, actualizado febrero 2026) — &lt;a href="https://kueue.sigs.k8s.io/docs/overview/">https://kueue.sigs.k8s.io/docs/overview/&lt;/a>&lt;/li>
&lt;li>Kueue — Cluster Queue (nominalQuota, borrowingLimit, lendingLimit, preemption) — &lt;a href="https://kueue.sigs.k8s.io/docs/concepts/cluster_queue/">https://kueue.sigs.k8s.io/docs/concepts/cluster_queue/&lt;/a>&lt;/li>
&lt;li>Kueue — Cohort — &lt;a href="https://kueue.sigs.k8s.io/docs/concepts/cohort/">https://kueue.sigs.k8s.io/docs/concepts/cohort/&lt;/a>&lt;/li>
&lt;li>Kueue — Fair Sharing — &lt;a href="https://kueue.sigs.k8s.io/docs/concepts/fair_sharing/">https://kueue.sigs.k8s.io/docs/concepts/fair_sharing/&lt;/a>&lt;/li>
&lt;li>Kueue — Topology Aware Scheduling — &lt;a href="https://kueue.sigs.k8s.io/docs/concepts/topology_aware_scheduling/">https://kueue.sigs.k8s.io/docs/concepts/topology_aware_scheduling/&lt;/a>&lt;/li>
&lt;li>Kueue — Preemption — &lt;a href="https://kueue.sigs.k8s.io/docs/concepts/preemption/">https://kueue.sigs.k8s.io/docs/concepts/preemption/&lt;/a>&lt;/li>
&lt;li>Kueue — Setup All-or-nothing with ready Pods — &lt;a href="https://kueue.sigs.k8s.io/docs/tasks/manage/setup_wait_for_pods_ready/">https://kueue.sigs.k8s.io/docs/tasks/manage/setup_wait_for_pods_ready/&lt;/a>&lt;/li>
&lt;li>Kueue — GitHub (kubernetes-sigs/kueue) — &lt;a href="https://github.com/kubernetes-sigs/kueue">https://github.com/kubernetes-sigs/kueue&lt;/a>&lt;/li>
&lt;li>Ray — Gang Scheduling with RayJob and Kueue — &lt;a href="https://docs.ray.io/en/latest/cluster/kubernetes/examples/rayjob-kueue-gang-scheduling.html">https://docs.ray.io/en/latest/cluster/kubernetes/examples/rayjob-kueue-gang-scheduling.html&lt;/a>&lt;/li>
&lt;li>Kubeflow — Volcano scheduler integration — &lt;a href="https://www.kubeflow.org/docs/components/trainer/operator-guides/job-scheduling/volcano/">https://www.kubeflow.org/docs/components/trainer/operator-guides/job-scheduling/volcano/&lt;/a>&lt;/li>
&lt;li>kubernetes-sigs/scheduler-plugins — Coscheduling plugin README — &lt;a href="https://github.com/kubernetes-sigs/scheduler-plugins/blob/master/pkg/coscheduling/README.md">https://github.com/kubernetes-sigs/scheduler-plugins/blob/master/pkg/coscheduling/README.md&lt;/a>&lt;/li>
&lt;li>kubernetes/enhancements — KEP-583 Coscheduling (sig-scheduling) — &lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-scheduling/583-coscheduling">https://github.com/kubernetes/enhancements/tree/master/keps/sig-scheduling/583-coscheduling&lt;/a>&lt;/li>
&lt;li>InfraCloud — Batch Scheduling on Kubernetes: Comparing YuniKorn, Volcano and Kueue — &lt;a href="https://www.infracloud.io/blogs/batch-scheduling-on-kubernetes/">https://www.infracloud.io/blogs/batch-scheduling-on-kubernetes/&lt;/a>&lt;/li>
&lt;li>Red Hat — Red Hat build of Kueue (OpenShift 4.20) — &lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html/ai_workloads/red-hat-build-of-kueue">https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html/ai_workloads/red-hat-build-of-kueue&lt;/a>&lt;/li>
&lt;li>AceCloud — Multi GPU Orchestration in Kubernetes 2026: Kueue, Volcano, DRA — &lt;a href="https://acecloud.ai/blog/multi-gpu-orchestration-kubernetes/">https://acecloud.ai/blog/multi-gpu-orchestration-kubernetes/&lt;/a>&lt;/li>
&lt;li>CloudOptimo — Kubernetes AI Infrastructure in 2026: GPU Scheduling and Production Realities — &lt;a href="https://www.cloudoptimo.com/blog/kubernetes-ai-infrastructure-in-2026-gpu-scheduling-and-production-realities/">https://www.cloudoptimo.com/blog/kubernetes-ai-infrastructure-in-2026-gpu-scheduling-and-production-realities/&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>GPU chargeback and showback in multi-tenancy: how to split cluster cost between teams</title><link>https://blog.lo0.es/en/posts/gpu-chargeback-showback-multi-tenancy/</link><pubDate>Mon, 15 Jun 2026 04:00:00 +0200</pubDate><guid>https://blog.lo0.es/en/posts/gpu-chargeback-showback-multi-tenancy/</guid><description>&lt;blockquote>
&lt;p>Notation: amounts in &lt;strong>euros (N €)&lt;/strong>, decimals with a point. The dollar sign is not used
(on this site it is a formula delimiter).&lt;/p>
&lt;/blockquote>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>A cluster of 4×H100 SXM at ~1.40 €/GPU-hour (depreciated capex plus energy) shared between three
teams with different occupancy produces a monthly chargeback report of 3 rows and an additional
idle row that nobody claimed. Without tooling, that idle cost vanishes, diluted into the total.
With OpenCost + LiteLLM + Kueue, attribution operates on three orthogonal planes: the &lt;strong>iron&lt;/strong>
(OpenCost, €/GPU-hour per namespace/label), &lt;strong>token consumption&lt;/strong> (LiteLLM, €/token per
key/team/model) and the &lt;strong>scheduler quota&lt;/strong> (Kueue, GPUs reserved per ClusterQueue). Crossing the
three produces the number that goes to finance: team B consumed X million tokens at Y €/1M tok,
the GPU cost it Z €, and it still has 2 GPUs borrowed from the cohort that will cost it W € if it
holds on to them next month.&lt;/p>
&lt;hr>
&lt;h2 id="showback-vs-chargeback-the-finops-foundation-definition">Showback vs chargeback: the FinOps Foundation definition&lt;/h2>
&lt;p>The distinction is not one of technology but of &lt;strong>accounting formality&lt;/strong>
(&lt;a href="https://www.finops.org/framework/capabilities/invoicing-chargeback/">FinOps Foundation — Invoicing &amp;amp; Chargeback&lt;/a>,
&lt;a href="https://www.finops.org/framework/previous-capabilities/analysis-showback/">FinOps Foundation — Data Analysis and Showback&lt;/a>):&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Concept&lt;/th>
&lt;th>Definition&lt;/th>
&lt;th>Moves money&lt;/th>
&lt;th>Requires&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Showback&lt;/strong>&lt;/td>
&lt;td>visibility of consumption and its cost per team; the report arrives, the budget does not change&lt;/td>
&lt;td>No&lt;/td>
&lt;td>metrics + attribution&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Chargeback&lt;/strong>&lt;/td>
&lt;td>the cost is transferred to the team&amp;rsquo;s or product&amp;rsquo;s P&amp;amp;L as real expenditure&lt;/td>
&lt;td>Yes&lt;/td>
&lt;td>showback + accounting policy + financial system&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Two points from the framework worth pinning down:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Showback is a requirement of any FinOps practice; chargeback is optional&lt;/strong> and depends on
the organisation&amp;rsquo;s accounting policy supporting transfers between cost centres.&lt;/li>
&lt;li>&lt;strong>Neither is &amp;ldquo;more mature&amp;rdquo; than the other.&lt;/strong> The narrative that chargeback is the &amp;ldquo;grown-up&amp;rdquo;
version is false according to the framework itself. The natural sequence is: showback → trust
in the data → chargeback if policy allows it.&lt;/li>
&lt;/ol>
&lt;h3 id="when-to-use-each">When to use each&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Situation&lt;/th>
&lt;th>Recommended mode&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>First attribution cycle; teams do not trust the data yet&lt;/td>
&lt;td>Showback&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Teams with their own budget in a financial system&lt;/td>
&lt;td>Chargeback&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Shared cluster with no P&amp;amp;L separation per team&lt;/td>
&lt;td>Showback with visible idle cost&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Teams with a committed GPU availability SLA&lt;/td>
&lt;td>Chargeback (real reservation)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Research/experimentation workloads with no formal budget&lt;/td>
&lt;td>Showback + threshold alert&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="gpu-cost-attribution-with-opencost">GPU cost attribution with OpenCost&lt;/h2>
&lt;h3 id="allocation-api-attribution-parameters">Allocation API: attribution parameters&lt;/h3>
&lt;p>The OpenCost &lt;code>/allocation&lt;/code> API is the piece that turns Prometheus metrics into a cost report per
dimension (&lt;a href="https://opencost.io/docs/integrations/api/">OpenCost — API&lt;/a>):&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Parameter&lt;/th>
&lt;th>Values&lt;/th>
&lt;th>Use in multi-tenancy&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>window&lt;/code>&lt;/td>
&lt;td>&lt;code>today&lt;/code>, &lt;code>7d&lt;/code>, &lt;code>lastmonth&lt;/code>, RFC3339 range&lt;/td>
&lt;td>window of the monthly report&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>aggregate&lt;/code>&lt;/td>
&lt;td>&lt;code>namespace&lt;/code>, &lt;code>label:LABEL&lt;/code>, &lt;code>annotation:NAME&lt;/code>, &lt;code>pod&lt;/code>, &lt;code>controller&lt;/code>&lt;/td>
&lt;td>attribution dimension&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>includeIdle&lt;/code>&lt;/td>
&lt;td>&lt;code>true&lt;/code> / &lt;code>false&lt;/code>&lt;/td>
&lt;td>adds an &lt;code>__idle__&lt;/code> row to the report&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>shareIdle&lt;/code>&lt;/td>
&lt;td>&lt;code>true&lt;/code> / &lt;code>false&lt;/code>&lt;/td>
&lt;td>distributes idle among the non-idle allocations (proportional to non-idle cost)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>idleByNode&lt;/code>&lt;/td>
&lt;td>&lt;code>true&lt;/code> / &lt;code>false&lt;/code>&lt;/td>
&lt;td>computes idle per node instead of per cluster&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>filter&lt;/code>&lt;/td>
&lt;td>&lt;code>namespace:&amp;quot;llm-prod&amp;quot;&lt;/code>, &lt;code>label:equipo:&amp;quot;datos&amp;quot;&lt;/code>&lt;/td>
&lt;td>restrict to one specific team&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Query for a monthly report per team, with idle visible as a separate row:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">curl -G http://localhost:9003/allocation &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -d &lt;span class="nv">window&lt;/span>&lt;span class="o">=&lt;/span>lastmonth &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -d &lt;span class="nv">aggregate&lt;/span>&lt;span class="o">=&lt;/span>label:equipo &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -d &lt;span class="nv">includeIdle&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">true&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -d &lt;span class="nv">shareIdle&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">false&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -d &lt;span class="nv">resolution&lt;/span>&lt;span class="o">=&lt;/span>10m
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>With &lt;code>shareIdle=false&lt;/code> (the default), OpenCost returns idle as a separate &lt;code>__idle__&lt;/code> entry, which
makes visible how much was paid for unused capacity. With &lt;code>shareIdle=true&lt;/code>, that idle is
distributed among the tenants in proportion to their non-idle cost: each absorbs its share of the
waste, which is the right behaviour for a chargeback that penalises whoever is responsible for
the idle.&lt;/p>
&lt;h3 id="labelling-inference-pods">Labelling inference pods&lt;/h3>
&lt;p>For &lt;code>aggregate=label:equipo&lt;/code> to work, the inference pods need the right label. Two methods:&lt;/p>
&lt;p>&lt;strong>Label in the pod spec&lt;/strong> (the most direct):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># vLLM Deployment for the datos team&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">labels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">equipo&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">producto&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">rag-prod&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">modelo&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">llama-70b&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">entorno&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">prod&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Annotation&lt;/strong> (when the label is already taken by another convention):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># aggregate as an annotation&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">aggregate&lt;/span>&lt;span class="o">=&lt;/span>annotation:finops.io/equipo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>OpenCost supports &lt;code>aggregate=label:KEY&lt;/code> and &lt;code>aggregate=annotation:KEY&lt;/code> with the same syntax; the
choice between the two depends on the cluster&amp;rsquo;s labelling convention.&lt;/p>
&lt;h3 id="shared-costs-and-idle-the-three-modes">Shared costs and idle: the three modes&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>API mode&lt;/th>
&lt;th>Behaviour&lt;/th>
&lt;th>When&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>includeIdle=false&lt;/code> (default)&lt;/td>
&lt;td>Ignores idle; total cost looks lower than it is&lt;/td>
&lt;td>Never in production&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>includeIdle=true, shareIdle=false&lt;/code>&lt;/td>
&lt;td>Idle in a separate &lt;code>__idle__&lt;/code> row&lt;/td>
&lt;td>Showback: visibility of waste&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>includeIdle=true, shareIdle=true&lt;/code>&lt;/td>
&lt;td>Idle distributed among tenants proportionally&lt;/td>
&lt;td>Chargeback: the team pays its share of idle&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>shareIdle=true, idleByNode=true&lt;/code>&lt;/td>
&lt;td>Idle distributed per node (finer-grained if there are dedicated nodes)&lt;/td>
&lt;td>Chargeback with heterogeneous nodes&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>For infrastructure with nodes dedicated per team, &lt;code>idleByNode=true&lt;/code> is fairer: the idle of a node
dedicated to team A is not transferred to team B.&lt;/p>
&lt;hr>
&lt;h2 id="litellm-as-the-attribution-point-for-token-consumption">LiteLLM as the attribution point for token consumption&lt;/h2>
&lt;h3 id="virtual-keys-and-teams">Virtual keys and teams&lt;/h3>
&lt;p>LiteLLM materialises token chargeback with four mechanisms
(&lt;a href="https://docs.litellm.ai/docs/proxy/virtual_keys">LiteLLM — Virtual Keys&lt;/a>,
&lt;a href="https://docs.litellm.ai/docs/proxy/team_budgets">LiteLLM — Setting Team Budgets&lt;/a>,
&lt;a href="https://docs.litellm.ai/docs/proxy/cost_tracking">LiteLLM — Spend Tracking&lt;/a>):&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Mechanism&lt;/th>
&lt;th>What it does&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Virtual key&lt;/strong> with &lt;code>max_budget&lt;/code>&lt;/td>
&lt;td>monthly budget per key; the key is blocked once it is exhausted&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>&lt;code>budget_duration&lt;/code>&lt;/strong>&lt;/td>
&lt;td>reset window: &lt;code>30d&lt;/code>, &lt;code>7d&lt;/code>, &lt;code>24h&lt;/code>; the proxy runs a daily cron that resets according to the duration&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>&lt;code>team_id&lt;/code>&lt;/strong>&lt;/td>
&lt;td>groups keys; spend accumulates in &lt;code>LiteLLM_TeamTable&lt;/code> per team&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>&lt;code>tags&lt;/code>&lt;/strong>&lt;/td>
&lt;td>tag each request; they allow budgets per tag (cost centre)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Spend logs&lt;/strong>&lt;/td>
&lt;td>one row per request with &lt;code>team_id&lt;/code>, &lt;code>model&lt;/code>, &lt;code>prompt_tokens&lt;/code>, &lt;code>completion_tokens&lt;/code>, &lt;code>response_cost&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="configuring-teams-with-a-monthly-budget">Configuring teams with a monthly budget&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># litellm-config.yaml — per-team budgets with the declared on-prem cost&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">model_list&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">model_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">llama-3-70b-onprem&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">litellm_params&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">model&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">openai/llama-3-70b&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">api_base&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">http://vllm-svc:8000/v1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">input_cost_per_token&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">0.00000140&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 1.40 €/1M tok (€/GPU-hour ÷ throughput)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">output_cost_per_token&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">0.00000140&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">model_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">llama-3-8b-onprem&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">litellm_params&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">model&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">openai/llama-3-8b&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">api_base&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">http://vllm-8b-svc:8000/v1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">input_cost_per_token&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">0.00000035&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 0.35 €/1M tok (1 GPU, higher throughput)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">output_cost_per_token&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">0.00000035&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">litellm_settings&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">success_callback&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;langfuse&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># or any external logger&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># Teams (via the /team/new API or config)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># POST /team/new&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># {&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># &amp;#34;team_alias&amp;#34;: &amp;#34;equipo-datos&amp;#34;,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># &amp;#34;max_budget&amp;#34;: 800, # 800 € per month&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># &amp;#34;budget_duration&amp;#34;: &amp;#34;30d&amp;#34;,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># &amp;#34;tpm_limit&amp;#34;: 500000, # max tokens/min&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># &amp;#34;rpm_limit&amp;#34;: 1000 # max requests/min&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># }&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The &lt;code>input_cost_per_token&lt;/code> key comes from the identity in &lt;a href="https://blog.lo0.es/en/posts/gpu-hour-to-cost-per-token-on-prem-vs-cloud/">article A4&lt;/a>:
the €/GPU-hour from OpenCost divided by the benchmark throughput. With that value, the
&lt;code>response_cost&lt;/code> of each request reflects the real cost of the on-prem iron for that model.&lt;/p>
&lt;h3 id="endpoints-for-querying-spend-per-team">Endpoints for querying spend per team&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Team spend accumulated over the period&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">GET /team/info?team_id&lt;span class="o">=&lt;/span>equipo-datos
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Team spend per model (aggregated spend_logs table)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">GET /global/spend/logs?team_id&lt;span class="o">=&lt;/span>equipo-datos&lt;span class="p">&amp;amp;&lt;/span>&lt;span class="nv">start_date&lt;/span>&lt;span class="o">=&lt;/span>2026-06-01&lt;span class="p">&amp;amp;&lt;/span>&lt;span class="nv">end_date&lt;/span>&lt;span class="o">=&lt;/span>2026-06-30
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Total spend across all teams&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">GET /global/spend/teams
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The response includes &lt;code>spend&lt;/code> (accumulated cost in the configured currency), &lt;code>total_tokens&lt;/code>,
&lt;code>prompt_tokens&lt;/code>, &lt;code>completion_tokens&lt;/code> and a per-model breakdown, the direct fields for the monthly
chargeback report.&lt;/p>
&lt;h3 id="joining-gpu-hour-iron-with-tokens-per-team">Joining €/GPU-hour (iron) with tokens per team&lt;/h3>
&lt;p>The two attribution planes, OpenCost (iron) and LiteLLM (tokens), are crossed with one key: the
&lt;code>model_name&lt;/code> and the &lt;code>namespace&lt;/code>. The join happens outside the tools (in a BI pipeline or a SQL
query over the LiteLLM database and the data exported from OpenCost):&lt;/p>
&lt;pre tabindex="0">&lt;code>coste_por_token_real = OpenCost.GPU_cost_namespace / LiteLLM.total_tokens_team
&lt;/code>&lt;/pre>&lt;p>When the on-prem cost is properly declared in &lt;code>input_cost_per_token&lt;/code>, LiteLLM already does this
calculation internally and the &lt;code>response_cost&lt;/code> is correct. The explicit join serves to validate:
if the sum of LiteLLM&amp;rsquo;s &lt;code>response_cost&lt;/code> per team does not match the GPU cost OpenCost assigns to
the namespace, there is drift in &lt;code>input_cost_per_token&lt;/code> that has to be corrected (changed
throughput, a new optimisation, more replicas).&lt;/p>
&lt;hr>
&lt;h2 id="kueue-as-the-gpu-budgetquota-mechanism">Kueue as the GPU budget/quota mechanism&lt;/h2>
&lt;h3 id="clusterqueue-localqueue-and-cohorts">ClusterQueue, LocalQueue and cohorts&lt;/h3>
&lt;p>Kueue introduces the &lt;strong>quota-based scheduling&lt;/strong> layer on top of Kubernetes
(&lt;a href="https://kueue.sigs.k8s.io/docs/concepts/cluster_queue/">Kueue — Cluster Queue&lt;/a>,
&lt;a href="https://kueue.sigs.k8s.io/docs/concepts/cohort/">Kueue — Cohort&lt;/a>,
&lt;a href="https://kueue.sigs.k8s.io/docs/concepts/fair_sharing/">Kueue — Fair Sharing&lt;/a>):&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Object&lt;/th>
&lt;th>Scope&lt;/th>
&lt;th>What it does&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>ResourceFlavor&lt;/code>&lt;/td>
&lt;td>cluster&lt;/td>
&lt;td>maps resources to a group of nodes (e.g. H100 nodes)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>ClusterQueue&lt;/code>&lt;/td>
&lt;td>cluster&lt;/td>
&lt;td>defines &lt;code>nominalQuota&lt;/code>, &lt;code>borrowingLimit&lt;/code>, &lt;code>lendingLimit&lt;/code> per resource/flavor&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>LocalQueue&lt;/code>&lt;/td>
&lt;td>namespace&lt;/td>
&lt;td>entry point for the team&amp;rsquo;s workloads; points to a &lt;code>ClusterQueue&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Cohort&lt;/code>&lt;/td>
&lt;td>cluster&lt;/td>
&lt;td>groups ClusterQueues that can lend quota to each other&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="quota-concepts">Quota concepts&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>&lt;code>nominalQuota&lt;/code>&lt;/strong>: GPUs guaranteed to the ClusterQueue at all times.&lt;/li>
&lt;li>&lt;strong>&lt;code>borrowingLimit&lt;/code>&lt;/strong>: maximum additional GPUs it can borrow from the cohort when others are not
using them.&lt;/li>
&lt;li>&lt;strong>&lt;code>lendingLimit&lt;/code>&lt;/strong>: GPUs from its &lt;code>nominalQuota&lt;/code> that it allows to be lent to others (if not
specified, it can lend all unused ones).&lt;/li>
&lt;li>&lt;strong>Fair Sharing&lt;/strong>: a mechanism that orders pending workloads by the historical resource usage of
their LocalQueue, giving preference to whoever has consumed less. Compatible with hierarchical
cohorts since Kueue v0.11.&lt;/li>
&lt;/ul>
&lt;h3 id="example-yaml-3-teams-in-the-llm-platform-cohort">Example YAML: 3 teams in the llm-platform cohort&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># ResourceFlavor mapping to the H100 SXM nodes&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kueue.x-k8s.io/v1beta2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ResourceFlavor&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">h100-sxm&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nodeLabels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">accelerator&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">h100-sxm&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># ClusterQueue for the datos team — 2 guaranteed GPUs, can borrow up to 2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kueue.x-k8s.io/v1beta2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ClusterQueue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">cq-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cohort&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">llm-platform&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespaceSelector&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">matchLabels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kubernetes.io/metadata.name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ns-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">queueingStrategy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">BestEffortFIFO&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resourceGroups&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">coveredResources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;nvidia.com/gpu&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">flavors&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">h100-sxm&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;nvidia.com/gpu&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nominalQuota&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">borrowingLimit&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">2&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># can use up to 4 GPUs in total&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">preemption&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">reclaimWithinCohort&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">LowerPriority&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">withinClusterQueue&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">LowerPriority&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># ClusterQueue for the ia team — 1 guaranteed GPU, lends what it does not use&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kueue.x-k8s.io/v1beta2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ClusterQueue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">cq-ia&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cohort&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">llm-platform&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespaceSelector&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">matchLabels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kubernetes.io/metadata.name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ns-ia&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resourceGroups&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">coveredResources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;nvidia.com/gpu&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">flavors&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">h100-sxm&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;nvidia.com/gpu&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nominalQuota&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">lendingLimit&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># lends its GPU when it is not using it&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># ClusterQueue for the plataforma team — 1 guaranteed GPU, low priority&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kueue.x-k8s.io/v1beta2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ClusterQueue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">cq-plataforma&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cohort&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">llm-platform&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespaceSelector&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">matchLabels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kubernetes.io/metadata.name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ns-plataforma&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resourceGroups&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">coveredResources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;nvidia.com/gpu&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">flavors&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">h100-sxm&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;nvidia.com/gpu&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nominalQuota&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">borrowingLimit&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">3&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># can use all 4 if the rest are free&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># LocalQueue in each namespace — entry point for the workloads&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kueue.x-k8s.io/v1beta2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">LocalQueue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">lq-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ns-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">clusterQueue&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">cq-datos&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="how-kueue-materialises-the-gpu-budget">How Kueue materialises the &amp;ldquo;GPU budget&amp;rdquo;&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>FinOps concept&lt;/th>
&lt;th>Kueue mechanism&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Guaranteed budget&lt;/td>
&lt;td>&lt;code>nominalQuota&lt;/code>: the team always has these GPUs available&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Maximum spend limit&lt;/td>
&lt;td>&lt;code>nominalQuota + borrowingLimit&lt;/code>: absolute ceiling of admissible GPUs&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Lending idle capacity&lt;/td>
&lt;td>cohort + &lt;code>lendingLimit&lt;/code>: others take what this one does not use&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Fair sharing between teams&lt;/td>
&lt;td>&lt;code>Fair Sharing&lt;/code> + &lt;code>WorkloadPriorityClass&lt;/code>: those who have consumed most wait longest&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Reclaiming your own quota&lt;/td>
&lt;td>&lt;code>preemption.reclaimWithinCohort: LowerPriority&lt;/code>: the owner of the lent GPU reclaims it by evicting lower-priority workloads&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The &lt;code>nominalQuota&lt;/code> is the expression of the budget in GPUs: if the team has 2 nominal GPUs and the
price is 1.40 €/GPU-hour, its maximum guaranteed spend is&lt;/p>
\[
\text{maximum nominal spend} = 2 \times 1.40 \times 720 = 2{,}016 \text{ €/month}
\]
&lt;p>The &lt;code>borrowingLimit&lt;/code> sets the potential overspend if it borrows from the cohort (and that
borrowing can be charged with the same formula, multiplying the borrowed usage hours by
1.40 €/GPU-hour).&lt;/p>
&lt;hr>
&lt;h2 id="cost-model-an-example-with-4h100-sxm-and-3-teams">Cost model: an example with 4×H100 SXM and 3 teams&lt;/h2>
&lt;h3 id="node-price">Node price&lt;/h3>
&lt;p>Generic hardware: a server with 4×H100 SXM 80 GB. 2026 market prices: a single H100 SXM costs
between 27,000 and 40,000 € depending on the source
(&lt;a href="https://www.gmicloud.ai/en/blog/nvidia-h100-gpu-pricing-2026-rent-vs-buy-cost-analysis">GMI Cloud — H100 GPU Pricing 2026&lt;/a>);
a 4×H100 server sits in the 120,000–180,000 € range including chassis, power supplies and NVLink.
We use 140,000 € as a generic assumption for the complete server (4 GPUs plus infrastructure).&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Component&lt;/th>
&lt;th>Calculation&lt;/th>
&lt;th>€/hour node&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Depreciated capex (140,000 €, 4 years, 90 % availability)&lt;/td>
&lt;td>140,000 ÷ (4 × 8,760 × 0.9)&lt;/td>
&lt;td>~4.43&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Energy (4 × 700 W TDP × PUE 1.4 × 0.12 €/kWh)&lt;/td>
&lt;td>4 × 0.7 × 1.4 × 0.12&lt;/td>
&lt;td>~0.47&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Operations / networking / maintenance&lt;/td>
&lt;td>estimate&lt;/td>
&lt;td>~0.70&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Total 4×H100 node&lt;/strong>&lt;/td>
&lt;td>&lt;/td>
&lt;td>&lt;strong>~5.60 €/h&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Per GPU&lt;/strong>&lt;/td>
&lt;td>5.60 ÷ 4&lt;/td>
&lt;td>&lt;strong>~1.40 €/GPU-hour&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Cost-per-token formula for the 70B model (sustained throughput ~2,000 tok/s at TP=4):&lt;/p>
$$\text{€/1M tokens} = \frac{5.60 \text{ €/h}}{2{,}000 \text{ tok/s} \times 3{,}600 \text{ s/h}} \times 10^6 \approx 0.78 \text{ €/1M tokens}$$
&lt;h3 id="monthly-scenario-3-teams-heterogeneous-utilisation">Monthly scenario: 3 teams, heterogeneous utilisation&lt;/h3>
&lt;p>Reference month (720 hours). The 4 GPUs are nominally assigned: 2 to &lt;strong>Datos&lt;/strong>, 1 to &lt;strong>IA&lt;/strong>, 1 to
&lt;strong>Plataforma&lt;/strong>. Real occupancy varies:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Team&lt;/th>
&lt;th>Nominal GPUs&lt;/th>
&lt;th>Average occupancy&lt;/th>
&lt;th>GPU-hours used&lt;/th>
&lt;th>Idle GPU-hours&lt;/th>
&lt;th>GPU cost (€)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Datos&lt;/td>
&lt;td>2&lt;/td>
&lt;td>75 %&lt;/td>
&lt;td>1,080&lt;/td>
&lt;td>360&lt;/td>
&lt;td>~1,512&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>IA&lt;/td>
&lt;td>1&lt;/td>
&lt;td>60 %&lt;/td>
&lt;td>432&lt;/td>
&lt;td>288&lt;/td>
&lt;td>~605&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Plataforma&lt;/td>
&lt;td>1&lt;/td>
&lt;td>35 %&lt;/td>
&lt;td>252&lt;/td>
&lt;td>468&lt;/td>
&lt;td>~353&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Cluster idle&lt;/strong>&lt;/td>
&lt;td>—&lt;/td>
&lt;td>—&lt;/td>
&lt;td>—&lt;/td>
&lt;td>&lt;strong>1,116&lt;/strong>&lt;/td>
&lt;td>&lt;strong>~1,562&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Node total&lt;/strong>&lt;/td>
&lt;td>4&lt;/td>
&lt;td>—&lt;/td>
&lt;td>1,764&lt;/td>
&lt;td>1,116&lt;/td>
&lt;td>&lt;strong>~4,032&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;blockquote>
&lt;p>Total node cost per month: 5.60 €/h × 720 h = 4,032 €.
Cost per GPU-hour used: 5.60 ÷ 4 = 1.40 €.&lt;/p>
&lt;/blockquote>
&lt;p>With &lt;code>shareIdle=false&lt;/code> (showback), the 1,562 € of idle appears as a separate row in the report and
nobody pays for it directly. With &lt;code>shareIdle=true&lt;/code> (proportional chargeback), it is split among
the three in proportion to their non-idle cost: Datos absorbs ~857 €, IA ~333 €, Plataforma ~192 €
of additional idle.&lt;/p>
&lt;h3 id="token-consumption-per-team-litellm-spend-logs">Token consumption per team (LiteLLM spend logs)&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Team&lt;/th>
&lt;th>Model&lt;/th>
&lt;th>Tokens/month&lt;/th>
&lt;th>Cost/token&lt;/th>
&lt;th>Token cost (€)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Datos&lt;/td>
&lt;td>llama-70b (TP=4)&lt;/td>
&lt;td>380 M&lt;/td>
&lt;td>0.78 €/1M&lt;/td>
&lt;td>~296&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>IA&lt;/td>
&lt;td>llama-8b (1 GPU)&lt;/td>
&lt;td>210 M&lt;/td>
&lt;td>0.35 €/1M&lt;/td>
&lt;td>~74&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Plataforma&lt;/td>
&lt;td>llama-8b + batch&lt;/td>
&lt;td>80 M&lt;/td>
&lt;td>0.35 €/1M&lt;/td>
&lt;td>~28&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="monthly-chargeback-report-showback--tokens">Monthly chargeback report (showback + tokens)&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Team&lt;/th>
&lt;th>Iron GPU cost (€)&lt;/th>
&lt;th>Assigned idle cost (€)&lt;/th>
&lt;th>LiteLLM token cost (€)&lt;/th>
&lt;th>Total chargeable (€)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Datos&lt;/td>
&lt;td>1,512&lt;/td>
&lt;td>857&lt;/td>
&lt;td>296&lt;/td>
&lt;td>&lt;strong>2,665&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>IA&lt;/td>
&lt;td>605&lt;/td>
&lt;td>333&lt;/td>
&lt;td>74&lt;/td>
&lt;td>&lt;strong>1,012&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Plataforma&lt;/td>
&lt;td>353&lt;/td>
&lt;td>192&lt;/td>
&lt;td>28&lt;/td>
&lt;td>&lt;strong>573&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Idle (without shareIdle)&lt;/td>
&lt;td>1,562&lt;/td>
&lt;td>—&lt;/td>
&lt;td>—&lt;/td>
&lt;td>visible, not charged&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="attribution-dimensions--policy-table">Attribution dimensions × policy table&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Attribution dimension&lt;/th>
&lt;th>Tool&lt;/th>
&lt;th>Showback&lt;/th>
&lt;th>Chargeback&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>namespace&lt;/td>
&lt;td>OpenCost &lt;code>aggregate=namespace&lt;/code>&lt;/td>
&lt;td>&lt;code>/allocation?aggregate=namespace&amp;amp;includeIdle=true&lt;/code>&lt;/td>
&lt;td>&lt;code>shareIdle=true&lt;/code> + transfer to P&amp;amp;L&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>pod label&lt;/td>
&lt;td>OpenCost &lt;code>aggregate=label:equipo&lt;/code>&lt;/td>
&lt;td>report per label&lt;/td>
&lt;td>same with shareIdle&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>virtual key / team&lt;/td>
&lt;td>LiteLLM &lt;code>/global/spend/teams&lt;/code>&lt;/td>
&lt;td>token dashboard&lt;/td>
&lt;td>hard &lt;code>max_budget&lt;/code> per key&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ClusterQueue (reserved GPU)&lt;/td>
&lt;td>Kueue &lt;code>nominalQuota&lt;/code>&lt;/td>
&lt;td>observe usage vs quota&lt;/td>
&lt;td>committed budget in GPUs&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>request tag&lt;/td>
&lt;td>LiteLLM &lt;code>tag_budgets&lt;/code>&lt;/td>
&lt;td>per cost centre&lt;/td>
&lt;td>budget per tag&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>pod annotation&lt;/td>
&lt;td>OpenCost &lt;code>aggregate=annotation:KEY&lt;/code>&lt;/td>
&lt;td>report per annotation&lt;/td>
&lt;td>same with shareIdle&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="end-to-end-data-flow">End-to-end data flow&lt;/h2>
&lt;div class="diagram" style="max-width:780px;margin:1rem auto;">
&lt;svg viewBox="0 0 780 300" role="img" aria-label="GPU chargeback attribution flow: from the inference pod to the three planes OpenCost, LiteLLM and Kueue, and to the monthly report" xmlns="http://www.w3.org/2000/svg">
&lt;style>.bx{fill:none;stroke:currentColor;stroke-width:1.3}.dsh{fill:none;stroke:currentColor;stroke-width:1.3;stroke-dasharray:5 3}.tl{font:600 12px sans-serif;fill:currentColor}.ts{font:11px sans-serif;fill:currentColor}.ar{fill:none;stroke:currentColor;stroke-width:1.3;marker-end:url(#chm)}&lt;/style>
&lt;defs>&lt;marker id="chm" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">&lt;path d="M0,0 L10,5 L0,10 z" fill="currentColor"/>&lt;/marker>&lt;/defs>
&lt;rect class="bx" x="20" y="30" width="160" height="50" rx="6"/>
&lt;text x="32" y="52" class="tl">vLLM pod&lt;/text>
&lt;text x="32" y="68" class="ts">label:equipo=datos&lt;/text>
&lt;path class="ar" d="M180,55 L220,80"/>
&lt;path class="ar" d="M180,55 L220,145"/>
&lt;path class="ar" d="M180,55 L220,210"/>
&lt;rect class="bx" x="220" y="60" width="175" height="50" rx="6"/>
&lt;text x="232" y="82" class="tl">OpenCost (iron)&lt;/text>
&lt;text x="232" y="98" class="ts">€/GPU-hour × namespace/label&lt;/text>
&lt;rect class="bx" x="220" y="125" width="175" height="50" rx="6"/>
&lt;text x="232" y="147" class="tl">LiteLLM (tokens)&lt;/text>
&lt;text x="232" y="163" class="ts">€/token × team_id/key/model&lt;/text>
&lt;rect class="bx" x="220" y="190" width="175" height="50" rx="6"/>
&lt;text x="232" y="212" class="tl">Kueue (scheduler)&lt;/text>
&lt;text x="232" y="228" class="ts">nominalQuota / cohort / fair-share&lt;/text>
&lt;path class="ar" d="M395,85 L440,140"/>
&lt;path class="ar" d="M395,150 L440,150"/>
&lt;path class="ar" d="M395,215 L440,160"/>
&lt;rect class="bx" x="440" y="115" width="185" height="70" rx="6"/>
&lt;text x="452" y="137" class="tl">Monthly report&lt;/text>
&lt;text x="452" y="153" class="ts">€/team (iron + idle + tokens)&lt;/text>
&lt;text x="452" y="169" class="ts">borrowed GPUs · budget left&lt;/text>
&lt;path class="ar" d="M625,150 L665,150"/>
&lt;rect class="dsh" x="665" y="115" width="100" height="70" rx="6"/>
&lt;text x="677" y="143" class="tl">Showback&lt;/text>
&lt;text x="677" y="159" class="ts">or&lt;/text>
&lt;text x="677" y="175" class="tl">Chargeback&lt;/text>
&lt;text x="20" y="275" class="ts">The three planes are orthogonal: OpenCost sees the iron, LiteLLM sees the tokens, Kueue sees the scheduler quota.&lt;/text>
&lt;text x="20" y="292" class="ts">Crossing the three gives the complete number: €/team with idle, tokens and borrowed GPUs.&lt;/text>
&lt;/svg>
&lt;/div>
&lt;hr>
&lt;h2 id="fair-sharing-and-preemption-how-kueue-reclaims-quota">Fair sharing and preemption: how Kueue reclaims quota&lt;/h2>
&lt;p>When the Datos team has exhausted its 2 nominal GPUs and borrows those of Plataforma (which is
not using them), Kueue records that loan. As soon as Plataforma launches a new workload:&lt;/p>
&lt;ol>
&lt;li>Kueue detects that &lt;code>cq-plataforma&lt;/code> is below its &lt;code>nominalQuota&lt;/code>.&lt;/li>
&lt;li>With &lt;code>preemption.reclaimWithinCohort: LowerPriority&lt;/code>, Kueue evicts the Datos workload that was
on the borrowed GPU, if its priority is lower.&lt;/li>
&lt;li>The evicted workload returns to the &lt;code>cq-datos&lt;/code> queue and is readmitted once quota frees up.&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>Fair Sharing&lt;/strong> orders the pending queue by the LocalQueue&amp;rsquo;s accumulated historical usage: if
Datos has consumed more GPU-hours than IA in the recent period, IA&amp;rsquo;s next workloads have
admission priority over new ones from Datos. This implements an equitable split without blocking
anyone permanently.&lt;/p>
&lt;hr>
&lt;h2 id="configuring-opencost-for-the-node-price">Configuring OpenCost for the node price&lt;/h2>
&lt;p>For the numbers in the previous section to be reproducible, the node price has to be declared
explicitly (the default value underestimates on-prem GPU,
&lt;a href="https://github.com/opencost/opencost/issues/3781">issue #3781&lt;/a>):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># OpenCost Helm values.yaml — on-prem 4×H100 node, 5.60 €/h&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">opencost&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">customPricing&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">provider&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">custom&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">costModel&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">description&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;On-prem 4xH100 SXM node&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">CPU&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;0.025&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># €/CPU-hour (minor component)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">RAM&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;0.003&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># €/GB-hour&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">GPU&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;1.40&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># €/GPU-hour ← the one that drives the split&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">storage&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;0.0002&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># €/GB-hour&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Verify after configuring:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Check the price resolved per node&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">curl http://localhost:9003/allNodePricing
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Attribution query per team label, last month, idle separate&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">curl -G http://localhost:9003/allocation &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -d &lt;span class="nv">window&lt;/span>&lt;span class="o">=&lt;/span>lastmonth &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -d &lt;span class="nv">aggregate&lt;/span>&lt;span class="o">=&lt;/span>label:equipo &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -d &lt;span class="nv">includeIdle&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">true&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -d &lt;span class="nv">shareIdle&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">false&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -d &lt;span class="nv">accumulate&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">true&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="reference-promql-for-chargeback-dashboards">Reference PromQL for chargeback dashboards&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-promql" data-lang="promql">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># GPU cost assigned per team (label:equipo) — €/hour&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">sum&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">by&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="nv">label_equipo&lt;/span>&lt;span class="o">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nv">container_gpu_allocation&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">on&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="nv">node&lt;/span>&lt;span class="o">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">group_left&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nv">node_gpu_hourly_cost&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="o">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1"># Idle GPU-hours per node (idle &amp;gt; 15 min)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">sum&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">by&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="nv">node&lt;/span>&lt;span class="o">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kr">avg_over_time&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="nv">DCGM_FI_DEV_GPU_UTIL&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s">15m&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="o">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">on&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="nv">node&lt;/span>&lt;span class="o">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">group_left&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nv">node_gpu_hourly_cost&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="o">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1"># Accumulated monthly cost per team (sum over window)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kr">sum_over_time&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">sum&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">by&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="nv">label_equipo&lt;/span>&lt;span class="o">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nv">container_gpu_allocation&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">on&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="nv">node&lt;/span>&lt;span class="o">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">group_left&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nv">node_gpu_hourly_cost&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">)&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s">30d&lt;/span>&lt;span class="err">:&lt;/span>&lt;span class="s">1h&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="o">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="sources">Sources&lt;/h2>
&lt;ul>
&lt;li>FinOps Foundation — Invoicing &amp;amp; Chargeback Capability — &lt;a href="https://www.finops.org/framework/capabilities/invoicing-chargeback/">https://www.finops.org/framework/capabilities/invoicing-chargeback/&lt;/a>&lt;/li>
&lt;li>FinOps Foundation — Data Analysis and Showback — &lt;a href="https://www.finops.org/framework/previous-capabilities/analysis-showback/">https://www.finops.org/framework/previous-capabilities/analysis-showback/&lt;/a>&lt;/li>
&lt;li>FinOps Foundation — Allocation Capability — &lt;a href="https://www.finops.org/framework/capabilities/allocation/">https://www.finops.org/framework/capabilities/allocation/&lt;/a>&lt;/li>
&lt;li>OpenCost — API (Allocation API, parámetros window/aggregate/shareIdle/idleByNode) — &lt;a href="https://opencost.io/docs/integrations/api/">https://opencost.io/docs/integrations/api/&lt;/a>&lt;/li>
&lt;li>OpenCost — API Examples — &lt;a href="https://opencost.io/docs/integrations/api-examples/">https://opencost.io/docs/integrations/api-examples/&lt;/a>&lt;/li>
&lt;li>OpenCost — GitHub (issue #3781, infra-precio GPU on-prem por defecto) — &lt;a href="https://github.com/opencost/opencost/issues/3781">https://github.com/opencost/opencost/issues/3781&lt;/a>&lt;/li>
&lt;li>LiteLLM — Virtual Keys (&lt;code>max_budget&lt;/code>, &lt;code>budget_duration&lt;/code>, &lt;code>team_id&lt;/code>) — &lt;a href="https://docs.litellm.ai/docs/proxy/virtual_keys">https://docs.litellm.ai/docs/proxy/virtual_keys&lt;/a>&lt;/li>
&lt;li>LiteLLM — Setting Team Budgets — &lt;a href="https://docs.litellm.ai/docs/proxy/team_budgets">https://docs.litellm.ai/docs/proxy/team_budgets&lt;/a>&lt;/li>
&lt;li>LiteLLM — Spend Tracking — &lt;a href="https://docs.litellm.ai/docs/proxy/cost_tracking">https://docs.litellm.ai/docs/proxy/cost_tracking&lt;/a>&lt;/li>
&lt;li>LiteLLM — Budgets &amp;amp; Rate Limits — &lt;a href="https://docs.litellm.ai/docs/proxy/users">https://docs.litellm.ai/docs/proxy/users&lt;/a>&lt;/li>
&lt;li>LiteLLM — Setting Tag Budgets — &lt;a href="https://docs.litellm.ai/docs/proxy/tag_budgets">https://docs.litellm.ai/docs/proxy/tag_budgets&lt;/a>&lt;/li>
&lt;li>LiteLLM — Budget Reset Times — &lt;a href="https://docs.litellm.ai/docs/proxy/budget_reset_and_tz">https://docs.litellm.ai/docs/proxy/budget_reset_and_tz&lt;/a>&lt;/li>
&lt;li>Kueue — Cluster Queue (nominalQuota, borrowingLimit, lendingLimit, preemption) — &lt;a href="https://kueue.sigs.k8s.io/docs/concepts/cluster_queue/">https://kueue.sigs.k8s.io/docs/concepts/cluster_queue/&lt;/a>&lt;/li>
&lt;li>Kueue — Cohort — &lt;a href="https://kueue.sigs.k8s.io/docs/concepts/cohort/">https://kueue.sigs.k8s.io/docs/concepts/cohort/&lt;/a>&lt;/li>
&lt;li>Kueue — Fair Sharing — &lt;a href="https://kueue.sigs.k8s.io/docs/concepts/fair_sharing/">https://kueue.sigs.k8s.io/docs/concepts/fair_sharing/&lt;/a>&lt;/li>
&lt;li>Kueue — Administer Cluster Quotas — &lt;a href="https://kueue.sigs.k8s.io/docs/tasks/manage/administer_cluster_quotas/">https://kueue.sigs.k8s.io/docs/tasks/manage/administer_cluster_quotas/&lt;/a>&lt;/li>
&lt;li>GMI Cloud — NVIDIA H100 GPU Pricing 2026 — &lt;a href="https://www.gmicloud.ai/en/blog/nvidia-h100-gpu-pricing-2026-rent-vs-buy-cost-analysis">https://www.gmicloud.ai/en/blog/nvidia-h100-gpu-pricing-2026-rent-vs-buy-cost-analysis&lt;/a>&lt;/li>
&lt;li>IntuitionLabs — NVIDIA AI GPU Prices H100 Cost Guide — &lt;a href="https://intuitionlabs.ai/articles/nvidia-ai-gpu-pricing-guide">https://intuitionlabs.ai/articles/nvidia-ai-gpu-pricing-guide&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="see-also">See also&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/opencost-gpu-cost-allocation-kubernetes/">OpenCost in depth: how GPU cost is allocated in Kubernetes&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/kubecost-vs-opencost-vs-alternatives/">Kubecost vs OpenCost vs alternatives&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/gpu-hour-to-cost-per-token-on-prem-vs-cloud/">From GPU-hour to cost per token&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/finops-multi-tenancy-gpu-cluster-who-pays/">FinOps and GPU cluster multi-tenancy: who pays for what&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/sharing-one-gpu-time-slicing-mps-mig/">Sharing a GPU: time-slicing, MPS and MIG&lt;/a>&lt;/li>
&lt;/ul></description></item></channel></rss>