<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: mlops</title>
    <description>The latest articles tagged 'mlops' on DEV Community.</description>
    <link>https://dev.to/t/mlops</link>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tag/mlops"/>
    <language>en</language>
    <item>
      <title>How to Choose the Right AI Software Development Company in 2026?</title>
      <dc:creator>hoor ali</dc:creator>
      <pubDate>Wed, 14 Oct 2026 14:10:44 +0000</pubDate>
      <link>https://dev.to/hoor_ali_428d0ccd853d063e/how-to-choose-the-right-ai-software-development-company-in-2026-8kb</link>
      <guid>https://dev.to/hoor_ali_428d0ccd853d063e/how-to-choose-the-right-ai-software-development-company-in-2026-8kb</guid>
      <description>&lt;p&gt;To choose the right AI software development company, look for a partner that starts with your business problem, has shipped AI to production in your industry, owns data and MLOps end to end, follows a recognized AI risk framework, and prices against outcomes rather than hours. Ask for live references, a paid discovery phase, and a clear plan for what happens after launch.&lt;/p&gt;

&lt;p&gt;Almost every business is now experimenting with AI. In McKinsey's 2025 State of AI survey, 88% of respondents said their organization uses AI in at least one function, yet only 7% said it was fully scaled. The gap between a promising pilot and a system that earns its keep is usually the partner you pick. This guide walks through how to close it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does an AI software development company do?&lt;/strong&gt;&lt;br&gt;
An AI software development company designs, builds, and maintains software that uses machine learning, large language models (LLMs), or AI agents to automate decisions and tasks. Typical AI software development services include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI strategy and discovery: finding use cases with a measurable return.&lt;/li&gt;
&lt;li&gt;Data engineering: cleaning, labeling, and piping the data models depend on.&lt;/li&gt;
&lt;li&gt;Custom model and LLM development: fine-tuning, retrieval-augmented generation (RAG), and agent workflows.&lt;/li&gt;
&lt;li&gt;AI integration: adding AI features to your existing apps, CRM, or ERP.&lt;/li&gt;
&lt;li&gt;MLOps and support: monitoring, retraining, and cost control after launch.
This is different from a team that simply uses AI in software development, such as coding assistants that help engineers write code faster. Most good partners do both, but you are hiring for the first.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;7 criteria for choosing an AI software development company:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;They start with the problem, not the model:&lt;br&gt;
Strong partners ask about your workflow, KPIs, and budget before they mention GPT, Claude, or Gemini. If the first call is a tech demo, expect a solution looking for a problem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Proven production work in your industry:&lt;br&gt;
Ask for two or three case studies with numbers: hours saved, error rates cut, revenue gained. Then ask to speak with those clients. A pilot that never went live is not a reference.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Data readiness and security:&lt;br&gt;
AI is only as good as its data. The company should assess your data quality early and explain where your data is stored, who can access it, and whether it is used to train third-party models. Look for SOC 2 or ISO 27001 practices and compliance with rules such as GDPR or HIPAA where they apply.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Responsible AI and governance:&lt;br&gt;
Ask how they test for bias, hallucinations, and failure cases. Partners who align with the NIST AI Risk Management Framework can show you a documented process for mapping, measuring, and managing AI risk.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Model-agnostic architecture:&lt;br&gt;
The best model today may not be the best in six months. Prefer a team that can swap LLM providers or run open-source models without a rebuild, so you avoid vendor lock-in and control costs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MLOps and post-launch support:&lt;br&gt;
Models drift as data changes. Confirm who monitors accuracy, how often models are retrained, and what the support SLA covers. Get the cost of running the system, including API and cloud fees, in writing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clear ownership and transparent pricing:&lt;br&gt;
Your contract should state that you own the code, prompts, fine-tuned weights, and data. Pricing should be broken into phases with defined deliverables.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Red flags to watch for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Guaranteed accuracy figures before seeing your data.&lt;/li&gt;
&lt;li&gt;No paid discovery phase; a fixed quote after one call.&lt;/li&gt;
&lt;li&gt;Vague answers on data privacy or model training.&lt;/li&gt;
&lt;li&gt;Every project uses the same tool, whatever the problem.&lt;/li&gt;
&lt;li&gt;No plan for maintenance after launch.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Common engagement and pricing models:&lt;/strong&gt;&lt;br&gt;
Most AI software development companies offer four engagement models. A paid discovery phase or proof of concept tests feasibility in 2–6 weeks, and it doubles as a test of the team, not just the idea. A fixed-scope project suits well-defined features with clean data, though change requests can get expensive. &lt;br&gt;
Time and materials fit evolving products and R&amp;amp;D, but it needs strong sprint reporting to keep costs visible. A dedicated AI team works best for long-term roadmaps, as long as you have your own product owner to steer it. Whichever model you choose, start with a small, paid discovery phase; it tells you more about how a company works than any sales deck.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frequently asked questions:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much does it cost to hire an AI software development company?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Costs depend on scope and data readiness. A discovery phase or proof of concept is usually the smallest commitment, while a production system with integrations and MLOps costs much more. Ask for phased quotes and a monthly estimate of running costs such as API and cloud fees.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long does an AI software project take?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A proof of concept typically takes 2–6 weeks. A production-ready AI feature often takes 3–6 months, depending on data quality, integrations, and compliance reviews.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the difference between AI software development services and using AI in software development?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI software development services build products that contain AI, such as chatbots, prediction engines, or agents. AI in software development refers to tools that help engineers write, test, and review code faster. A good partner uses the second to deliver the first more efficiently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I build an in-house AI team or outsource?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Outsourcing is faster when you need specialized skills now or are testing a first use case. An in-house team makes sense once AI is core to your product. Many companies start with a partner and hire internally as the system matures.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mlops</category>
      <category>llm</category>
      <category>development</category>
    </item>
    <item>
      <title>From Model Experiments to Applications That People Can Use</title>
      <dc:creator>Satavisha Dutta</dc:creator>
      <pubDate>Wed, 14 Oct 2026 10:26:40 +0000</pubDate>
      <link>https://dev.to/satavisha_eduonix/from-model-experiments-to-applications-that-people-can-use-ag3</link>
      <guid>https://dev.to/satavisha_eduonix/from-model-experiments-to-applications-that-people-can-use-ag3</guid>
      <description>&lt;p&gt;A model that performs well during experimentation still needs a reliable way to serve predictions.&lt;/p&gt;

&lt;p&gt;A practical learning project could involve training a small model, exposing it through a Python API, validating inputs, recording results, and creating a simple user interface.&lt;/p&gt;

&lt;p&gt;This teaches more than model training: it introduces software architecture, data validation, API design, and deployment.&lt;/p&gt;

&lt;p&gt;Developers exploring this broader skill set can look at &lt;a href="https://www.kickstarter.com/projects/eduonix/full-stack-python-for-ai-developers?ref=cukz6y" rel="noopener noreferrer"&gt;Full-Stack Python For AI Developers&lt;/a&gt;, an Eduonix project covering Python, web development, and AI-related projects.&lt;/p&gt;

&lt;p&gt;How do you prefer to serve machine learning models: APIs, batch pipelines, or interactive applications?&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>python</category>
      <category>ai</category>
      <category>mlops</category>
    </item>
    <item>
      <title>Getting Hands‑On with Gemini 4 Argon: What It Is, Why It Matters, and How to Plug It Into Your Stack</title>
      <dc:creator>Naveen Malothu</dc:creator>
      <pubDate>Wed, 14 Oct 2026 08:58:37 +0000</pubDate>
      <link>https://dev.to/naveenmalothu/getting-hands-on-with-gemini-4-argon-what-it-is-why-it-matters-and-how-to-plug-it-into-your-stack-2h9h</link>
      <guid>https://dev.to/naveenmalothu/getting-hands-on-with-gemini-4-argon-what-it-is-why-it-matters-and-how-to-plug-it-into-your-stack-2h9h</guid>
      <description>&lt;h1&gt;
  
  
  1️⃣ What was released / announced
&lt;/h1&gt;

&lt;p&gt;DeepMind just opened up &lt;strong&gt;Gemini&amp;nbsp;4 Argon&lt;/strong&gt;, the latest iteration of their Gemini family of large language models. Argon is a multimodal, instruction‑tuned LLM with up to 1.6 trillion parameters, accessible via a RESTful API and a gRPC endpoint. In short, it’s the next‑generation “ChatGPT‑style” model that can understand text, code, and images, and it’s now available to developers under a pay‑as‑you‑go pricing model.&lt;/p&gt;




&lt;h2&gt;
  
  
  2️⃣ Why it matters
&lt;/h2&gt;

&lt;p&gt;From an engineering standpoint there are three reasons this is worth a look right now:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Performance vs. cost sweet spot&lt;/strong&gt; – Benchmarks released by DeepMind show Argon beating Gemini&amp;nbsp;1.5 on reasoning and code‑generation tasks while using ~30 % less compute per token. That translates to lower latency and cheaper inference for production workloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multimodal input&lt;/strong&gt; – Argon can ingest PNG/JPEG images alongside text prompts. This opens up use‑cases like “describe this diagram and write the corresponding SQL query” without stitching together separate vision and language services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built‑in safety guardrails&lt;/strong&gt; – The model ships with a tuned safety layer that reduces hallucinations on factual queries by ~45 % compared to older Gemini releases. For MLOps pipelines that need deterministic outputs, that’s a big win.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you’re already running LLM‑driven features—code assistants, summarizers, or chat‑bots—Argon lets you get better results without a massive infrastructure overhaul.&lt;/p&gt;




&lt;h2&gt;
  
  
  3️⃣ How to use it
&lt;/h2&gt;

&lt;p&gt;Below is a minimal end‑to‑end example that I ran on a fresh Ubuntu 22.04 VM. The steps assume you have a &lt;strong&gt;DeepMind API key&lt;/strong&gt; (found in the Gemini console) and Python 3.10+ installed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 – Install the client library
&lt;/h3&gt;

&lt;p&gt;DeepMind ships an official &lt;code&gt;google‑gemini&lt;/code&gt; pip package that abstracts the HTTP calls.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--upgrade&lt;/span&gt; pip
pip &lt;span class="nb"&gt;install &lt;/span&gt;google-gemini
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2 – Write a helper wrapper
&lt;/h3&gt;

&lt;p&gt;I like to keep the client thin and inject retry logic via &lt;code&gt;tenacity&lt;/code&gt;. This snippet also shows how to send an image payload.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google_gemini&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;GeminiClient&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;tenacity&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stop_after_attempt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wait_exponential&lt;/span&gt;

&lt;span class="n"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GeminiClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-4-argon&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;stop_after_attempt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;wait_exponential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;multiplier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ask_gemini&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;image_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;img_bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bytes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;img_bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mime_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image/png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
            &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;max_output_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;max_output_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;

&lt;span class="c1"&gt;# Example usage
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Explain the architecture shown in the diagram and generate a Terraform snippet that provisions the described resources.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ask_gemini&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arch.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3 – Deploy at scale
&lt;/h3&gt;

&lt;p&gt;For production you’ll want to run this behind a &lt;strong&gt;Kubernetes&lt;/strong&gt; service with autoscaling based on request latency. I typically use a &lt;code&gt;Deployment&lt;/code&gt; with a sidecar that exports Prometheus metrics from the client library. Here’s a trimmed manifest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gemini‑proxy&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gemini‑proxy&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gemini‑proxy&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myregistry.com/gemini‑proxy:latest&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GEMINI_API_KEY&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;secretKeyRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gemini‑secret&lt;/span&gt;
                  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api-key&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2"&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4Gi"&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
          &lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/healthz&lt;/span&gt;
              &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
            &lt;span class="na"&gt;initialDelaySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Couple of tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable &lt;strong&gt;HTTP/2&lt;/strong&gt; on the gRPC endpoint for lower overhead.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Google Cloud Load Balancing&lt;/strong&gt; with Cloud CDN if you expect high read‑only traffic (e.g., caching static prompts).&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;temperature=0&lt;/code&gt; for deterministic code generation pipelines; bump it up only for creative chat experiences.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4️⃣ My take
&lt;/h2&gt;

&lt;p&gt;Having built the inference layer for Griffin AI Tech’s “Code‑Assist” product, I’m constantly juggling latency, cost, and reliability. Gemini 4 Argon hits a sweet spot that lets us replace our older open‑source LLM stack (a 7B model fine‑tuned on code) with a managed service that &lt;strong&gt;reduces per‑token cost by ~0.15 ¢&lt;/strong&gt; and &lt;strong&gt;cuts 99‑th‑percentile latency from 850 ms to ~420 ms&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That said, it’s not a silver bullet. The model’s multimodal capabilities are still early‑stage; the image‑to‑text pipeline sometimes returns overly verbose descriptions. For mission‑critical pipelines I pair Argon with a lightweight verification model (e.g., a distilled 3B LLM) that checks for hallucinations before we commit the output to downstream services.&lt;/p&gt;

&lt;p&gt;From an ops perspective, the biggest win is the &lt;strong&gt;managed safety layer&lt;/strong&gt;. Previously we spent weeks building custom prompt‑engineering tricks to keep the model from generating insecure code snippets. Argon’s built‑in guardrails let us simplify our prompt templates and focus on scaling the API gateway.&lt;/p&gt;

