<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Showback on lo0 — Tech Blog</title><link>https://blog.lo0.es/en/tags/showback/</link><description>Recent content in Showback on lo0 — Tech Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Mon, 15 Jun 2026 04:00:00 +0200</lastBuildDate><atom:link href="https://blog.lo0.es/en/tags/showback/index.xml" rel="self" type="application/rss+xml"/><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>