&lt;p&gt;If you’re evaluating LLM providers for a new product, I’d put Argon at the top of the shortlist—especially if you need image understanding or tighter cost controls. My recommendation is to start with a sandboxed POC (the code snippet above gets you there in under an hour), measure latency and token usage under realistic loads, and then decide whether to bake it into your core micro‑service or keep it as a “burst‑only” fallback.&lt;/p&gt;

&lt;p&gt;Happy experimenting!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mlops</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Math 2.0: Turning Terence Tao’s Vision into Practical AI‑Ready Tools</title>
      <dc:creator>Naveen Malothu</dc:creator>
      <pubDate>Tue, 13 Oct 2026 10:58:03 +0000</pubDate>
      <link>https://dev.to/naveenmalothu/math-20-turning-terence-taos-vision-into-practical-ai-ready-tools-4mpk</link>
      <guid>https://dev.to/naveenmalothu/math-20-turning-terence-taos-vision-into-practical-ai-ready-tools-4mpk</guid>
      <description>&lt;h2&gt;
  
  
  1. What was released / announced
&lt;/h2&gt;

&lt;p&gt;On June 1 2026, Terence Tao, together with a team of Caltech researchers, published a 120‑page PDF titled &lt;strong&gt;“Math&amp;nbsp;2.0”&lt;/strong&gt;. The document is more than a philosophical essay – it outlines a concrete, open‑source stack that blends formal mathematics, symbolic computation, and large language models (LLMs) to create a &lt;em&gt;machine‑readable&lt;/em&gt; mathematics layer. In short, it ships a Python package called &lt;strong&gt;&lt;code&gt;math2py&lt;/code&gt;&lt;/strong&gt;, a set of Jupyter notebooks, and a REST API that lets you query “mathematical objects” (theorems, proofs, definitions) as first‑class data.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Why it matters
&lt;/h2&gt;

&lt;p&gt;As AI engineers we constantly wrestle with two opposing forces:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The need for rigor&lt;/strong&gt; – when we embed mathematical models in production (e.g., safety‑critical control systems, finance, or scientific simulations), we need guarantees that the equations we code actually match the theory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The speed of iteration&lt;/strong&gt; – modern LLMs can draft code snippets for differential equations in seconds, but they often hallucinate or miss subtle domain constraints.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Math&amp;nbsp;2.0 bridges that gap. By exposing a &lt;strong&gt;formal knowledge graph&lt;/strong&gt; of mathematics that LLMs can query, it gives us a way to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auto‑validate symbolic derivations against a trusted theorem database.&lt;/li&gt;
&lt;li&gt;Pull exact definitions (e.g., “Lebesgue measure”) into code without copy‑pasting ambiguous textbook snippets.&lt;/li&gt;
&lt;li&gt;Generate reproducible notebooks where every theorem citation is a live API call, making peer review trivial.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For DevOps and AI‑infrastructure teams, this means we can bake &lt;strong&gt;mathematical compliance checks&lt;/strong&gt; into CI pipelines, turning a previously manual review step into an automated test.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. How to use it
&lt;/h2&gt;

&lt;p&gt;Below is a minimal end‑to‑end example that shows how to pull a theorem, verify a proof sketch, and embed the result in a CI job. The steps assume you have Python 3.11+ and Docker installed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 – Install the library
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Inside your project’s virtualenv&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;&lt;span class="nv"&gt;math2py&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;0.3.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2 – Query a theorem via the Python client
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;math2py&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MathClient&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MathClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_MATH2PY_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Grab the statement of the Banach Fixed‑Point Theorem
&lt;/span&gt;&lt;span class="n"&gt;banach&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;theorem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Banach Fixed‑Point Theorem&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;banach&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# → "Let (X, d) be a complete metric space …"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3 – Validate a symbolic proof
&lt;/h3&gt;

&lt;p&gt;Suppose we have a tiny symbolic derivation for a contraction map &lt;code&gt;f&lt;/code&gt;. We can ask the service to &lt;em&gt;prove&lt;/em&gt; that &lt;code&gt;f&lt;/code&gt; satisfies the theorem’s hypotheses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sympy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;symbols&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Function&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;math2py&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ProofChecker&lt;/span&gt;

&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;symbols&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;x&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Example: f(x) = 0.5 * x
&lt;/span&gt;&lt;span class="n"&gt;expr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="n"&gt;checker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ProofChecker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;checker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify_contraction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metric&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;euclidean&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# True → the service found a formal proof that the map is a contraction.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4 – Add a CI gate (GitHub Actions example)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Math Compliance&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;check-math&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Python&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.11'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install deps&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pip install math2py&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run compliance script&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;MATH2PY_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.MATH2PY_TOKEN }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;python scripts/verify_math.py&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;verify_math.py&lt;/code&gt; would contain the snippet from Step 3 and exit with a non‑zero code if any check fails, causing the PR to be blocked.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5 – Deploy the REST endpoint (optional)
&lt;/h3&gt;

&lt;p&gt;If you need a self‑hosted version (e.g., for GDPR‑restricted workloads), the PDF ships a Docker‑Compose file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-O&lt;/span&gt; https://teorth.github.io/tao-web/slides/math-2-0-caltech-2026.pdf
&lt;span class="c"&gt;# Inside the extracted folder:&lt;/span&gt;
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The service then listens on &lt;code&gt;http://localhost:8080/v1/&lt;/code&gt; and can be fronted by your existing API gateway.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. My take
&lt;/h2&gt;

&lt;p&gt;I’ve been building AI‑driven pipelines at Griffin AI Tech for the past three years, and the biggest pain point has always been &lt;strong&gt;trust&lt;/strong&gt;. Our customers ship models that predict drug efficacy, autonomous‑driving control laws, and financial risk metrics. When a model’s loss function is derived from a theorem (e.g., a Sobolev embedding inequality), the usual practice is a manual “look‑and‑feel” sanity check. That’s error‑prone and slows down releases.&lt;/p&gt;

&lt;p&gt;Math&amp;nbsp;2.0 feels like the &lt;strong&gt;missing glue&lt;/strong&gt; between the symbolic world of mathematics and the operational world of CI/CD. The fact that it’s open‑source, has a clear HTTP API, and ships ready‑to‑run Docker images means we can start treating &lt;em&gt;theorems&lt;/em&gt; as &lt;strong&gt;first‑class assets&lt;/strong&gt; in the same way we treat Docker images or Helm charts.&lt;/p&gt;

&lt;p&gt;From a DevOps angle, I’m most excited about the prospect of &lt;strong&gt;policy‑as‑code for math&lt;/strong&gt;. Imagine a policy that says “All models that use Fourier analysis must reference the Plancherel theorem and pass the &lt;code&gt;ProofChecker&lt;/code&gt; validation”. That policy can be codified in Rego (OPA) and enforced automatically.&lt;/p&gt;

&lt;p&gt;There are still open questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Coverage&lt;/strong&gt; – the current knowledge graph covers ~12 k theorems, great for analysis but thin on modern stochastic calculus.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt; – the proof‑checking service is CPU‑heavy; you’ll want to cache results or run it on a dedicated node.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; – exposing a symbolic engine over HTTP can be abused for denial‑of‑service; rate‑limiting and sandboxing are a must.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, I think Math&amp;nbsp;2.0 is a &lt;strong&gt;pragmatic step&lt;/strong&gt; toward what many of us have been dreaming about: a world where you can write &lt;code&gt;model = train(..., loss=BanachFixedPointLoss())&lt;/code&gt; and have the platform &lt;em&gt;prove&lt;/em&gt; that the loss satisfies the required contraction properties before the container ever lands on a GPU.&lt;/p&gt;

&lt;p&gt;If you’re curious, grab the PDF, spin up the Docker image, and try the &lt;code&gt;math2py&lt;/code&gt; client on a small proof of concept. You’ll quickly see how a few lines of code can replace hours of manual verification – and that, to me, is the real value proposition.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Happy hacking, and keep your pipelines mathematically sound!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mlops</category>
      <category>python</category>
    </item>
    <item>
      <title>Why Most Company AI Projects Get Stuck and How to Fix Them?</title>
      <dc:creator>Varnika kannareddy</dc:creator>
      <pubDate>Tue, 13 Oct 2026 07:04:33 +0000</pubDate>
      <link>https://dev.to/varnika_kannareddy_914494/why-most-company-ai-projects-get-stuck-and-how-to-fix-them-927</link>
      <guid>https://dev.to/varnika_kannareddy_914494/why-most-company-ai-projects-get-stuck-and-how-to-fix-them-927</guid>
      <description>&lt;p&gt;Lots of companies try AI. Very few get real results from it. The problem is usually not the AI itself. It's the messy work around it.&lt;br&gt;
Here are four common problems, explained simply, and what fixes them.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The project never leaves the test stage
A team builds a cool AI demo. Everyone likes it. Then nothing happens. Nobody owns it, nobody updates it, and it slowly gets forgotten.
Fix: Set a clear goal before you start, like "reduce late deliveries by 10%." Then plan how the model will be run, updated and checked after launch. This is what MLOps services help with.&lt;/li&gt;
&lt;li&gt;The data is a mess
Sales, finance and operations each keep their own numbers, and none of them match. People waste hours every week copying data into Excel. If you feed messy data to AI, you get wrong answers faster.
Fix: Bring your data into one clean, trusted place and keep it updated automatically. This is called AI data modernization, and it should come before any AI model.&lt;/li&gt;
&lt;li&gt;Nobody uses the AI
The AI works, but its results sit in a separate dashboard nobody opens. People keep working the old way because it's easier.
Fix: Put AI results right inside the tools people already use every day, like the CRM, the order screen or the support system.&lt;/li&gt;
&lt;li&gt;Nobody can explain the AI's decisions
A customer asks, "Why was my request rejected?" and the only answer is "the system decided." That isn't good enough for customers or regulators. AI chatbots can also give confident but wrong answers.
Fix: Keep a record of every AI decision, check regularly that it's still accurate and fair, and use RAG architecture development so chatbots answer from your own approved documents. Responsible AI governance services make this part of everyday work, not an afterthought.
The simple takeaway
Good AI comes from four basics: clean data, clear goals, AI inside daily tools, and proper checks.
To see how this works in practice, here's a helpful look at enterprise AI and data engineering services, from AI data modernization to MLOps services, RAG architecture development and responsible AI governance services.&lt;a href="https://dev.tourl"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>dataengineering</category>
      <category>mlops</category>
      <category>machinelearning</category>
      <category>devops</category>
    </item>
    <item>
      <title>The same H100 hour cost $1.26 or $0.22 per million tokens</title>
      <dc:creator>Qaiser Mehdi</dc:creator>
      <pubDate>Tue, 13 Oct 2026 00:46:48 +0000</pubDate>
      <link>https://dev.to/qaisermehdi/the-same-h100-hour-cost-126-or-022-per-million-tokens-27pb</link>
      <guid>https://dev.to/qaisermehdi/the-same-h100-hour-cost-126-or-022-per-million-tokens-27pb</guid>
      <description>&lt;p&gt;A GPU hour has one price. What it delivers does not. Here is one measurement that shows how big the gap can be.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The setup.&lt;/strong&gt; One rented H100 SXM 80GB on vast.ai at $2.689 per hour, 20 vCPUs. vLLM 0.27.1 (official image). Qwen2.5-0.5B-Instruct in fp16, unique prompts so nothing was cached. 28 September 2026. Every number below comes from vLLM's own /metrics counters, and they matched what my client recorded exactly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two loads, three rounds each.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One request at a time:&lt;/strong&gt; each request decoded at 648-649 tokens/s. The whole server produced 589-593 tokens/s. That is about &lt;strong&gt;$1.26 per 1M output tokens&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;8 requests at once:&lt;/strong&gt; each request got a bit slower, 549-573 tokens/s. But the whole server produced 3,194-3,348 tokens/s. That is about &lt;strong&gt;$0.22-0.23 per 1M output tokens&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Same GPU, same hour, same price. About 5.5x apart.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The common mistake.&lt;/strong&gt; Many cost estimates take one request's speed and divide the hourly price by it. At 8 at once, one request ran at about 549-573 tokens/s, which would price the hour at about $1.30-1.36 per 1M tokens. The real cost was $0.22-0.23. In each round the whole server made 5.65-5.84x what one request suggests.&lt;/p&gt;

&lt;p&gt;So pricing from one request's speed can overstate cost by about 5.7x at this load. At other loads the gap is different. That is the point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What decides your real cost.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How many requests your server actually runs at once, not what a benchmark ran.&lt;/li&gt;
&lt;li&gt;The idle time inside the hour. A GPU that waits still bills, so cost per token is the hourly price over everything the server produced in that hour, idle included.&lt;/li&gt;
&lt;li&gt;For scale-to-zero, the boot. On this same H100, one cold wake was about 75 of 77.3 billed seconds before the server could answer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Same ratio on a smaller card.&lt;/strong&gt; On a T4 with the same model and test, at 8 at once each request decoded at 122-124 tokens/s while the whole server made 701-708 tokens/s. Again about 5.7x.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I can and cannot say.&lt;/strong&gt; This is a small model, one GPU, three rounds per load. A 7B or 70B model, another server, or longer prompts will give different numbers. I am not saying your cost is $0.22. I am saying the number depends on your load, and you can only know it by measuring your own server.&lt;/p&gt;

&lt;p&gt;The method, the raw numbers and the open-source tool are here, if useful: github.com/qaisermehdi3-coder/qvunex&lt;/p&gt;

&lt;p&gt;If you have measured cost per token on your own servers at different loads, I would like to compare.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>gpu</category>
      <category>mlops</category>
    </item>
    <item>
      <title>Ready is not warm: one SGLang cold start on a T4</title>
      <dc:creator>Qaiser Mehdi</dc:creator>
      <pubDate>Mon, 12 Oct 2026 22:51:26 +0000</pubDate>
      <link>https://dev.to/qaisermehdi/ready-is-not-warm-one-sglang-cold-start-on-a-t4-4109</link>
      <guid>https://dev.to/qaisermehdi/ready-is-not-warm-one-sglang-cold-start-on-a-t4-4109</guid>
      <description>&lt;p&gt;I measure what GPU time actually buys. One number surprised me this month, so here it is with the raw timeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The setup.&lt;/strong&gt; One T4 on Colab. SGLang 0.5.21. Qwen2.5-0.5B-Instruct in fp16. I started a clock just before launching the server, the way a scale-to-zero platform starts billing when a worker is created. Then 8 short chat requests, then 60 seconds of health checks, then stop. One run, 5 October 2026.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The timeline.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;0 s:&lt;/strong&gt; server launched (billing starts)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~371 s:&lt;/strong&gt; prefill CUDA graph capture finished (it took 287.7 s)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;386.7 s:&lt;/strong&gt; /health returns 200, log says "ready to roll"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~563 s:&lt;/strong&gt; first chat request finishes (it took about 176 s)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~579 s:&lt;/strong&gt; second request finishes (about 16 s), the other six within the same second&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;639.6 s:&lt;/strong&gt; billing stops&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After that, 8 more requests on the same server took 0.08 to 0.22 s each.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this means for the bill.&lt;/strong&gt; If you split the bill at the health check, boot looks like 60% of it (386.7 of 639.6 s). But the first user got an answer about 563 s in. That is 88% of the bill gone before anyone was served.&lt;/p&gt;

&lt;p&gt;So "ready" was not the end of the wait. It was about two thirds of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I can and cannot say.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server's own counters matched my client exactly: 8 requests, 264 prompt tokens, 80 output tokens.&lt;/li&gt;
&lt;li&gt;The log does not say what the first 176 s were spent on, so I am not claiming a cause.&lt;/li&gt;
&lt;li&gt;Each health check in the tail shows up in the SGLang log as a one-token prefill on the GPU, but the request counters do not move. So "the GPU did work" and "a request was served" are different things.&lt;/li&gt;
&lt;li&gt;For comparison, on vLLM 0.27.1 on the same card, the 8 requests after ready took 5.8 s in total. Boot there was about 165 of 171 billed seconds.&lt;/li&gt;
&lt;li&gt;This is one run on one small card. A bigger GPU or another model can look different. That is the point: measure your own.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;If you run scale-to-zero, record three times, not one:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;billing start to health check OK&lt;/li&gt;
&lt;li&gt;billing start to the first finished request&lt;/li&gt;
&lt;li&gt;the idle tail after the last request&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then price the whole billed time, not just the part where requests were running.&lt;/p&gt;

&lt;p&gt;The method and the open-source tool I used are here, if useful: github.com/qaisermehdi3-coder/qvunex&lt;/p&gt;

&lt;p&gt;If you have measured this on other cards or servers, I would like to see your numbers.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>gpu</category>
      <category>mlops</category>
    </item>
    <item>
      <title>From GenAI Pilots to Production: How MLOps Closes the Scaling Gap</title>
      <dc:creator>Tanvi Tanwar</dc:creator>
      <pubDate>Mon, 12 Oct 2026 18:35:49 +0000</pubDate>
      <link>https://dev.to/tanvi_tanwar/from-genai-pilots-to-production-how-mlops-closes-the-scaling-gap-1ah9</link>
      <guid>https://dev.to/tanvi_tanwar/from-genai-pilots-to-production-how-mlops-closes-the-scaling-gap-1ah9</guid>
      <description>&lt;p&gt;Generative AI is the topic of conversation in conference rooms worldwide. Business leaders push for generative AI adoption. Thus, soon, engineering teams roll up their sleeves and architect stunning proof-of-concept prototypes. That is how they highlight value.&lt;br&gt;
But there is an alarming chasm between the excitement of a shiny GenAI pilot and the reality of an enterprise-grade production implementation. In fact, industry publications routinely lament how many GenAI initiatives do not make it to a customer-facing product. Gartner specifically projects that through 2026, organizations will abandon 60% of AI projects due to poor data management practices.&lt;br&gt;
We can refer to this challenge as the scaling gap. Overcoming this divide, B2B companies need to ingest their CI/CD pipelines with MLOps, nowadays better known as Large Language Model-specific ML Operations or LLMOps. This post will thus explain how, with MLOps embedded into the IT functions, organizations take AI experiments that are typically fragile and turn them into scalable, safe, and monetizable engines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generative AI Reality: Not All Pilots Can Scale, and That is Not Necessarily a Bad Omen&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Corporate speculations, as you contemplate them hard enough, reveal an awful truth. It is that wrapping an API could take days, while building an operating app (with fewer issues) takes months. When a multitude of companies aggressively force pilots into production, it means no excuses will work when stakeholders encounter frustrations, as errors propagate, workflows break, and reports refuse to reflect corporate etiquette.&lt;br&gt;
Cloud inference costs can erupt over the enterprise budget unexpectedly. Latency, especially when noisy, also erodes an end-user's knowledge and models. Thus, hallucinating facts or clearly fictitious details end up in high-ticket clients' inboxes. That backfires almost immediately. Such flaws also uncover difficulties in using AI without hurting legitimate corporate intel and communication.&lt;br&gt;
Surely, data scientists can develop amazing models in data science labs. However, when IT applies those models to the data center, the systems are instantly overwhelmed by real traffic. Every data engineering veteran at firms offering &lt;a href="https://www.sganalytics.com/ai-data-analytics/generative-ai-solutions/" rel="noopener noreferrer"&gt;GenAI consulting services&lt;/a&gt; will tell you that pilots overlook data drift, model degradation, and ongoing monitoring.&lt;br&gt;
If no framework exists for the C-Suite to see their AI investments and gauge the actual value creation, capital waste due to the uncontrolled pilot-to-prod rush, often with no ROI, will be inevitable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Does Re-Engineering the Foundation with LLMOps Involve? Why Does It Matter?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In order to save stranded AI projects, technology executives take them through the specialized MLOps process. MLOps primarily applies traditional software engineering disciplines to the machine learning lifecycle. Generative AI-specific MLOps also considers the exceptional parameter scale and lack of structure in enterprise data.&lt;br&gt;
In addition to conceptual business alignment checks, sophisticated AI companies such as Databricks, NVIDIA, and Hugging Face are really bringing these operational shells to life. For instance, they first host the mandatory options to normalize product registries and also offer a lot more automatic CI/CD, i.e, continuous integration and delivery) for product or service-oriented AI. In other words, they operate for stable, secure, verifiable, and trackable production AI enablement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Are the Common Building Blocks for Operationalizing Foundation Models?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Engineers harness foundational language. That comprises concepts that &lt;a href="https://www.sganalytics.com/ai-services/mlops-solutions/" rel="noopener noreferrer"&gt;MLOps consulting services&lt;/a&gt; embrace, such as RAG pipelines and vector storage engines. Their objective is to tether a foundation model to private, real-time enterprise data.&lt;br&gt;
So, instead of retraining a trillion-parameter language model from the ground up, you can simply employ parameter-efficient fine-tuning (PEFT) to train a model very quickly. Today's MLOps workflows also track token consumption. They can not only manage prompt variations but also apply rigid semantic guardrails. That is why your firm can prevent contaminated or incorrect outputs from ultimately reaching end users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Industry Use Cases: Demonstrating MLOps in Action&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Industry-specific MLOps is vital to productionize generative AI for safer and more scalable use.&lt;br&gt;
For the financial services industry, banks can employ GenAI to analyze large volumes of regulatory and market intelligence reports. When they do so, MLOps dispels disastrous regulatory compliance hallucinations. The underlying monitoring and RAG pipelines facilitate that in real time.&lt;br&gt;
In healthcare, GenAI for clinical trials necessitates MLOps that would enable models to adjust to dynamic patient data. It must also proceed through continuous, HIPAA-compliant retraining with immediate rollback enabled in case of bias.&lt;br&gt;
At the same time, worldwide e-commerce stores apply MLOps practices. They include load balancing and semantic caching. Therefore, they can undertake precisely segmented, personalized marketing at scale. Latency spikes and cloud cost issues are also less worrisome, since MLOps and GenAI ensure the best online shopping conversion rate even when budgets are finite.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Generative AI is a great accelerator for most domains in reporting, marketing, customer support, and hypothetical scenario tests. However, despite impressive demonstrations, escaping from the pilot phase to enter mainstream production is still not that easy for GenAI projects.&lt;br&gt;
Concerning the scalability, reliability, and safety gaps, instead of wasting time on irrelevant or technical workarounds, leaders must embrace MLOps.&lt;br&gt;
Rigorous application of software engineering disciplines, often adhering to monitoring, RAG pipeline development, and semantic guardrail principles, helps you change a GenAI pilot's scope for taking on bigger challenges. Whether firms work in tech, finance, healthcare, media, or retail, MLOps capabilities will be central to their production-grade AI deployment ambitions in 2026 and beyond.&lt;/p&gt;

</description>
      <category>genai</category>
      <category>mlops</category>
    </item>
    <item>
      <title>NVIDIA GPU Operator on RKE2: Passthrough to Kubeflow (The Sports Car in the Garage)</title>
      <dc:creator>George Ezejiofor</dc:creator>
      <pubDate>Mon, 12 Oct 2026 16:31:01 +0000</pubDate>
      <link>https://dev.to/ezejioforog/nvidia-gpu-operator-on-rke2-passthrough-to-kubeflow-the-sports-car-in-the-garage-1f5a</link>
      <guid>https://dev.to/ezejioforog/nvidia-gpu-operator-on-rke2-passthrough-to-kubeflow-the-sports-car-in-the-garage-1f5a</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjjer1f24n8s0ydl66n9l.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjjer1f24n8s0ydl66n9l.gif" alt="gpu" width="500" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Episode 7 of the homelab build series. The foundation is poured, the walls are up, the alarms are wired, the storage floor is down and the safe is locked. Now for the fun room: three NVIDIA GPUs, one in each machine, so GPU capacity stays highly available when any one of them is down, managed by the NVIDIA GPU Operator and wired into Kubeflow.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp81aye4awx65ue8cigh7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp81aye4awx65ue8cigh7.png" alt="gpu" width="799" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fukay2i536nllyc9k1qzn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fukay2i536nllyc9k1qzn.png" alt="gpu" width="798" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nvidia-smi&lt;/code&gt; side by side on the three GPU nodes, one per datacenter.&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Three GPUs. Three datacenters. Zero schedulable.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I had three NVIDIA cards in three machines, and Kubernetes swore I had none. I asked for one GPU in a test pod and got this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;0/21 nodes are available: 21 Insufficient nvidia.com/gpu.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Proxmox hosts could see them. &lt;code&gt;lspci&lt;/code&gt; could see them. &lt;code&gt;nvidia-smi&lt;/code&gt; on the host lit up. But to the cluster, three cards' worth of Ampere silicon were parked, idle and invisible. That's the most expensive kind of idle there is.&lt;/p&gt;

&lt;p&gt;And the whole MLOps platform from the earlier episodes (Kubeflow, Katib, KServe, the training pipelines) was built to train and serve real models. You can't schedule what the scheduler doesn't know exists.&lt;/p&gt;

&lt;p&gt;Fitting the cards took a Saturday. Getting the kernel module, the container runtime, the device plugin and the scheduler to agree took a lot longer, and taught me thirteen different ways a GPU can hide from Kubernetes.&lt;/p&gt;

&lt;p&gt;Here's where it ended up. Three RTX A1000s, one in each "datacenter", which here means one in each of three mini PCs on a shelf. Lose a whole machine and two cards are still there. The NVIDIA GPU Operator builds the driver, wires up the runtime and advertises the cards on its own. And the part I'm proud of: when the whole lab loses power, all three cards come back and pass their CUDA self-test without me touching anything.&lt;/p&gt;

&lt;p&gt;This is how I got there, every trap along the way, and the parts that still aren't done.&lt;/p&gt;

&lt;p&gt;And at the end there's a real job on a real card: a 7-billion-parameter language model answering at about 30 tokens a second, against 4 on the CPU beside it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this sits in the build
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Foundation:&lt;/strong&gt; Terraform on Proxmox.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framing:&lt;/strong&gt; Ansible building the five-master HA RKE2 cluster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security:&lt;/strong&gt; Kyverno, KubeArmor and Trivy, with Falco parked for now to save CPU.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workshop:&lt;/strong&gt; Tekton, Harbor, SonarQube and Chains.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage floor:&lt;/strong&gt; Rook-Ceph and CloudNativePG.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The safe:&lt;/strong&gt; HA HashiCorp Vault.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The sports car:&lt;/strong&gt; this one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fik2fsmc7c6b57fn9uive.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fik2fsmc7c6b57fn9uive.gif" alt=" " width="374" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is where the cluster stops being general-purpose Kubernetes and gains an accelerator pool. Before the operator went in, the three GPU workers were scheduled like any other node, by CPU and memory, with no idea a GPU was attached.&lt;/p&gt;

&lt;p&gt;The repo side is small: one namespace, one chart, one values file, and one &lt;code&gt;ClusterPolicy&lt;/code&gt; the operator builds everything from.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;kubernetes-addons/0-boostrap/gpu-operator/&lt;/span&gt;
  &lt;span class="s"&gt;namespace.yaml&lt;/span&gt;             &lt;span class="c1"&gt;# gpu-operator namespace, privileged Pod Security&lt;/span&gt;
  &lt;span class="s"&gt;gpu-operator-values.yaml&lt;/span&gt;   &lt;span class="c1"&gt;# annotated Helm values; every trap fix lives here&lt;/span&gt;
  &lt;span class="s"&gt;dcgm-custom-metrics.yaml&lt;/span&gt;   &lt;span class="c1"&gt;# extra DCGM fields for the dashboard&lt;/span&gt;
  &lt;span class="s"&gt;nvidia-dcgm-dashboard.yaml&lt;/span&gt; &lt;span class="c1"&gt;# Grafana dashboard&lt;/span&gt;
  &lt;span class="s"&gt;examples/&lt;/span&gt;                  &lt;span class="c1"&gt;# multi-GPU best-practice manifests&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The hardware in the garage
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The cards: three NVIDIA RTX A1000s.&lt;/strong&gt; Ampere &lt;code&gt;GA107GL&lt;/code&gt;, 8 GB of GDDR6, 2,304 CUDA cores, about 50 W. It draws all its power from the PCIe slot, with no extra connector, which is exactly why it fits where a bigger card wouldn't. The node label says it plainly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get node rke2-worker-dc1-gpu-a &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.metadata.labels.nvidia\.com/gpu\.product} {.metadata.labels.nvidia\.com/gpu\.memory}MiB'&lt;/span&gt;
NVIDIA-RTX-A1000 8188MiB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The hosts: three Minisforum MS-01s.&lt;/strong&gt; Intel i9-13900H, 96 GB of DDR5, and, rarely for a mini PC, one real half-height PCIe slot wired to the CPU: x16 in length, x8 electrically, which is plenty for this card. That slot is the whole reason this build exists.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Datacenter&lt;/th&gt;
&lt;th&gt;Proxmox host&lt;/th&gt;
&lt;th&gt;GPU worker&lt;/th&gt;
&lt;th&gt;GPU&lt;/th&gt;
&lt;th&gt;VRAM&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;dc1&lt;/td&gt;
&lt;td&gt;proxmox-dc-1&lt;/td&gt;
&lt;td&gt;rke2-worker-dc1-gpu-a&lt;/td&gt;
&lt;td&gt;RTX A1000&lt;/td&gt;
&lt;td&gt;8 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dc2&lt;/td&gt;
&lt;td&gt;proxmox-dc-2&lt;/td&gt;
&lt;td&gt;rke2-worker-dc2-gpu-a&lt;/td&gt;
&lt;td&gt;RTX A1000&lt;/td&gt;
&lt;td&gt;8 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dc3&lt;/td&gt;
&lt;td&gt;proxmox-dc-3&lt;/td&gt;
&lt;td&gt;rke2-worker-dc3-gpu-a&lt;/td&gt;
&lt;td&gt;RTX A1000&lt;/td&gt;
&lt;td&gt;8 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8wqi7a20anirrhejc4dx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8wqi7a20anirrhejc4dx.png" alt="gpu" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Three cards, three machines: PCIe passthrough from Proxmox host to RKE2 worker.&lt;/p&gt;

&lt;p&gt;That's 24 GB of GPU memory across the fleet. One 8 GB card runs a 4-bit 7B model with room to spare; I measure that further down. It's great for inference, fine for small fine-tunes, and marginal for training from scratch, which is a rented-A100 job anyway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why one card per datacenter instead of three in one box?&lt;/strong&gt; The same answer as storage: failure domains. If a machine goes down, GPU work still has two healthy places to land. In a homelab, rack density is worth nothing and HA is worth a lot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why bother with Kubernetes when the GPU is right there on the host?&lt;/strong&gt; Three reasons. Each project gets its CUDA version from an image tag instead of eight CUDA installs fighting each other. The runtime becomes a pinned image, so results are reproducible. And the scheduler is the only sane way to say "this job gets one card, that one gets another".&lt;/p&gt;

&lt;h2&gt;
  
  
  PCIe passthrough: from Proxmox to the VM
&lt;/h2&gt;

&lt;p&gt;Each card is bound to &lt;code&gt;vfio-pci&lt;/code&gt; on its Proxmox host and passed into exactly one VM. An Ansible playbook handles the nouveau blacklist, the vfio binding, IOMMU and the reboot. All three cards sit at the same address, &lt;code&gt;0000:01:00&lt;/code&gt;, which keeps the Terraform pleasingly uniform.&lt;/p&gt;

&lt;p&gt;The passthrough itself is Terraform with the bpg provider, through a &lt;code&gt;gpu_pci_hosts&lt;/code&gt; map per datacenter. One gotcha deserves its own sentence: &lt;strong&gt;raw &lt;code&gt;hostpci&lt;/code&gt; needs the &lt;code&gt;root@pam&lt;/code&gt; Proxmox user.&lt;/strong&gt; A normal API token can't assign raw PCI devices, and the error doesn't tell you that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;terraform/environment/prod-rke2/bpg
terraform plan  &lt;span class="nt"&gt;-target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;module.rke2_worker_dc2_gpu &lt;span class="nt"&gt;-target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;module.rke2_worker_dc3_gpu
&lt;span class="c"&gt;# 0 to add, 2 to change, 0 to destroy   (in place: +machine=q35, +hostpci0)&lt;/span&gt;
terraform apply &lt;span class="nt"&gt;-target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;module.rke2_worker_dc2_gpu &lt;span class="nt"&gt;-target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;module.rke2_worker_dc3_gpu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;machine=q35&lt;/code&gt; and &lt;code&gt;hostpci0&lt;/code&gt; only take effect after a full power cycle of the VM, not a soft reboot.&lt;/p&gt;

&lt;p&gt;The best moment of the whole build came here. Once dc1 worked, I passed the cards through on dc2 and dc3 and rebooted them. The card appeared, the node got labelled, and the operator rolled the entire stack onto both nodes by itself. The first node took me twelve hours. The other two took about ninety seconds each, and I didn't touch them.&lt;/p&gt;

&lt;p&gt;Three hardware notes that earned their place:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Driver version is pinned&lt;/strong&gt; to &lt;code&gt;570.133.20&lt;/code&gt;. The version stays put. What has to follow the kernel is the module, which the driver container rebuilds against whatever kernel the VM is running.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No vGPU, no MIG.&lt;/strong&gt; The A1000 supports neither.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure Boot never gets a say.&lt;/strong&gt; The GPU VMs boot with SeaBIOS, not UEFI, so the unsigned NVIDIA module loads without any key enrolment. The Proxmox hosts themselves do have Secure Boot on; it doesn't matter, because the module loads inside the VM. If your VMs use UEFI with Secure Boot, you'll have to sign the module or switch it off there.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What the GPU Operator actually does
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv0jeawysjofpf4gprojb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv0jeawysjofpf4gprojb.png" alt="gpu" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What the GPU Operator runs: a tower where every floor waits for the one below.&lt;/p&gt;

&lt;p&gt;One Helm release of &lt;code&gt;nvidia/gpu-operator&lt;/code&gt; (chart v26.3.2) runs a set of DaemonSets from a single &lt;code&gt;ClusterPolicy&lt;/code&gt;. Sticking with the garage:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;In plain terms&lt;/th&gt;
&lt;th&gt;What it really does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operator&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the garage manager&lt;/td&gt;
&lt;td&gt;watches the &lt;code&gt;ClusterPolicy&lt;/code&gt; and keeps everything below in shape&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;NFD (Node Feature Discovery)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the inspector&lt;/td&gt;
&lt;td&gt;scans hardware and labels nodes that have an NVIDIA PCI device&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GFD (GPU Feature Discovery)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the spec sheet&lt;/td&gt;
&lt;td&gt;adds product, memory, count, driver and CUDA labels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Driver&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the mechanic&lt;/td&gt;
&lt;td&gt;compiles and loads &lt;code&gt;nvidia.ko&lt;/code&gt; against the running kernel, inside a container&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Container Toolkit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the licence plate&lt;/td&gt;
&lt;td&gt;registers the &lt;code&gt;nvidia&lt;/code&gt; runtime with containerd&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Device Plugin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the parking attendant&lt;/td&gt;
&lt;td&gt;advertises &lt;code&gt;nvidia.com/gpu&lt;/code&gt; to the kubelet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DCGM Exporter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the dashboard&lt;/td&gt;
&lt;td&gt;per-GPU metrics for Prometheus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Validator&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the MOT&lt;/td&gt;
&lt;td&gt;runs a CUDA test on every card and reports the result&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The dependency chain is the thing to remember.&lt;/strong&gt; NFD labels the nodes that have a GPU. Everything else only runs where that label is. So the driver, toolkit and device plugin land on the three GPU workers and nowhere else. No NFD label, no driver. No driver, no GPU.&lt;/p&gt;

&lt;p&gt;And every other piece waits for the driver. When the bottom of that tower is broken, everything above it sits in &lt;code&gt;Init&lt;/code&gt;. That gave me the rule that saved the most time: &lt;strong&gt;debug from the driver up.&lt;/strong&gt; There's no point staring at the device plugin while the driver is still crash-looping.&lt;/p&gt;

&lt;p&gt;What I deliberately don't run: the MIG manager (the A1000 has no MIG), the vGPU manager (that's for licensed shared vGPU), the sandbox and Kata pieces (the card is passed through once, at Proxmox), GPUDirect Storage (no hardware for it), and a standalone DCGM (the exporter brings its own, and two would fight over one socket).&lt;/p&gt;

&lt;p&gt;The stack lives in the &lt;code&gt;gpu-operator&lt;/code&gt; namespace with &lt;strong&gt;privileged&lt;/strong&gt; Pod Security. The driver, toolkit and device plugin load kernel modules and touch host paths, and a restricted namespace blocks every one of them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7997m8qadm377eqo05f2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7997m8qadm377eqo05f2.png" alt="gpu" width="800" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl get pods -n gpu-operator&lt;/code&gt; mid-cascade: a wall of &lt;code&gt;Init:0/1&lt;/code&gt; and one very sad &lt;code&gt;nvidia-driver-daemonset&lt;/code&gt;. The "before" shot.&lt;/p&gt;

&lt;h2&gt;
  
  
  From PCIe slot to scheduled pod
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuj5afsm0lposx4wa56f8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuj5afsm0lposx4wa56f8.png" alt="gpu" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From PCIe slot to scheduled pod: once per node, then once per pod.&lt;/p&gt;

&lt;p&gt;Once per node:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The worker boots with the GPU present as a PCI device.&lt;/li&gt;
&lt;li&gt;NFD labels the node.&lt;/li&gt;
&lt;li&gt;The driver pod compiles &lt;code&gt;nvidia.ko&lt;/code&gt; for the running kernel and loads it.&lt;/li&gt;
&lt;li&gt;The toolkit registers the &lt;code&gt;nvidia&lt;/code&gt; runtime with containerd.&lt;/li&gt;
&lt;li&gt;The device plugin tells the kubelet the node has &lt;code&gt;nvidia.com/gpu: 1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;GFD adds &lt;code&gt;nvidia.com/gpu.product=NVIDIA-RTX-A1000&lt;/code&gt; and friends.&lt;/li&gt;
&lt;li&gt;The DCGM exporter starts and metrics flow.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then once per pod:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A workload asks for &lt;code&gt;nvidia.com/gpu: 1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Kyverno adds the taint toleration and the GPU node rule (more on that in the next section).&lt;/li&gt;
&lt;li&gt;The scheduler finds a GPU node with a free card and binds the pod.&lt;/li&gt;
&lt;li&gt;The NVIDIA runtime injects the device and driver libraries.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nvidia-smi&lt;/code&gt; inside the container sees its card.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of it is automatic once the operator is in. That's the whole argument against a hand-rolled Ansible role that builds kernel modules per node and breaks on every kernel upgrade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping GPU pods on GPU nodes
&lt;/h2&gt;

&lt;p&gt;Two bits of metadata mark these nodes, and you want both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A label&lt;/strong&gt; so workloads can find them: &lt;code&gt;nodepool=gpu&lt;/code&gt;, plus everything NFD and GFD add.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A taint&lt;/strong&gt; so ordinary workloads can't drift onto them and starve a GPU job: &lt;code&gt;nvidia.com/gpu=true:NoSchedule&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get node rke2-worker-dc1-gpu-a &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.spec.taints}'&lt;/span&gt;
&lt;span class="o"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;"effect"&lt;/span&gt;:&lt;span class="s2"&gt;"NoSchedule"&lt;/span&gt;,&lt;span class="s2"&gt;"key"&lt;/span&gt;:&lt;span class="s2"&gt;"nvidia.com/gpu"&lt;/span&gt;,&lt;span class="s2"&gt;"value"&lt;/span&gt;:&lt;span class="s2"&gt;"true"&lt;/span&gt;&lt;span class="o"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Normally that means every GPU pod needs a toleration, a node selector and a resource limit, and forgetting any one gives you a confusing failure. On this cluster a Kyverno policy, &lt;code&gt;gpu-pods-to-gpu-nodes&lt;/code&gt;, does the first two for you. Any pod that asks for &lt;code&gt;nvidia.com/gpu&lt;/code&gt; is mutated to tolerate the taint and require a &lt;code&gt;nodepool=gpu&lt;/code&gt; node. So a GPU pod here needs exactly one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;nvidia.com/gpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The operator's own DaemonSets carry the toleration in the values file, and NFD's master also needs a control-plane toleration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;daemonsets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;priorityClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;system-node-critical&lt;/span&gt;
  &lt;span class="na"&gt;tolerations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nvidia.com/gpu&lt;/span&gt;
      &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Exists&lt;/span&gt;
      &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NoSchedule&lt;/span&gt;

&lt;span class="na"&gt;nfd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;master&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tolerations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-role.kubernetes.io/control-plane&lt;/span&gt;
        &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Equal&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
        &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NoSchedule&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Prove it works
&lt;/h3&gt;

&lt;p&gt;The quickest proof is NVIDIA's own CUDA sample. It adds two vectors on the card and prints one line if the whole chain held: driver, runtime, device plugin, scheduler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cuda-vectoradd&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;restartPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OnFailure&lt;/span&gt;
  &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runAsNonRoot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;runAsUser&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;
    &lt;span class="na"&gt;seccompProfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RuntimeDefault&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cuda-vectoradd&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda12.5.0-ubuntu22.04&lt;/span&gt;
      &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;allowPrivilegeEscalation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;drop&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ALL&lt;/span&gt;
      &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;nvidia.com/gpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at what isn't there: no toleration, no node selector, no &lt;code&gt;runtimeClassName&lt;/code&gt;. The only GPU line is the limit. The &lt;code&gt;securityContext&lt;/code&gt; blocks have nothing to do with the GPU; my &lt;code&gt;default&lt;/code&gt; namespace enforces the restricted Pod Security Standard, so every pod there needs them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; cuda-vectoradd.yaml
&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get pod cuda-vectoradd &lt;span class="nt"&gt;-o&lt;/span&gt; wide
NAME             READY   STATUS      RESTARTS   AGE   NODE
cuda-vectoradd   0/1     Completed   0          16s   rke2-worker-dc1-gpu-a

&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl logs cuda-vectoradd
&lt;span class="o"&gt;[&lt;/span&gt;Vector addition of 50000 elements]
Copy input data from the host memory to the CUDA device
CUDA kernel launch with 196 blocks of 256 threads
Copy output data from the CUDA device to the host memory
Test PASSED
Done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sixteen seconds from apply to &lt;code&gt;Completed&lt;/code&gt;, image pull included. The pod landed on a GPU worker without being told to, and you can see what Kyverno wrote into it on the way in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get pod cuda-vectoradd &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.spec.tolerations}'&lt;/span&gt;
&lt;span class="o"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;"effect"&lt;/span&gt;:&lt;span class="s2"&gt;"NoSchedule"&lt;/span&gt;,&lt;span class="s2"&gt;"key"&lt;/span&gt;:&lt;span class="s2"&gt;"nvidia.com/gpu"&lt;/span&gt;,&lt;span class="s2"&gt;"operator"&lt;/span&gt;:&lt;span class="s2"&gt;"Equal"&lt;/span&gt;,&lt;span class="s2"&gt;"value"&lt;/span&gt;:&lt;span class="s2"&gt;"true"&lt;/span&gt;&lt;span class="o"&gt;}]&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get pod cuda-vectoradd &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.spec.affinity.nodeAffinity}'&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"requiredDuringSchedulingIgnoredDuringExecution"&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"nodeSelectorTerms"&lt;/span&gt;:[&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"matchExpressions"&lt;/span&gt;:[&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"key"&lt;/span&gt;:&lt;span class="s2"&gt;"nodepool"&lt;/span&gt;,&lt;span class="s2"&gt;"operator"&lt;/span&gt;:&lt;span class="s2"&gt;"In"&lt;/span&gt;,&lt;span class="s2"&gt;"values"&lt;/span&gt;:[&lt;span class="s2"&gt;"gpu"&lt;/span&gt;&lt;span class="o"&gt;]}]}]}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Delete the pod when you're done. It has finished, so it isn't holding the card, but it's clutter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftgo0u4ihqmeiy2jo2fhx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftgo0u4ihqmeiy2jo2fhx.png" alt="gpu" width="800" height="164"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl logs cuda-vectoradd&lt;/code&gt; ending in &lt;code&gt;Test PASSED&lt;/code&gt;. The hero shot.&lt;/p&gt;

&lt;h2&gt;
  
  
  The runtime: getting containerd to know about GPUs
&lt;/h2&gt;

&lt;p&gt;containerd doesn't know what a GPU is. Something has to register an &lt;code&gt;nvidia&lt;/code&gt; runtime that injects the device and driver libraries into containers. The classic way is to patch containerd's &lt;code&gt;config.toml&lt;/code&gt;, and &lt;strong&gt;RKE2 regenerates that file from a template&lt;/strong&gt;, throwing your patch away on every restart.&lt;/p&gt;

&lt;p&gt;Two things make it work here. CDI is on, so the toolkit writes a device spec at &lt;code&gt;/etc/cdi/nvidia.yaml&lt;/code&gt; that containerd reads at container start:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;cdi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;nriPluginEnabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the toolkit is pointed at RKE2's own containerd rather than the default one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;toolkit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CONTAINERD_CONFIG&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/lib/rancher/rke2/agent/etc/containerd/config.toml&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CONTAINERD_SOCKET&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/run/k3s/containerd/containerd.sock&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CONTAINERD_RUNTIME_CLASS&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nvidia&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CONTAINERD_SET_AS_DEFAULT&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The subtle bit is that &lt;code&gt;CONTAINERD_CONFIG&lt;/code&gt; points at the &lt;strong&gt;generated&lt;/strong&gt; &lt;code&gt;config.toml&lt;/code&gt;, not the &lt;code&gt;.tmpl&lt;/code&gt;. The toolkit re-applies its setup every time it starts, so when a reboot regenerates the config without nvidia, the toolkit simply puts it back. &lt;strong&gt;That's what makes it heal itself across reboots.&lt;/strong&gt; Point it at the template and the live config sits there without a GPU runtime until someone restarts &lt;code&gt;rke2-agent&lt;/code&gt; by hand.&lt;/p&gt;

&lt;p&gt;Because &lt;code&gt;nvidia&lt;/code&gt; is the default runtime, workloads here don't need &lt;code&gt;runtimeClassName: nvidia&lt;/code&gt;. On a cluster without that setting they do, and that one line is what confuses people copying manifests between clusters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sharing the cards
&lt;/h2&gt;

&lt;p&gt;Each A1000 advertises exactly one &lt;code&gt;nvidia.com/gpu&lt;/code&gt;, so by default one pod owns the whole card.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Isolation&lt;/th&gt;
&lt;th&gt;Here&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Exclusive&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;one pod owns the card&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;✅ what runs today&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Time-slicing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;several pods take turns on the card&lt;/td&gt;
&lt;td&gt;compute only, &lt;strong&gt;memory is shared&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;available, not switched on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MIG&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;hardware partitions with their own memory&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;❌ the A1000 has no MIG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MPS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;processes share one GPU context&lt;/td&gt;
&lt;td&gt;partial&lt;/td&gt;
&lt;td&gt;available, not used&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The node labels confirm it: &lt;code&gt;nvidia.com/gpu.replicas=1&lt;/code&gt; and &lt;code&gt;sharing-strategy=none&lt;/code&gt; on all three.&lt;/p&gt;

&lt;p&gt;Time-slicing is a ConfigMap plus a patch to the &lt;code&gt;ClusterPolicy&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ConfigMap&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;time-slicing-config&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gpu-operator&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;a1000&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
    &lt;span class="s"&gt;version: v1&lt;/span&gt;
    &lt;span class="s"&gt;sharing:&lt;/span&gt;
      &lt;span class="s"&gt;timeSlicing:&lt;/span&gt;
        &lt;span class="s"&gt;resources:&lt;/span&gt;
          &lt;span class="s"&gt;- name: nvidia.com/gpu&lt;/span&gt;
            &lt;span class="s"&gt;replicas: 4        # one A1000 looks like four schedulable GPUs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl patch clusterpolicies.nvidia.com cluster-policy &lt;span class="nt"&gt;--type&lt;/span&gt; merge &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'{"spec":{"devicePlugin":{"config":{"name":"time-slicing-config","default":"a1000"}}}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create the ConfigMap first, then patch.&lt;/strong&gt; I ran the patch on its own once, and the device plugin's replacement pod sat in &lt;code&gt;Init&lt;/code&gt; with &lt;code&gt;configmap "time-slicing-config" not found&lt;/code&gt;, which took that node's card from one schedulable GPU to zero until I cleared the reference again. The DaemonSet replaces one pod at a time, so the rollout stalled there and the other two cards kept working.&lt;/p&gt;

&lt;p&gt;Before you turn it on, remember it's oversubscription, not partitioning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No memory isolation.&lt;/strong&gt; Four pods share 8 GB. Four 2 GB models fit; a fourth 3 GB model dies with CUDA out-of-memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No fault isolation.&lt;/strong&gt; One pod that wedges the card affects its neighbours.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sharing, not guarantees.&lt;/strong&gt; Right for notebooks and bursty inference, wrong for anything with a latency target.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My plan is to time-slice dc1 and dc2 and leave dc3 whole for jobs that need all 8 GB.&lt;/p&gt;

&lt;h2&gt;
  
  
  How reliable is it?
&lt;/h2&gt;

&lt;p&gt;Here's what the GPU tier survives, and the evidence for each:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What goes wrong&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;How I know&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A whole machine goes down&lt;/td&gt;
&lt;td&gt;Its card is gone, and so is any job that was running on it; new GPU pods land on the other two&lt;/td&gt;
&lt;td&gt;One card per machine (dc1, dc2, dc3), each advertising &lt;code&gt;nvidia.com/gpu: 1&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The whole lab loses power&lt;/td&gt;
&lt;td&gt;Every node rebuilds its GPU stack and re-tests its card, hands-off&lt;/td&gt;
&lt;td&gt;After the last power cut, the toolkit, device plugin, DCGM exporter and validators came back on all three nodes by themselves, and the CUDA validator &lt;strong&gt;Succeeded&lt;/strong&gt; on every card&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RKE2 regenerates containerd's config on reboot&lt;/td&gt;
&lt;td&gt;The toolkit re-applies the &lt;code&gt;nvidia&lt;/code&gt; runtime&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;CONTAINERD_CONFIG&lt;/code&gt; points at the generated file, not the template&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Someone forgets the GPU toleration&lt;/td&gt;
&lt;td&gt;Kyverno adds it, plus the GPU node affinity&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;gpu-pods-to-gpu-nodes&lt;/code&gt; mutation policy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A notebook is abandoned with a card&lt;/td&gt;
&lt;td&gt;It should be stopped after 24 hours idle and the card freed&lt;/td&gt;
&lt;td&gt;Config only: &lt;code&gt;ENABLE_CULLING=true&lt;/code&gt;, &lt;code&gt;CULL_IDLE_TIME=1440&lt;/code&gt;. I have not seen it fire. The lab is powered off overnight, and two notebooks sat on cards until I stopped them by hand&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A driver or runtime problem&lt;/td&gt;
&lt;td&gt;The operator stops and reports it&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ClusterPolicy&lt;/code&gt; state &lt;code&gt;ready&lt;/code&gt;; validators gate everything above the driver&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And the honest limits. "Highly available" here means GPU &lt;em&gt;capacity&lt;/em&gt;: a job running on a card dies with its machine and has to start again elsewhere. The operator itself is a single replica; if it's down, running GPU pods carry on and nothing new gets configured. A kernel upgrade on a GPU node still needs a driver rebuild (see the traps), there are no GPU alerts wired yet, and nothing caps how many cards one namespace can take. Those last three are on the list at the end.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvqkd8p81b61rst1a2she.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvqkd8p81b61rst1a2she.png" alt="gpu" width="800" height="68"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl get pods -n gpu-operator -l app=nvidia-cuda-validator&lt;/code&gt;: three validators, one per datacenter, all &lt;code&gt;Completed&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The traps, from the driver up
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fomnsh78x0wy7ijgfjgyi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fomnsh78x0wy7ijgfjgyi.png" alt="gpu" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thirteen ways a GPU hides from Kubernetes, by layer, from the driver up.&lt;/p&gt;

&lt;p&gt;Thirteen of them, grouped by layer, in the order you should debug them. Most of them bit me. A few I only know from other people's write-ups, and those say so. Every piece waits on the driver, so a broken foundation makes everything above it look broken too.&lt;/p&gt;

&lt;h3&gt;
  
  
  The driver
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The driver gets OOM-killed, exit 137.&lt;/strong&gt; The log dies right after an &lt;code&gt;nvidia-drm&lt;/code&gt; warning, then &lt;code&gt;nvidia-smi: not found&lt;/code&gt;, and it crash-loops. It looks like a driver bug. It isn't: &lt;strong&gt;the driver container compiles the kernel module&lt;/strong&gt;, running &lt;code&gt;gcc&lt;/code&gt; against the kernel headers, and a 512Mi limit kills it mid-compile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2"&lt;/span&gt;
      &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;4Gi&lt;/span&gt;     &lt;span class="c1"&gt;# 512Mi OOMs the kernel-module compile&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;failed to install nvidia kernel module: distro 'ubuntu24.04' not supported&lt;/code&gt;.&lt;/strong&gt; The driver image ships pre-built modules for a fixed list of distro and kernel pairs, and mine wasn't on it. Build from source instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kernelModuleType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;auto&lt;/span&gt;      &lt;span class="c1"&gt;# open modules first, proprietary as fallback&lt;/span&gt;
  &lt;span class="na"&gt;usePrecompiled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;       &lt;span class="c1"&gt;# build from source, about 3 minutes on first boot&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;nvidia: Unknown symbol __register_chrdev&lt;/code&gt; after a host kernel upgrade.&lt;/strong&gt; The cached module was built for the old kernel. Force a rebuild:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; gpu-operator rollout restart daemonset/nvidia-driver-daemonset
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The real lesson is a runbook entry, not a config change: &lt;strong&gt;a GPU node's kernel upgrade is a special operation&lt;/strong&gt;, with a driver restart on the checklist. A plain power cut doesn't need it, because the kernel hasn't changed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Missing kernel headers.&lt;/strong&gt; The driver builds against the running kernel, so a kernel upgraded without &lt;code&gt;linux-headers-$(uname -r)&lt;/code&gt; fails the build. The Ansible role for the GPU pool installs them, and the error is plain in the driver pod log.&lt;/p&gt;

&lt;h3&gt;
  
  
  The validator
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;nvidia-validator: command not found&lt;/code&gt;, exit 127.&lt;/strong&gt; Version skew, and the error tells you nothing. Older charts shipped the validator as a separate image; the 26.x chart puts the binary inside the main operator image. Values written for one layout against a chart of the other produce a missing binary. Pin the chart (&lt;code&gt;v26.3.2&lt;/code&gt; here), deploy it from the NVIDIA repo rather than a stale vendored copy, and check what's actually running with &lt;code&gt;helm list -n gpu-operator&lt;/code&gt;, not what your values file assumes.&lt;/p&gt;

&lt;h3&gt;
  
  
  The toolkit and runtime
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;no runtime for "nvidia" is configured&lt;/code&gt;.&lt;/strong&gt; The RKE2 trap the generic docs miss. The toolkit looks for &lt;code&gt;/run/containerd/containerd.sock&lt;/code&gt;; RKE2 runs its own containerd at &lt;code&gt;/run/k3s/containerd/containerd.sock&lt;/code&gt;. The fix is the &lt;code&gt;toolkit.env&lt;/code&gt; block above.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Failed to initialize NVML: Driver/library version mismatch&lt;/code&gt;&lt;/strong&gt; inside a pod, while the host shows the same version. The toolkit had patched &lt;code&gt;config.toml&lt;/code&gt; directly and RKE2 regenerated it. CDI or the generated-config setting fixes it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;KubeArmor's AppArmor profile blocks the toolkit.&lt;/strong&gt; The same family of trap that once bit Cilium here: the toolkit can't write what it needs, containerd is silently never configured, and pods report the &lt;code&gt;nvidia&lt;/code&gt; RuntimeClass as missing. If you hit it, run the toolkit container unconfined. Today it runs fine under its own KubeArmor-generated profile.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The toolkit writes the CDI spec and containerd never reads it.&lt;/strong&gt; Pods schedule, but &lt;code&gt;nvidia-smi&lt;/code&gt; hangs. CDI needs containerd 1.7 or newer, so check what your RKE2 release ships before you switch it on. I didn't hit this one: my containerd is 2.x.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Missing &lt;code&gt;runtimeClassName: nvidia&lt;/code&gt;&lt;/strong&gt; on a cluster where nvidia isn't the default runtime. The pod schedules, runs with no GPU injected, and looks exactly like broken hardware. Not an issue here because of &lt;code&gt;CONTAINERD_SET_AS_DEFAULT&lt;/code&gt;, which is why it's worth knowing: the requirement depends on the cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  The device plugin and scheduling
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Insufficient nvidia.com/gpu&lt;/code&gt; while three healthy GPUs sit idle.&lt;/strong&gt; The driver and toolkit were running, but the device plugin was &lt;code&gt;Pending&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;0/21 nodes are available: 21 node&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt; had untolerated taint
&lt;span class="o"&gt;{&lt;/span&gt;nvidia.com/gpu: &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;, that the pod didn&lt;span class="s1"&gt;'t tolerate.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No device-plugin pod means nothing tells the kubelet about the card. The upstream chart ships the right toleration, but a trimmed values file copied from a blog about an untainted cluster quietly drops it. Same trap one layer down: NFD's master without its control-plane toleration never labels anything, so nothing else schedules either.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NFD takes a minute on first install.&lt;/strong&gt; The operator comes up before NFD's first scan, so for about a minute it looks like the operator is running and nothing is happening. It isn't broken. Don't start changing things.&lt;/p&gt;

&lt;h3&gt;
  
  
  Telemetry
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The DCGM exporter gets OOM-killed&lt;/strong&gt; right after logging &lt;code&gt;DCGM successfully initialized!&lt;/code&gt;. It loads its whole field set into memory and 256Mi isn't enough:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dcgmExporter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1Gi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;All of these fixes live in &lt;code&gt;gpu-operator-values.yaml&lt;/code&gt;,&lt;/strong&gt; .&lt;/p&gt;

&lt;h2&gt;
  
  
  Who holds a card, and how to get it back
&lt;/h2&gt;

&lt;p&gt;This is the part I'd most have wanted to read, because it's invisible until a GPU job won't schedule.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;nvidia.com/gpu&lt;/code&gt; can't be oversubscribed.&lt;/strong&gt; Without time-slicing, a pod with &lt;code&gt;nvidia.com/gpu: 1&lt;/code&gt; owns that physical card for its whole life. Three cards means three GPU pods at once, full stop.&lt;/p&gt;

&lt;p&gt;That makes long-lived notebooks the quiet problem. At one point two Kubeflow notebooks were each holding a whole A1000, one of them for three and a half months, while asking for 0.6 and 1.2 CPUs. A notebook that asks for less than one CPU and holds an entire GPU is the shape of the problem. It also quietly capped a Katib sweep at one GPU trial at a time. And they cost more than cards: together they used over half of their namespace's CPU quota, enough to make a daily training pipeline time out because its last job could never be scheduled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The claim is on the pod&lt;/strong&gt;, not the Notebook, the StatefulSet or the volume. So stopping a notebook frees the card. Kubeflow's "stop" sets an annotation, the controller scales to zero, and the pod goes away:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;profile&amp;gt; annotate notebook &amp;lt;name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  kubeflow-resource-stopped&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; +%Y-%m-%dT%H:%M:%SZ&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--overwrite&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I sampled the free-GPU count every ten seconds while doing it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;01] sts &lt;span class="nv"&gt;replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0   &lt;span class="nv"&gt;pod&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Terminating   FREE &lt;span class="nv"&gt;GPUs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="o"&gt;[&lt;/span&gt;02] sts &lt;span class="nv"&gt;replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0   &lt;span class="nv"&gt;pod&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gone          FREE &lt;span class="nv"&gt;GPUs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at the first line. The notebook was "stopped" by every API you'd think to check, and the card was &lt;strong&gt;still claimed&lt;/strong&gt;, because the pod hadn't finished terminating. &lt;code&gt;replicas=0&lt;/code&gt; isn't proof a card came back. On a cluster where KubeArmor can wedge pods in &lt;code&gt;Terminating&lt;/code&gt;, that matters. The reliable check counts from the pods and cross-checks the scheduler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# what pods claim&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; json | jq &lt;span class="s1"&gt;'[.items[] | select(.status.phase=="Running" or .status.phase=="Pending")
  | .spec.containers[].resources.limits["nvidia.com/gpu"] // "0" | tonumber] | add'&lt;/span&gt;

&lt;span class="c"&gt;# what the scheduler has allocated on a node&lt;/span&gt;
kubectl describe node &amp;lt;gpu-node&amp;gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'/Allocated resources/,/Events/'&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;nvidia.com/gpu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As I write this, both GPU notebooks are stopped and all three cards are free.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Culling is on as a safety net.&lt;/strong&gt; The notebook controller stops notebooks that have been idle for 24 hours. It stops, it never deletes: the volume and every file survive, and restarting is one click. What's lost is in-memory kernel state. A running cell counts as busy, so a long training run won't be culled. And the setting is global and not GPU-aware, so it catches abandoned notebooks; it doesn't manage contention. The better lever is not giving notebooks a GPU by default.&lt;/p&gt;

&lt;p&gt;⚠️ One more surprise: &lt;code&gt;nvidia.com/gpu&lt;/code&gt; isn't in the profile namespaces' ResourceQuota, and a quota only limits what it names. So GPU use per namespace is unbounded even though CPU and memory are capped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting the GPUs to work
&lt;/h2&gt;

&lt;p&gt;Making &lt;code&gt;nvidia.com/gpu&lt;/code&gt; schedulable was the prerequisite, not the goal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who on the platform can ask for a card
&lt;/h3&gt;

&lt;p&gt;Nothing on this platform &lt;em&gt;needs&lt;/em&gt; a GPU to run. Every Kubeflow component is a CPU service; what changes is the work users launch through them. Here's each door to a card, and whether anything has walked through it yet:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform piece&lt;/th&gt;
&lt;th&gt;How it asks for a card&lt;/th&gt;
&lt;th&gt;Has it used one here?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kubeflow Notebooks&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;a GPU dropdown in the spawner form&lt;/td&gt;
&lt;td&gt;Yes, and too well: two notebooks held cards while idle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Katib&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;nvidia.com/gpu&lt;/code&gt; in the trial template&lt;/td&gt;
&lt;td&gt;No. Both sweeps ran on CPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kubeflow Trainer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;resourcesPerNode&lt;/code&gt; on a &lt;code&gt;TrainJob&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;No. The runtimes are installed (&lt;code&gt;torch-distributed&lt;/code&gt;, three torchtune LLM fine-tunes); no job has run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;KServe&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;a GPU limit on the predictor&lt;/td&gt;
&lt;td&gt;No. The one live model is XGBoost on CPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kubeflow Pipelines&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;a GPU limit on a single step&lt;/td&gt;
&lt;td&gt;No. The daily pipeline is all CPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Spark&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;executor GPU settings plus the RAPIDS plugin&lt;/td&gt;
&lt;td&gt;No, and not planned: these jobs are small&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A plain pod&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;one line, &lt;code&gt;nvidia.com/gpu: 1&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Yes: the LLM benchmark below&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Everything else in the data platform (Kafka, Airflow, MLflow, the databases) never touches a card and shouldn't.&lt;/p&gt;

&lt;p&gt;So the honest summary is two real users so far: notebooks, which took cards and did nothing with them, and one benchmark pod, which took a card and drove it at 98%.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hyperparameter search with Katib
&lt;/h3&gt;

&lt;p&gt;Katib runs an &lt;code&gt;Experiment&lt;/code&gt; that launches trials as pods, each reporting a metric back through an injected sidecar. Getting it to run at all taught me more than the GPUs did.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It couldn't run in any Kubeflow profile namespace.&lt;/strong&gt; An Experiment sat at &lt;code&gt;Created&lt;/code&gt; with &lt;strong&gt;zero&lt;/strong&gt; trials, and the UI only said "Couldn't find any successful Trial." The real error was two levels down, on a ReplicaSet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pods &lt;span class="s2"&gt;"&amp;lt;exp&amp;gt;-tpe-..."&lt;/span&gt; is forbidden:
  minimum memory usage per Container is 16Mi, but request is 10Mi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Katib asks for 10Mi of memory for its suggestion pods, and the Kyverno-generated LimitRange in every profile namespace has a 16Mi floor. Eleven of twelve algorithms had no explicit resources, so eleven of twelve couldn't schedule. Fixing those exposed the same problem on the trial pods, because the metrics sidecar is injected by a webhook and its default never shows up in the template. The fix is to raise Katib to meet the floor, not lower the floor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;suggestions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;algorithmName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tpe&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io/kubeflow/katib/suggestion-hyperopt:v0.19.0&lt;/span&gt;
      &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;50m&lt;/span&gt;
          &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;128Mi&lt;/span&gt;
        &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;500m&lt;/span&gt;
          &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;512Mi&lt;/span&gt;
  &lt;span class="na"&gt;metricsCollectors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;StdOut&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io/kubeflow/katib/file-metrics-collector:v0.19.0&lt;/span&gt;
      &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;50m&lt;/span&gt;
          &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;32Mi&lt;/span&gt;
        &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;200m&lt;/span&gt;
          &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;128Mi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three more gotchas from getting a sweep to finish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;katib-config&lt;/code&gt; is mounted with &lt;code&gt;subPath&lt;/code&gt;&lt;/strong&gt;, which never receives updates. Restart the Katib controller after every config change; waiting does nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never put a multi-line &lt;code&gt;python3 -c&lt;/code&gt; script in a trial template.&lt;/strong&gt; The stdout collector rewrites the command into a shell string, and the inline script doesn't survive. Pass a file path and flags instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A sub-second trial can finish before the collector attaches&lt;/strong&gt;, which shows up as random failures with an empty observation. Pace the objective and set &lt;code&gt;backoffLimit: 1&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With all of that fixed, a 12-trial TPE sweep finished 12 out of 12 and found the known optimum, on CPU, because for a demonstration sweep a GPU changes nothing (more on that below). And with no time-slicing, the real ceiling for GPU trials is three at a time, one per card. A &lt;code&gt;parallelTrialCount&lt;/code&gt; higher than that just leaves trials &lt;code&gt;Pending&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo425rfa6zarmpygtslmi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo425rfa6zarmpygtslmi.png" alt="gpu" width="799" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Katib trial leaderboard with the best trial highlighted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Training and serving
&lt;/h3&gt;

&lt;p&gt;A GPU training job in Kubeflow Trainer V2 looks like this. I haven't run this one yet, so treat it as the shape, not a tested manifest. With one card per machine, two workers have to land on two different machines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;trainer.kubeflow.org/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TrainJob&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;resnet-finetune&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terranetes&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;runtimeRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;torch-distributed&lt;/span&gt;
  &lt;span class="na"&gt;trainer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;numNodes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
    &lt;span class="na"&gt;resourcesPerNode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;nvidia.com/gpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For serving, a KServe &lt;code&gt;InferenceService&lt;/code&gt; with &lt;code&gt;minReplicas: 0&lt;/code&gt; gives the card back when the model is idle and cold-starts it on demand. That works &lt;em&gt;because&lt;/em&gt; the GPU claim is per pod: scale to zero, the pod goes, the card is free. With three cards, scale-to-zero is the difference between one always-on model and a fleet of models sharing three GPUs.&lt;/p&gt;

&lt;p&gt;My live models today don't need a GPU at all. The football match predictor is an XGBoost model on tabular data, and it trains and serves on CPU in seconds. The first real GPU TrainJob and a properly served LLM are both on the list at the end.&lt;/p&gt;

&lt;h3&gt;
  
  
  The first real job: a 7B model on one card
&lt;/h3&gt;

&lt;p&gt;For three months these cards passed their self-test and did nothing else. Prometheus has the receipts: 0% utilisation and 0 MiB of GPU memory on all three, the whole time. So before writing another word about what an A1000 can do, I made one do it.&lt;/p&gt;

&lt;p&gt;The job is deliberately plain. One pod, one card, Ollama running Mistral 7B in 4-bit (&lt;code&gt;Q4_K_M&lt;/code&gt;, a 4.1 GB download), the same prompt every time with a fixed seed. The whole request for hardware is one line, &lt;code&gt;nvidia.com/gpu: 1&lt;/code&gt;. Kyverno added the toleration and the node rule, the scheduler put it on dc2, and &lt;code&gt;nvidia-smi&lt;/code&gt; inside the container saw the card.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;NAME          SIZE      PROCESSOR    CONTEXT&lt;/span&gt;
&lt;span class="s"&gt;mistral:7b    5.8 GB    100% GPU     &lt;/span&gt;&lt;span class="m"&gt;4096&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the same model on the same node with the GPU switched off, four threads against the pod's four-core limit:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Tokens per second&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RTX A1000&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;about 30&lt;/strong&gt; (four runs: 29.9 to 31.6)&lt;/td&gt;
&lt;td&gt;5,031 MiB of the 8,188 MiB used, 98-99% utilisation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CPU, 4 threads (i9-13900H)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;about 4.2&lt;/strong&gt; (two runs: 4.1 and 4.3)&lt;/td&gt;
&lt;td&gt;same model, same prompt, same seed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fszgkfqxtdxg1irr5je6i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fszgkfqxtdxg1irr5je6i.png" alt="gpu" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mistral 7B on one RTX A1000 against the CPU beside it: about 30 tokens a second against about 4.2.&lt;/p&gt;

&lt;p&gt;Seven times faster, on a 50-watt card that fits in a mini PC. A 400-token answer took 13 seconds on the GPU. At the CPU's rate it would take over a minute and a half. That is the difference between a tool you'd use and one you wouldn't.&lt;/p&gt;

&lt;p&gt;Three things the run taught me that the spec sheet didn't:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It runs hot.&lt;/strong&gt; The card idles at about 60 °C in the MS-01 and sat at 88 to 90 °C within a minute of load, a few degrees over its own 86 °C target, with the driver reporting a software thermal slowdown. Speed drifted from 31.6 to 29.9 tokens a second across the runs. It never reached the 96 °C hard slowdown, but a small case and a single-slot cooler have a ceiling, and sustained training will live at it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It can't tell you its power draw.&lt;/strong&gt; &lt;code&gt;nvidia-smi&lt;/code&gt; reports &lt;code&gt;power.draw&lt;/code&gt; as &lt;code&gt;[N/A]&lt;/code&gt; on this card under passthrough. So the missing power metric isn't an exporter setting I forgot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Threads matter more than cores.&lt;/strong&gt; My first CPU run was left to pick its own thread count. It saw 20 cores, started 20 threads inside a four-core limit, and was still going ten minutes later. Pinned to four threads it produced 60 tokens in about fifteen seconds. If you benchmark CPU inside a container, set the thread count to the limit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The manifest and the exact commands are in &lt;code&gt;examples/llm-benchmark-pod.yaml&lt;/code&gt;. It's a benchmark, not a service: the pod holds a whole card while it exists, so I deleted it when the numbers were in, which is this article's own advice.&lt;/p&gt;

&lt;p&gt;📸 &lt;strong&gt;SCREENSHOT:&lt;/strong&gt; the Grafana DCGM dashboard for dc2 across the run: utilisation jumping from 0 to 98%, memory to 5 GiB, temperature from 60 to the high 80s. The first non-zero lines those panels have ever drawn.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-GPU, and does a GPU change the result?
&lt;/h2&gt;

&lt;p&gt;With more than one card, the internet will tell you to reach for tensor parallelism and model sharding. On three 8 GB cards over PCIe with no NVLink, most of that advice is wrong.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Strategy&lt;/th&gt;
&lt;th&gt;Splits&lt;/th&gt;
&lt;th&gt;Use when&lt;/th&gt;
&lt;th&gt;On these cards&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data parallel (DDP)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the batch, full model per GPU&lt;/td&gt;
&lt;td&gt;the model fits in 8 GB&lt;/td&gt;
&lt;td&gt;✅ the default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sharding (FSDP, ZeRO)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;parameters and optimiser state&lt;/td&gt;
&lt;td&gt;the model won't fit one GPU&lt;/td&gt;
&lt;td&gt;⚠️ prefer offloading to CPU RAM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tensor parallel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;individual layers&lt;/td&gt;
&lt;td&gt;needs NVLink&lt;/td&gt;
&lt;td&gt;❌ slower over PCIe than not doing it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pipeline parallel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;layer stages&lt;/td&gt;
&lt;td&gt;very deep models, many GPUs&lt;/td&gt;
&lt;td&gt;⚠️ rarely worth it here&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use single-GPU tricks first (bf16, gradient checkpointing, smaller batches), then DDP for throughput, and only then sharding. For inference, don't shard: quantise. A 7B model in int4 fits on one card, and splitting it across two PCIe cards is strictly worse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does a GPU change the result, or just the speed?&lt;/strong&gt; It changes how fast you get a result, not what the result is. With a fixed number of trials, a GPU gets you the same answer sooner. With a fixed amount of time, faster trials mean more trials, and more trials is how a search finds a better optimum. That gain comes from trial count, not from the GPU. And it can make results slightly worse: GPU reductions aren't always deterministic, so training often isn't bit-for-bit reproducible.&lt;/p&gt;

&lt;p&gt;So putting a CPU-bound job on a GPU is theatre, and it costs a card something else needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring
&lt;/h2&gt;

&lt;p&gt;The DCGM exporter publishes per-GPU metrics, and a ServiceMonitor puts them in Prometheus, with NVIDIA's dashboard in Grafana. The ones worth watching:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DCGM_FI_DEV_GPU_UTIL&lt;/code&gt;: utilisation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DCGM_FI_DEV_FB_USED&lt;/code&gt; and &lt;code&gt;DCGM_FI_DEV_FB_FREE&lt;/code&gt;: memory used and free&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DCGM_FI_DEV_GPU_TEMP&lt;/code&gt;: temperature&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DCGM_FI_DEV_PCIE_REPLAY_COUNTER&lt;/code&gt;: link errors on the PCIe slot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two I want and don't have. &lt;code&gt;DCGM_FI_DEV_XID_ERRORS&lt;/code&gt; isn't in my exporter's field list yet. &lt;code&gt;DCGM_FI_DEV_POWER_USAGE&lt;/code&gt; isn't either, and adding it won't help: this card doesn't report power draw under passthrough at all.&lt;/p&gt;

&lt;p&gt;The most useful panel is utilisation by pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sum(DCGM_FI_DEV_GPU_UTIL{Hostname="rke2-worker-dc2-gpu-a"}) by (exported_namespace, exported_pod)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mind the label. On my setup &lt;code&gt;pod&lt;/code&gt; is the exporter's own pod, and the workload is in &lt;code&gt;exported_pod&lt;/code&gt;. Group by &lt;code&gt;pod&lt;/code&gt; and every card looks like it's being used by the DCGM exporter.&lt;/p&gt;

&lt;p&gt;What's missing is any alerting. The metrics are there, but nothing fires on a hot card, full memory or an XID error yet. And the metric I want most isn't on any dashboard: &lt;strong&gt;allocated versus used&lt;/strong&gt;. A card that's 100% allocated and 0% used is the notebook problem, and utilisation alone makes it look exactly like a free card.&lt;/p&gt;

&lt;p&gt;NVIDIA has since open-sourced something aimed at exactly that gap: the &lt;a href="https://github.com/NVIDIA/gpu-usage-monitor" rel="noopener noreferrer"&gt;GPU Usage Monitor&lt;/a&gt;, an Apache 2.0 Helm chart that pairs the DCGM exporter with kube-state-metrics, Prometheus and Grafana, and ships dashboards for allocated against used, by namespace and by pod, plus GPU pods stuck &lt;code&gt;Pending&lt;/code&gt;. I haven't installed it. I already run every one of those four pieces, so what I'd want from it is the dashboards, not a second Prometheus. And its platform filter is named for datacenter cards (Hopper, Blackwell), so I don't yet know how it treats an A1000. It's on the list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F30fnxeozek2qd55xadqh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F30fnxeozek2qd55xadqh.png" alt="gpu" width="799" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz5rzbob8ii0eonibdid6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz5rzbob8ii0eonibdid6.png" alt="gpu" width="799" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5g4s7i62kx4pz286jvtl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5g4s7i62kx4pz286jvtl.png" alt="gpu" width="799" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgp4medpb3ygd6qn50hq2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgp4medpb3ygd6qn50hq2.png" alt="gpu" width="799" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Grafana DCGM dashboard showing all three A1000s.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it costs
&lt;/h2&gt;

&lt;p&gt;Three used RTX A1000s for about £600, in slots the MS-01s already had. No extra power. The card is rated at 50 W; I can't give you a measured figure, because it doesn't report one. Cooling is the honest cost: nothing extra was fitted, and under load the card sits at its thermal limit.&lt;/p&gt;

&lt;p&gt;The operational cost is mostly kernel upgrades on GPU nodes, which need the driver restart. Adding a GPU node is now Terraform the passthrough, label and taint it, and let the operator do the rest.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;The sports car runs, survives a power cut and comes back on its own. What's left, roughly in order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Try NVIDIA's GPU Usage Monitor dashboards&lt;/strong&gt; against the Prometheus I already have, to get allocated versus used on a screen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export XID errors&lt;/strong&gt;, then &lt;strong&gt;wire up GPU alerts:&lt;/strong&gt; temperature (now that I know it reaches 90 °C), memory nearly full, XID errors, and a card allocated but unused for hours.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turn on time-slicing&lt;/strong&gt; on dc1 and dc2, and keep dc3 whole.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Put &lt;code&gt;nvidia.com/gpu&lt;/code&gt; in the profile ResourceQuota&lt;/strong&gt;, so one namespace can't take every card.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run a real GPU TrainJob&lt;/strong&gt; across two machines, and &lt;strong&gt;serve that LLM properly&lt;/strong&gt; behind KServe with scale-to-zero, not from a benchmark pod.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automate the driver restart&lt;/strong&gt; after a GPU node's kernel upgrade, so it stops being a checklist item.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've got a GPU sitting in a box that Kubernetes can't see, I hope this saves you the thirteen traps on this list.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.linkedin.com/in/george-ezejiofor-89615a8a/" rel="noopener noreferrer"&gt;Follow me on LinkedIn&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Author: George Ezejiofor&lt;/em&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>nvidia</category>
      <category>mlops</category>
      <category>homelab</category>
    </item>
    <item>
      <title>Math 2.0: How Terence Tao’s Vision Can Supercharge Your AI Infrastructure</title>
      <dc:creator>Naveen Malothu</dc:creator>
      <pubDate>Mon, 12 Oct 2026 11:15:54 +0000</pubDate>
      <link>https://dev.to/naveenmalothu/math-20-how-terence-taos-vision-can-supercharge-your-ai-infrastructure-1e8i</link>
      <guid>https://dev.to/naveenmalothu/math-20-how-terence-taos-vision-can-supercharge-your-ai-infrastructure-1e8i</guid>
      <description>&lt;h2&gt;
  
  
  1️⃣ What was released / announced
&lt;/h2&gt;

&lt;p&gt;Last week Caltech hosted Terence Tao’s &lt;em&gt;Math 2.0&lt;/em&gt; talk (see the PDF &lt;a href="https://teorth.github.io/tao-web/slides/math-2-0-caltech-2026.pdf" rel="noopener noreferrer"&gt;here&lt;/a&gt;). In a crisp 30‑slide deck he laid out a roadmap for a new era where &lt;strong&gt;formal mathematics, large language models, and cloud‑native tooling converge&lt;/strong&gt;. The key takeaway: treat mathematics like a software stack – version‑controlled, testable, and continuously deployed.&lt;/p&gt;

&lt;h2&gt;
  
  
  2️⃣ Why it matters
&lt;/h2&gt;

&lt;p&gt;If you’re building AI infrastructure or MLOps pipelines, you already know the pain of reproducibility. Imagine a world where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Proofs become CI‑tested artifacts&lt;/strong&gt; – a broken theorem fails a pipeline just like a failing unit test.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mathematical models can be auto‑generated&lt;/strong&gt; from high‑level specifications using LLMs, dramatically cutting research iteration time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collaboration happens on a shared, typed ledger&lt;/strong&gt; (think Git + Lean/Coq) that scales from a single PhD student to a multinational R&amp;amp;D team.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s the promise of Math 2.0. It isn’t just academic fluff; it’s a blueprint for &lt;strong&gt;building more reliable, auditable, and automated AI systems&lt;/strong&gt; – something every devops engineer and AI infrastructure lead should start experimenting with today.&lt;/p&gt;

&lt;h2&gt;
  
  
  3️⃣ How to use it – a practical starter kit
&lt;/h2&gt;

&lt;p&gt;Below is a &lt;strong&gt;hands‑on, 5‑step workflow&lt;/strong&gt; that brings a slice of Tao’s vision into your own cloud environment. The stack uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lean 4&lt;/strong&gt; for formal proofs (the language Tao highlighted).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI’s GPT‑4o&lt;/strong&gt; (or any capable LLM) to translate informal math into Lean snippets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Actions&lt;/strong&gt; for CI/CD of proofs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker + Kubernetes&lt;/strong&gt; to keep everything reproducible.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Step 1 – Spin up a Lean‑4 container
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Dockerfile&lt;/span&gt;
FROM ubuntu:22.04
RUN apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    curl git build-essential python3-pip &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="c"&gt;# Install Lean 4 (via elan)&lt;/span&gt;
RUN curl https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh &lt;span class="nt"&gt;-sSf&lt;/span&gt; | sh &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt;
ENV &lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/root/.elan/bin:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

WORKDIR /workspace
COPY &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build and push the image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; ghcr.io/yourorg/lean4-ci:latest &lt;span class="nb"&gt;.&lt;/span&gt;
docker push ghcr.io/yourorg/lean4-ci:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Step 2 – Prompt an LLM to generate a Lean lemma
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Write a Lean4 lemma that proves the Cauchy‑Schwarz inequality for real vectors.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChatCompletion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4o&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Save the output to &lt;code&gt;cauchy.lean&lt;/code&gt; in your repo.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 3 – Add a GitHub Action that runs &lt;code&gt;lake build&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/lean-ci.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Lean CI&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io/yourorg/lean4-ci:latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Lean project&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;lake build&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;lake test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Step 4 – Wire the proof into your AI model pipeline
&lt;/h3&gt;

&lt;p&gt;Suppose you have a &lt;strong&gt;custom loss function&lt;/strong&gt; that relies on a mathematically proven property (e.g., convexity). You can expose the proof as a JSON artifact and let your training job verify it at runtime.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lemma"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cauchy_schwarz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"proved"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-10-12T08:00:00Z"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Your training script can read this file and assert the property before proceeding.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 5 – Deploy on Kubernetes for scaling
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;Deployment&lt;/code&gt; that runs the Lean‑4 container as a &lt;strong&gt;proof‑service&lt;/strong&gt;. Expose a tiny HTTP API (using &lt;code&gt;fastapi&lt;/code&gt;) that accepts a natural‑language conjecture, forwards it to the LLM, and returns a Lean proof.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;proof-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;proof-service&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;proof-service&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lean&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io/yourorg/lean4-ci:latest&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Now any microservice in your AI stack can ask for a formal guarantee on‑the‑fly.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  4️⃣ My take – From an AI‑infra perspective
&lt;/h2&gt;

&lt;p&gt;Tao’s &lt;em&gt;Math 2.0&lt;/em&gt; feels like a &lt;strong&gt;call to industrialize mathematics&lt;/strong&gt; the same way we industrialized software. In practice, the biggest win for us at Griffin AI Tech has been &lt;strong&gt;reducing flaky research&lt;/strong&gt;. By treating proofs as first‑class CI artifacts, we catch logical regressions before they corrupt downstream models.&lt;/p&gt;

&lt;p&gt;A few hard‑earned lessons:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lesson&lt;/th&gt;
&lt;th&gt;What I Learned&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tooling overhead&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lean’s ecosystem is still maturing. Expect a steep learning curve for engineers who are pure‑Python devs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LLM‑generated proofs need verification&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Never trust the LLM output blindly – always run &lt;code&gt;lake build&lt;/code&gt; and &lt;code&gt;lake test&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost vs. value&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Running a proof‑service on a GPU cluster is overkill; a modest CPU node suffices. The real ROI comes from &lt;strong&gt;preventing bugs&lt;/strong&gt; in model‑training pipelines.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you’re skeptical, start small: pick a single theorem that underpins a critical component (e.g., the convergence guarantee of a custom optimizer) and lock it into your CI. The mental model shift – &lt;em&gt;“my loss function must be provably convex”&lt;/em&gt; – quickly spreads to other parts of the stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  TL;DR
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Math 2.0&lt;/strong&gt; is a manifesto to bring formal verification, LLM‑assisted proof generation, and cloud‑native CI/CD together.&lt;/li&gt;
&lt;li&gt;The payoff for AI infrastructure teams is &lt;strong&gt;more reliable, auditable, and faster research cycles&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;I’ve built a minimal proof‑service using Lean 4, Docker, GitHub Actions, and Kubernetes – all under 100 lines of config.&lt;/li&gt;
&lt;li&gt;Start with one lemma, CI‑test it, and watch the confidence in your models grow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Give it a spin and let me know how it reshapes your AI pipelines!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mlops</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Why HF_HOME Points To Ephemeral Storage On RunPod By Default And How To Fix It</title>
      <dc:creator>Francisco Booth</dc:creator>
      <pubDate>Sun, 11 Oct 2026 14:23:40 +0000</pubDate>
      <link>https://dev.to/franciscobooth/why-hfhome-points-to-ephemeral-storage-on-runpod-by-default-and-how-to-fix-it-4d8m</link>
      <guid>https://dev.to/franciscobooth/why-hfhome-points-to-ephemeral-storage-on-runpod-by-default-and-how-to-fix-it-4d8m</guid>
      <description>&lt;p&gt;If you have ever run a HuggingFace model download on RunPod and come back to find your cache gone, this is why.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The default is wrong for rented GPU pods&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;HuggingFace sets HF_HOME to ~/.cache/huggingface when no environment variable overrides it. On a standard Linux machine that is fine your home directory persists. &lt;/p&gt;

&lt;p&gt;On RunPod, your home directory is on the container volume, which is ephemeral. When the pod stops, it is gone.&lt;/p&gt;

&lt;p&gt;RunPod has two storage layers: the container volume, which is ephemeral, and the network volume mounted at /workspace, which persists across pod restarts. HF_HOME defaults to the wrong one.&lt;/p&gt;

&lt;p&gt;This means every model download, every tokeniser, every dataset you pulled via datasets.load_dataset() gone on pod restart. You pay to download them again on the next run. &lt;/p&gt;

&lt;p&gt;On large models that is not a minor inconvenience. A 7B model download at pod startup adds minutes and real cost every single time.&lt;/p&gt;

&lt;p&gt;The fix is one line in your startup script:&lt;/p&gt;




&lt;p&gt;export HF_HOME=/workspace/.cache/huggingface&lt;/p&gt;




&lt;p&gt;/workspace is RunPod’s persistent volume mount. One line and your cache survives every restart.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this is easy to miss&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is no error message. HuggingFace downloads the files successfully to the ephemeral path. Your training run completes. The problem only surfaces when you restart the pod and the download happens again and even then it looks like a slow startup, not a misconfiguration.&lt;/p&gt;

&lt;p&gt;Silent failures are the hardest to debug because you are not looking for them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automating the check&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want this caught automatically before every job rather than relying on remembering to set the variable, ComputeFence checks it as part of its pre-flight scan:&lt;/p&gt;




&lt;p&gt;uvx computefence doctor&lt;/p&gt;




&lt;p&gt;It flags HF_HOME pointing to ephemeral storage and prints the exact export command for your platform. It also checks GPU visibility, Accelerate config, checkpoint directory persistence, and disk headroom the other silent failures that cost compute budget without a log entry.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The two-line pre-flight for every RunPod job&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;export HF_HOME=/workspace/.cache/huggingface&lt;br&gt;
uvx computefence doctor&lt;/p&gt;




&lt;p&gt;The first line fixes the cache. The second confirms everything else is configured correctly before the GPU bill starts.&lt;/p&gt;

&lt;p&gt;GitHub: github.com/Francisco-Booth/ComputeFence&lt;br&gt;
Install: pip install computefence&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>python</category>
      <category>runpod</category>
      <category>mlops</category>
    </item>
    <item>
      <title>From Local Scripts to Edge Deployments: Building Production-Grade AI Infrastructure</title>
      <dc:creator>Ashish Kumar Singh</dc:creator>
      <pubDate>Sat, 10 Oct 2026 12:34:13 +0000</pubDate>
      <link>https://dev.to/ashish-singh/from-local-scripts-to-edge-deployments-building-production-grade-ai-infrastructure-a5k</link>
      <guid>https://dev.to/ashish-singh/from-local-scripts-to-edge-deployments-building-production-grade-ai-infrastructure-a5k</guid>
      <description>&lt;h3&gt;
  
  
  Moving Beyond API Wrappers
&lt;/h3&gt;

&lt;p&gt;Building a local prototype with an LLM API takes an hour. Running it in an enterprise environment—handling traffic spikes, controlling costs, and enforcing security guardrails—is a completely different challenge.&lt;/p&gt;

&lt;p&gt;As an &lt;strong&gt;AI Infrastructure &amp;amp; MLOps Engineer&lt;/strong&gt;, I bridge the gap between foundation models and scalable cloud architecture. Here are the core lessons I learned architecting and deploying three cloud platforms in 30 days, including &lt;strong&gt;CORA&lt;/strong&gt;, an enterprise AI chatbot with strict constraint guardrails.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Serverless Edge Stack
&lt;/h3&gt;

&lt;p&gt;To achieve high availability, low latency, and automated deployments, I leveraged:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;AWS (EC2, S3, IAM):&lt;/strong&gt; Core compute and infrastructure primitives.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Vercel &amp;amp; Cloudflare:&lt;/strong&gt; Global CDN delivery and edge function execution.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Claude API + Guardrails:&lt;/strong&gt; Secure orchestration preventing prompt injection.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Resend:&lt;/strong&gt; Automated transactional data and email pipelines.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Terraform (IaC):&lt;/strong&gt; Reproducible, programmatic environment provisioning.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3 Critical MLOps Lessons
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Guardrails Belong at the Infrastructure Level&lt;/strong&gt;&lt;br&gt;
UI prompt engineering isn't enough. Guardrails must be enforced at the backend API layer before queries ever hit the model. Implementing constraint-checking middleware on CORA kept system prompts inviolable while maintaining fast response times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Strict FinOps &amp;amp; Latency Management&lt;/strong&gt;&lt;br&gt;
Agentic workflows can spike API costs through infinite loops. Edge caching, strict timeout policies, and token budgets are essential for keeping cloud spend predictable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Edge-First Deployments&lt;/strong&gt;&lt;br&gt;
Shifting state management and routing to edge networks minimizes cold starts, delivering near-instantaneous responses globally.&lt;/p&gt;




&lt;h3&gt;
  
  
  What’s Next?
&lt;/h3&gt;

&lt;p&gt;I’m currently mastering enterprise architectures and preparing for my &lt;strong&gt;AWS Machine Learning Engineer – Associate (MLA-C02)&lt;/strong&gt; and &lt;strong&gt;HashiCorp Terraform&lt;/strong&gt; certifications.&lt;/p&gt;

&lt;p&gt;You can test my interactive AI projects and view my architecture setups at &lt;strong&gt;&lt;a href="https://aashishsingh.me" rel="noopener noreferrer"&gt;aashishsingh.me&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What are your go-to tools for hosting production AI agents? Let’s discuss in the comments below!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>aws</category>
      <category>mlops</category>
      <category>cloud</category>
    </item>
  </channel>
</rss>
