<?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: Sathpal Singh</title>
    <description>The latest articles on DEV Community by Sathpal Singh (@sathpal_singh).</description>
    <link>https://dev.to/sathpal_singh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1595943%2F19b522c7-82ed-4bf5-952e-72baa23f1857.png</url>
      <title>DEV Community: Sathpal Singh</title>
      <link>https://dev.to/sathpal_singh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sathpal_singh"/>
    <language>en</language>
    <item>
      <title>Picking the Latest Kubernetes Release on AKS Without Shooting Yourself in the Foot</title>
      <dc:creator>Sathpal Singh</dc:creator>
      <pubDate>Fri, 24 Jul 2026 07:41:22 +0000</pubDate>
      <link>https://dev.to/sathpal_singh/picking-the-latest-kubernetes-release-on-aks-without-shooting-yourself-in-the-foot-1oij</link>
      <guid>https://dev.to/sathpal_singh/picking-the-latest-kubernetes-release-on-aks-without-shooting-yourself-in-the-foot-1oij</guid>
      <description>&lt;h1&gt;
  
  
  Picking the Latest Kubernetes Release on AKS Without Shooting Yourself in the Foot
&lt;/h1&gt;

&lt;p&gt;Every few months a platform engineer opens a Slack message that reads something like: &lt;em&gt;"Hey, our AKS cluster is on a version that's being retired — what do we do?"&lt;/em&gt; The answer is never "just click upgrade," but it also shouldn't be a three-week fire drill. This post walks through how AKS versions work, how to find what's actually available in your region, and how to set a defensible upgrade posture — without repeating the node pool mechanics we've already covered in earlier posts in this series.&lt;/p&gt;

&lt;h2&gt;
  
  
  How AKS Manages Version Support Windows
&lt;/h2&gt;

&lt;p&gt;AKS doesn't support every Kubernetes minor version forever. Microsoft maintains a sliding support window — commonly described as the three most recent minor versions (N, N-1, N-2) — and retires older releases on a rolling basis. &lt;sup id="fnref1"&gt;1&lt;/sup&gt; NEEDS_VALIDATION: confirm the exact N/N-1/N-2 window against current Microsoft docs, as the supported count has varied historically.&lt;/p&gt;

&lt;p&gt;What that means operationally: if 1.30 is the current stable release, you can expect 1.29 and 1.28 to remain supported, while 1.27 approaches end-of-life. Clusters still running a retired version don't immediately explode, but they stop receiving security patches and you lose Microsoft support SLA coverage — two things you do not want to explain to your CISO.&lt;/p&gt;

&lt;p&gt;Patch versions (the third digit) within a supported minor are more granular. AKS regularly ships node OS patches and Kubernetes patch releases; these are where most of the day-to-day CVE fixes land.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding What's Available in Your Region
&lt;/h2&gt;

&lt;p&gt;Version availability is &lt;strong&gt;per-region&lt;/strong&gt;. A version that GA'd last week in East US may still be in preview in Southeast Asia. Always query your actual deployment region before planning an upgrade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az aks get-versions &lt;span class="nt"&gt;--location&lt;/span&gt; eastus &lt;span class="nt"&gt;--output&lt;/span&gt; table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NEEDS_VALIDATION: confirm &lt;code&gt;--output table&lt;/code&gt; renders usefully for this subcommand in current CLI versions; &lt;code&gt;--output json&lt;/code&gt; is always safe if the table format shifts.&lt;/p&gt;

&lt;p&gt;The output lists minor versions, their patch variants, and whether each is in preview or GA. Treat anything marked preview as off-limits for production unless you have a specific reason and the risk tolerance to match.&lt;/p&gt;

&lt;p&gt;If you want the current default version AKS would pick if you didn't specify one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az aks get-versions &lt;span class="nt"&gt;--location&lt;/span&gt; eastus &lt;span class="nt"&gt;--output&lt;/span&gt; json &lt;span class="se"&gt;\&lt;/span&gt;
  | jq &lt;span class="s1"&gt;'[.values[] | select(.isDefault == true)]'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NEEDS_VALIDATION: the &lt;code&gt;isDefault&lt;/code&gt; field name — verify against current CLI JSON schema.&lt;/p&gt;

&lt;p&gt;Key insight: &lt;strong&gt;the AKS default is not necessarily the latest GA patch&lt;/strong&gt;. &lt;sup id="fnref1"&gt;1&lt;/sup&gt; Microsoft selects a "recommended" version that has had some soak time. If you want the latest, you have to ask for it explicitly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pinning a Version at Cluster Create Time
&lt;/h2&gt;

&lt;p&gt;To be explicit about your version at cluster creation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az aks create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--resource-group&lt;/span&gt; my-rg &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; my-cluster &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--location&lt;/span&gt; eastus &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--kubernetes-version&lt;/span&gt; 1.30.2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--node-count&lt;/span&gt; 3 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--generate-ssh-keys&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NEEDS_VALIDATION: substitute the actual latest GA patch for your region; &lt;code&gt;1.30.2&lt;/code&gt; is illustrative only — do not copy-paste without checking &lt;code&gt;az aks get-versions&lt;/code&gt; first.&lt;/p&gt;

&lt;p&gt;Omitting &lt;code&gt;--kubernetes-version&lt;/code&gt; hands the decision to Microsoft's recommended default. That's fine for dev clusters. For production, pin it, document why you chose that version, and put the upgrade decision in your change process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auto-Upgrade Channels: Declaring Upgrade Intent
&lt;/h2&gt;

&lt;p&gt;Manually upgrading clusters is fine until you have fifteen of them. Auto-upgrade channels let you express &lt;em&gt;intent&lt;/em&gt; rather than managing individual upgrade events. AKS supports the following channels &lt;sup id="fnref1"&gt;1&lt;/sup&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;none&lt;/strong&gt; — no automatic upgrades; you control everything manually.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;patch&lt;/strong&gt; — automatically upgrades to the latest patch within the current minor version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;stable&lt;/strong&gt; — targets the latest patch on the N-1 minor version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;rapid&lt;/strong&gt; — targets the latest patch on the latest supported minor version (N).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;node-image&lt;/strong&gt; — upgrades only the node OS image, not the Kubernetes version itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;NEEDS_VALIDATION: confirm exact current semantics for &lt;code&gt;stable&lt;/code&gt; and &lt;code&gt;rapid&lt;/code&gt; against Microsoft docs — the mapping of "N" vs "N-1" has been adjusted in past releases.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;node-image&lt;/code&gt; channel is worth calling out explicitly: &lt;strong&gt;node image upgrades and Kubernetes version upgrades are decoupled&lt;/strong&gt;. &lt;sup id="fnref1"&gt;1&lt;/sup&gt; You can roll fresh OS images (security patches, kernel updates) without touching your Kubernetes minor or patch version. This is the channel most production clusters should be running continuously — there's little reason to let node images go stale.&lt;/p&gt;

&lt;p&gt;Setting the channel on an existing cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az aks update &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--resource-group&lt;/span&gt; my-rg &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; my-cluster &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--auto-upgrade-channel&lt;/span&gt; patch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Gating Upgrades with Planned Maintenance Windows
&lt;/h2&gt;

&lt;p&gt;Auto-upgrade without a maintenance window means upgrades can fire at any time AKS decides conditions are met. That's a bad day when it happens at 2 PM on a Tuesday during peak traffic. Planned Maintenance lets you constrain when auto-upgrades are allowed to execute. &lt;sup id="fnref1"&gt;1&lt;/sup&gt; NEEDS_VALIDATION: confirm current Planned Maintenance API capabilities and whether it gates both K8s and node-image upgrades or only 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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;maintenance.azure.com/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;MaintenanceConfiguration&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;aksmaintenance&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;timeInWeek&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;day&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Saturday&lt;/span&gt;
      &lt;span class="na"&gt;hourSlots&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;notAllowedTime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2024-12-20T00:00:00Z"&lt;/span&gt;
      &lt;span class="na"&gt;end&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2025-01-03T00:00:00Z"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NEEDS_VALIDATION: the above YAML structure is illustrative — validate the exact CRD schema against current AKS documentation before applying.&lt;/p&gt;

&lt;p&gt;Alternatively via CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az aks maintenanceconfiguration add &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--resource-group&lt;/span&gt; my-rg &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cluster-name&lt;/span&gt; my-cluster &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; aksManagedAutoUpgradeSchedule &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--weekday&lt;/span&gt; Saturday &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--start-hour&lt;/span&gt; 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NEEDS_VALIDATION: confirm subcommand name and flags for the current CLI version.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Concrete Upgrade Decision Process
&lt;/h2&gt;

&lt;p&gt;Here's the numbered checklist I'd run through before touching a production cluster's Kubernetes version:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Query available versions&lt;/strong&gt; in your target region with &lt;code&gt;az aks get-versions&lt;/code&gt;. Confirm the version you want is GA, not preview.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check your current cluster version&lt;/strong&gt; with &lt;code&gt;az aks show --resource-group my-rg --name my-cluster --query kubernetesVersion&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review the Kubernetes changelog&lt;/strong&gt; for the target minor version. Focus on API deprecations — if your workloads use APIs removed in the target version, fix that first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run &lt;code&gt;kubectl deprecations&lt;/code&gt;&lt;/strong&gt; (via the &lt;code&gt;kubent&lt;/code&gt; tool or similar) against your cluster to catch any in-use deprecated APIs before the upgrade window. NEEDS_VALIDATION: confirm &lt;code&gt;kubent&lt;/code&gt; compatibility with your target version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upgrade control plane first&lt;/strong&gt;, validate, then upgrade node pools — this is standard AKS sequencing. If you need the node pool mechanics, see our earlier posts in this series.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set your auto-upgrade channel&lt;/strong&gt; to &lt;code&gt;patch&lt;/code&gt; at minimum so you don't fall behind on patch releases between planned minor upgrades.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure a Planned Maintenance window&lt;/strong&gt; so automated patch upgrades don't surprise you in business hours.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Version Skew Problem
&lt;/h2&gt;

&lt;p&gt;One thing that catches teams off guard: AKS allows your control plane and node pools to differ by at most one minor version, with the control plane always ahead. &lt;sup id="fnref2"&gt;2&lt;/sup&gt; If you're running control plane 1.30 and node pools at 1.28, you have a problem — the node pools need to come up through 1.29 before they can reach 1.30. You cannot skip minor versions on node pools.&lt;/p&gt;

&lt;p&gt;This is why letting clusters drift is expensive. A cluster that hasn't been upgraded in a year may require sequential minor version upgrades, each with its own validation cycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting It Together
&lt;/h2&gt;

&lt;p&gt;Version management on AKS is less about clicking the upgrade button and more about having a policy that makes the decision for you at the right time. Set the &lt;code&gt;patch&lt;/code&gt; auto-upgrade channel, add a maintenance window, keep node images continuously current via &lt;code&gt;node-image&lt;/code&gt; channel, and plan minor version upgrades quarterly. That's a posture you can defend, automate, and sleep through.&lt;/p&gt;

&lt;p&gt;The clusters that cause incidents are the ones where version management was treated as a one-time task rather than a continuous process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
    A([Platform Engineer]) --&amp;gt; B[az aks get-versions\n--location region]
    B --&amp;gt; C{Version Selection\nStrategy}
    C --&amp;gt;|Pin explicit version| D[az aks create\n--kubernetes-version X.Y.Z]
    C --&amp;gt;|Declare upgrade intent| E[Set Auto-Upgrade Channel]
    E --&amp;gt; F{Channel Choice}
    F --&amp;gt;|Conservative| G[patch\nStay on current minor]
    F --&amp;gt;|Balanced| H[stable\nN-1 minor version]
    F --&amp;gt;|Aggressive| I[rapid\nLatest supported minor]
    D --&amp;gt; J[AKS Cluster]
    G --&amp;gt; J
    H --&amp;gt; J
    I --&amp;gt; J
    J --&amp;gt; K[Planned Maintenance\nWindow Gates Upgrades]
    K --&amp;gt; L{Upgrade Scope}
    L --&amp;gt;|K8s version| M[Control Plane\n+ Node Pools]
    L --&amp;gt;|OS patches only| N[Node Image Upgrade\nDecoupled from K8s]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/aks/what-is-aks" rel="noopener noreferrer"&gt;What is Azure Kubernetes Service (AKS)?&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/aks/concepts-clusters-workloads" rel="noopener noreferrer"&gt;Azure Kubernetes Service (AKS) Core Concepts&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>kubernetes</category>
      <category>aks</category>
      <category>azure</category>
      <category>platformengineering</category>
    </item>
    <item>
      <title>AKS and Near-Bare-Metal Workloads: What Platform Teams Can Responsibly Plan For</title>
      <dc:creator>Sathpal Singh</dc:creator>
      <pubDate>Thu, 23 Jul 2026 16:55:32 +0000</pubDate>
      <link>https://dev.to/sathpal_singh/aks-and-near-bare-metal-workloads-what-platform-teams-can-responsibly-plan-for-5927</link>
      <guid>https://dev.to/sathpal_singh/aks-and-near-bare-metal-workloads-what-platform-teams-can-responsibly-plan-for-5927</guid>
      <description>&lt;h1&gt;
  
  
  AKS and Near-Bare-Metal Workloads: What Platform Teams Can Responsibly Plan For
&lt;/h1&gt;

&lt;p&gt;Every few months a team shows up with a workload that has opinions about hardware. GPU inference, high-frequency packet processing, latency-sensitive financial systems — something that makes a shared-tenant VM feel like a traffic jam. The conversation usually ends up at "can we get bare-metal nodes on AKS?"&lt;/p&gt;

&lt;p&gt;The honest answer right now: &lt;em&gt;partially, with caveats, and you should not trust anyone who gives you a confident full answer without pointing at current documentation.&lt;/em&gt; This post is about what you can design around today, what requires validation before you commit to it, and where the gaps are that will bite you if you skip due diligence.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A note on sources:&lt;/strong&gt; The AKS core concepts and product overview documentation available at time of writing covers cluster and workload fundamentals&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;sup id="fnref2"&gt;2&lt;/sup&gt; but does not address bare-metal or near-bare-metal node pool specifics. Claims in that category are marked &lt;code&gt;NEEDS_VALIDATION&lt;/code&gt; throughout. Everything else is grounded in general AKS behavior that is broadly consistent across the platform.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why "Bare-Metal on AKS" Is Complicated Terminology
&lt;/h2&gt;

&lt;p&gt;AKS runs on Azure VMs. Azure VMs run on Azure's physical fleet. The question is how much of the hypervisor overhead and hardware sharing model you can escape.&lt;/p&gt;

&lt;p&gt;Azure offers VM SKU families that are designed to minimize virtualization overhead — isolated VM sizes that occupy an entire physical host, giving you a single-tenant hardware environment. Whether specific SKUs in this category are available as AKS node pool targets depends on regional availability and AKS's supported VM size list. &lt;code&gt;NEEDS_VALIDATION&lt;/code&gt; — check the current AKS supported VM sizes documentation for your target region before designing around a specific SKU.&lt;/p&gt;

&lt;p&gt;What you get with isolated or near-bare-metal SKUs, if available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Predictable NUMA topology&lt;/strong&gt; — no neighbor noise on the physical host&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full access to hardware features&lt;/strong&gt; — relevant for SR-IOV, DPDK, and accelerated networking scenarios (&lt;code&gt;NEEDS_VALIDATION&lt;/code&gt; for specific feature compatibility with AKS CNI configurations)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single-tenant physical isolation&lt;/strong&gt; — meaningful for compliance frameworks that require it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What you do NOT automatically get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A different version of Kubernetes&lt;/li&gt;
&lt;li&gt;Different node lifecycle behavior&lt;/li&gt;
&lt;li&gt;Escape from AKS's node auto-repair or OS upgrade mechanics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point is where platform teams usually get surprised.&lt;/p&gt;




&lt;h2&gt;
  
  
  Node Lifecycle Is Still AKS's Domain
&lt;/h2&gt;

&lt;p&gt;AKS manages node health and upgrades at the node pool level&lt;sup id="fnref1"&gt;1&lt;/sup&gt;. This does not change because you picked a specialty VM SKU. If auto-repair decides a node is unhealthy and reprovisioned it, the replacement VM must come from available capacity of the same SKU. For isolated VM families, that capacity is often constrained — regionally and numerically.&lt;/p&gt;

&lt;p&gt;The practical consequence: &lt;strong&gt;your cluster auto-repair and upgrade assumptions need re-evaluation for specialty node pools.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For standard node pools on commodity SKUs, AKS node upgrade behavior is well-documented and we've covered it in depth in our prior upgrade series (#2, #42, #50). The short version is that AKS handles node image upgrades via cordon-drain-replace, and you control the surge buffer and max unavailable settings. That mechanical behavior is the same regardless of SKU. What changes is the risk profile:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Capacity risk:&lt;/strong&gt; If your isolated SKU has low regional availability, a surge node during upgrade may not provision. The upgrade stalls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drain timing risk:&lt;/strong&gt; Pods on high-performance hardware often have longer graceful termination windows. Make sure your &lt;code&gt;terminationGracePeriodSeconds&lt;/code&gt; reflects that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OS upgrade compatibility:&lt;/strong&gt; Node OS image updates on specialty hardware SKUs may lag behind standard SKU rollouts. &lt;code&gt;NEEDS_VALIDATION&lt;/code&gt; — check AKS release notes for your target SKU family.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Node Pool Isolation Strategy
&lt;/h2&gt;

&lt;p&gt;If you're mixing standard workloads and hardware-sensitive workloads in the same cluster (which is a reasonable cost efficiency decision), node pool isolation is non-negotiable. This is standard AKS practice&lt;sup id="fnref1"&gt;1&lt;/sup&gt; and applies regardless of whether the specialty pool is "bare-metal adjacent" or not.&lt;/p&gt;

&lt;p&gt;The pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Separate node pools by workload class&lt;/strong&gt; — one pool for standard platform services, one for hardware-intensive workloads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Taint specialty node pools&lt;/strong&gt; — prevent accidental scheduling of standard workloads onto expensive hardware&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use node selectors and tolerations explicitly&lt;/strong&gt; — don't rely on the absence of a node being "wrong enough" to avoid it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set resource requests and limits that reflect actual hardware&lt;/strong&gt; — on high-performance SKUs with full NUMA access, misconfigured limits can be worse than no limits&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's a minimal node pool configuration pattern for a tainted specialty pool:&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;# Create a specialty node pool with a taint to prevent accidental scheduling&lt;/span&gt;
&lt;span class="c"&gt;# Replace &amp;lt;SKU_NAME&amp;gt; with your validated target SKU&lt;/span&gt;
az aks nodepool add &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--resource-group&lt;/span&gt; myRG &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cluster-name&lt;/span&gt; myCluster &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; specialtypool &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--node-vm-size&lt;/span&gt; &amp;lt;SKU_NAME&amp;gt; &lt;span class="se"&gt;\ &lt;/span&gt;&lt;span class="c"&gt;# NEEDS_VALIDATION: confirm SKU is AKS-supported&lt;/span&gt;
  &lt;span class="nt"&gt;--node-count&lt;/span&gt; 2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--node-taints&lt;/span&gt; workload-class&lt;span class="o"&gt;=&lt;/span&gt;hardware-intensive:NoSchedule &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--labels&lt;/span&gt; workload-class&lt;span class="o"&gt;=&lt;/span&gt;hardware-intensive &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--zones&lt;/span&gt; 1 2 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the corresponding pod spec side:&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;hardware-sensitive-workload&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;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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;workload-class"&lt;/span&gt;
      &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&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;hardware-intensive"&lt;/span&gt;
      &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NoSchedule"&lt;/span&gt;
  &lt;span class="na"&gt;nodeSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;workload-class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hardware-intensive&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;app&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;your-registry/your-image&lt;/span&gt; &lt;span class="c1"&gt;# pin your digest, don't use latest&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8"&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;32Gi"&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;8"&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;32Gi"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Concrete Steps Before Committing to a Specialty Node Pool
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Validate SKU availability in your target region.&lt;/strong&gt; Run &lt;code&gt;az vm list-skus --location &amp;lt;region&amp;gt; --size &amp;lt;sku-prefix&amp;gt; --output table&lt;/code&gt; and cross-reference against the AKS supported VM sizes list. Do not assume a SKU that works for standalone VMs is available for AKS node pools.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Check current AKS release notes for the SKU family.&lt;/strong&gt; Look specifically for known issues with node auto-repair, OS image compatibility, or accelerated networking feature support. &lt;code&gt;NEEDS_VALIDATION&lt;/code&gt; — this is release-cadence dependent.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Model your capacity headroom.&lt;/strong&gt; For upgrade surge and auto-repair replacement, you need available quota &lt;em&gt;and&lt;/em&gt; available physical capacity. For isolated SKUs, physical capacity is the harder constraint. File a support ticket to confirm capacity commitments if the workload is business-critical.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test node pool upgrade behavior in a non-production cluster first.&lt;/strong&gt; Don't discover that your specialty SKU has zero surge capacity during a production Kubernetes version upgrade. The upgrade series we've covered previously (#50 is the most current approved version) gives you the tooling — apply the same runbook to a test specialty pool before you need it for real.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Define your eviction and rescheduling strategy.&lt;/strong&gt; If a node is auto-repaired and the replacement takes longer than expected (capacity contention), what happens to your workload? PodDisruptionBudgets should reflect the actual tolerance of the workload, not the default.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Align with your golden path guardrails.&lt;/strong&gt; If your platform has golden path templates (covered in #25), specialty node pools should either be an explicit supported variant or explicitly out-of-scope. The worst outcome is an undocumented workaround that every team discovers independently and implements differently.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What Not To Do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Don't build production dependency on a feature that's in preview.&lt;/strong&gt; AKS preview features can change or be dropped. If a specific bare-metal adjacent capability is currently in preview, treat it as R&amp;amp;D, not production infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't assume SKU-level isolation means network-level isolation.&lt;/strong&gt; Physical host isolation and network security are different axes. Your CNI configuration and network policies still matter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't skip the PodDisruptionBudget.&lt;/strong&gt; On hardware-intensive workloads, the instinct is often "this thing is stateful and complex, let's not let Kubernetes touch it." That instinct leads to nodes that can't be drained and upgrades that time out.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Responsible Summary
&lt;/h2&gt;

&lt;p&gt;AKS can host workloads on VM SKUs designed to reduce virtualization overhead and provide single-tenant hardware access. The exact SKUs available, their compatibility with specific AKS networking and acceleration features, and their behavior under node lifecycle operations all require validation against current documentation before you commit. &lt;code&gt;NEEDS_VALIDATION&lt;/code&gt; on the specifics is not a cop-out — it's the difference between a platform that works and a platform that works until it doesn't.&lt;/p&gt;

&lt;p&gt;What you &lt;em&gt;can&lt;/em&gt; design now: isolation strategy, taint/toleration patterns, upgrade runbooks, and capacity planning processes. Get those right and the hardware specifics slot in cleanly once validated.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
    A[Platform Team Evaluation] --&amp;gt; B{Workload Requirements}
    B --&amp;gt; C[Standard Latency\nGeneral Purpose VMs]
    B --&amp;gt; D[Low Latency / Hardware Intensive\nSpecialty VM SKUs]
    D --&amp;gt; E[Validate SKU Availability\nby Region]
    E --&amp;gt; F[Dedicated Node Pool\nIsolation Strategy]
    F --&amp;gt; G[Review Auto-Repair &amp;amp;\nOS Upgrade Behavior]
    G --&amp;gt; H[Node Pool Taints &amp;amp; Tolerations\nfor Workload Scheduling]
    C --&amp;gt; H
    H --&amp;gt; I[Mixed Cluster:\nStandard + Specialty Pools]
    I --&amp;gt; J[Ongoing: Monitor AKS\nRelease Notes &amp;amp; SKU Docs]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/aks/concepts-clusters-workloads" rel="noopener noreferrer"&gt;Azure Kubernetes Service (AKS) Core Concepts&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/aks/what-is-aks" rel="noopener noreferrer"&gt;What is Azure Kubernetes Service (AKS)?&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>kubernetes</category>
      <category>azurekubernetesservice</category>
      <category>nodepools</category>
      <category>platformengineering</category>
    </item>
    <item>
      <title>Karpenter on AKS in 2026: What Actually Works</title>
      <dc:creator>Sathpal Singh</dc:creator>
      <pubDate>Sun, 31 May 2026 05:21:06 +0000</pubDate>
      <link>https://dev.to/sathpal_singh/karpenter-on-aks-in-2026-what-actually-works-1meh</link>
      <guid>https://dev.to/sathpal_singh/karpenter-on-aks-in-2026-what-actually-works-1meh</guid>
      <description>&lt;h1&gt;
  
  
  Karpenter on AKS in 2026: What Actually Works
&lt;/h1&gt;

&lt;p&gt;Karpenter on AKS has gone from "interesting experiment" to "something you can actually run in production" with some caveats that will save you a weekend of pain if you read them now. This post is a field report, not a sales pitch.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Short Version
&lt;/h2&gt;

&lt;p&gt;If you're running homogeneous, predictable workloads and you're happy with cluster-autoscaler (CAS), stay there. CAS is boring, it works, and Azure supports it fully. If you're running GPU workloads, spot-heavy batch pipelines, or you need bin-packing that doesn't require you to pre-define a node pool for every VM SKU you might want, Karpenter is now worth the operational overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Karpenter Actually Does on AKS
&lt;/h2&gt;

&lt;p&gt;Karpenter watches for unschedulable pods and provisions nodes directly via the Azure provider, no VMSS node pools required for every SKU combination. It provisions, consolidates, and terminates nodes based on pod requirements and your defined &lt;code&gt;NodePool&lt;/code&gt; and &lt;code&gt;AKSNodeClass&lt;/code&gt; resources.&lt;/p&gt;

&lt;p&gt;The AKS provider for Karpenter (&lt;code&gt;karpenter-provider-azure&lt;/code&gt;) is a separate project from the AWS provider. Same core Karpenter engine, different provider implementation. This matters because feature parity with AWS Karpenter is not guaranteed and the cadence of releases differs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites and Installation
&lt;/h2&gt;

&lt;p&gt;You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An AKS cluster with &lt;code&gt;--network-plugin azure&lt;/code&gt; or &lt;code&gt;--network-plugin overlay&lt;/code&gt; (Azure CNI in either mode works; kubenet is not supported)&lt;/li&gt;
&lt;li&gt;A managed identity with the right RBAC, the provider needs to create and delete VMs and manage NICs, disks, and NSGs&lt;/li&gt;
&lt;li&gt;Workload identity enabled on the cluster&lt;/li&gt;
&lt;li&gt;Karpenter installed via Helm&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The official installation path uses Helm with values pulled from your cluster. Here's a stripped-down install sequence:&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;# Set environment variables: replace with your actual values&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my-aks-cluster"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;RESOURCE_GROUP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my-rg"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;LOCATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"eastus2"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;KARPENTER_NAMESPACE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"kube-system"&lt;/span&gt;

&lt;span class="c"&gt;# Get cluster details needed for Karpenter config&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SUBSCRIPTION_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;az account show &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; tsv&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NODE_RESOURCE_GROUP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;az aks show &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RESOURCE_GROUP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; nodeResourceGroup &lt;span class="nt"&gt;-o&lt;/span&gt; tsv&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Install via Helm&lt;/span&gt;
&lt;span class="c"&gt;# NEEDS_VALIDATION: confirm chart version and repo URL against&lt;/span&gt;
&lt;span class="c"&gt;# https://github.com/Azure/karpenter-provider-azure at time of deployment&lt;/span&gt;
helm upgrade &lt;span class="nt"&gt;--install&lt;/span&gt; karpenter oci://mcr.microsoft.com/aks/karpenter/karpenter &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;KARPENTER_NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="s2"&gt;"settings.clusterName=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="s2"&gt;"settings.location=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LOCATION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="s2"&gt;"settings.subscriptionID=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SUBSCRIPTION_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="s2"&gt;"settings.resourceGroup=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NODE_RESOURCE_GROUP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Defining Your First NodePool
&lt;/h2&gt;

&lt;p&gt;This is where Karpenter's model diverges most from node pools. Instead of pre-creating a pool for every SKU you might want, you define constraints and let Karpenter pick:&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;karpenter.sh/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;NodePool&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;general&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;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;workload-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;general&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;nodeClassRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;karpenter.azure.com/v1alpha2&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;AKSNodeClass&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;default&lt;/span&gt;
      &lt;span class="na"&gt;requirements&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;karpenter.sh/capacity-type&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;In&lt;/span&gt;
          &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;on-demand"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spot"&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;kubernetes.io/arch&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;In&lt;/span&gt;
          &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amd64"&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;karpenter.azure.com/sku-family&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;In&lt;/span&gt;
          &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;D"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;E"&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;karpenter.azure.com/sku-version&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;Gt&lt;/span&gt;
          &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3"&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;200"&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;800Gi&lt;/span&gt;
  &lt;span class="na"&gt;disruption&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;consolidationPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;WhenEmptyOrUnderutilized&lt;/span&gt;
    &lt;span class="na"&gt;consolidateAfter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;karpenter.azure.com/v1alpha2&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;AKSNodeClass&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;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;imageFamily&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AzureLinux&lt;/span&gt;
  &lt;span class="na"&gt;osDiskSizeGB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;128&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note on API versions&lt;/strong&gt;: The &lt;code&gt;karpenter.azure.com&lt;/code&gt; API group is versioned separately from upstream Karpenter. &lt;code&gt;v1alpha2&lt;/code&gt; was current as of early 2026 but &lt;strong&gt;NEEDS_VALIDATION&lt;/strong&gt; check the CRD definitions in the installed chart before you copy this into a GitOps repo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What Works Well
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Spot consolidation&lt;/strong&gt; is the headline win. When spot VMs get preempted or you have underutilized nodes, Karpenter's consolidation loop handles bin-packing without you writing any automation. With CAS you're responsible for node pool min/max sizing and the consolidation is coarse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-SKU scheduling&lt;/strong&gt; is the other real win. A pod requesting 8 vCPU and 64 GiB RAM will cause Karpenter to search the allowed SKU families for a node that fits, rather than failing because your single pre-configured node pool is exhausted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GPU node provisioning&lt;/strong&gt; works, including time-slicing scenarios, as long as your &lt;code&gt;AKSNodeClass&lt;/code&gt; uses an image family that ships the NVIDIA drivers. AzureLinux with GPU extensions does this. You still need to manage the device plugin separately.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Still Rough
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Node provisioning latency&lt;/strong&gt; is higher than AWS because Azure VM creation is slower than EC2. Plan for 3–5 minutes from pod pending to node ready on cold starts. This isn't a Karpenter problem per se, but it affects how you design your buffer capacity and PodDisruptionBudgets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windows node pools&lt;/strong&gt; are not supported by the Azure Karpenter provider. If you have Windows workloads, keep a static node pool managed by CAS or manual scaling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Custom VNet/subnet selection&lt;/strong&gt; requires care. The &lt;code&gt;AKSNodeClass&lt;/code&gt; lets you specify subnet IDs, but if you're using private clusters with complex network topologies, test thoroughly before rolling to production. Subnet exhaustion errors surface late and are annoying to debug.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observability is immature&lt;/strong&gt;. Karpenter emits metrics to Prometheus and logs to stdout, but the AKS provider's specific actions (VM creation, NIC attachment) aren't surfaced as well as you'd want. You'll be reading &lt;code&gt;kubectl logs&lt;/code&gt; more than you'd like.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concrete Steps to a Safe Rollout
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start with a non-production cluster.&lt;/strong&gt; Run Karpenter alongside CAS, not instead of it. CAS can manage your system node pool; Karpenter handles a &lt;code&gt;workload&lt;/code&gt; node pool namespace.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Define &lt;code&gt;limits&lt;/code&gt; on your NodePool.&lt;/strong&gt; Without a CPU/memory ceiling, a scheduling bug or runaway HPA can provision hundreds of nodes before you notice. Set limits conservatively and raise them deliberately.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set &lt;code&gt;consolidateAfter&lt;/code&gt; to something sane for your workload.&lt;/strong&gt; 30 seconds is aggressive for stateful apps. Use 5–10 minutes for anything with slow startup or persistent volumes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test spot preemption handling.&lt;/strong&gt; Deploy a test workload on spot nodes and manually deallocate a VM. Verify that Karpenter reprovisioned within your acceptable window and that your pod disruption budgets held.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Add Karpenter's node labels to your monitoring dashboards.&lt;/strong&gt; Specifically track &lt;code&gt;karpenter.sh/capacity-type&lt;/code&gt;, &lt;code&gt;karpenter.azure.com/sku-name&lt;/code&gt;, and &lt;code&gt;karpenter.sh/nodepool&lt;/code&gt; as label dimensions so you can see cost and performance breakdown by node type.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pin your Helm chart version in GitOps.&lt;/strong&gt; The provider is still in active development. Uncontrolled upgrades have broken NodePool CRD schemas between minor versions. Treat upgrades as a planned event.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  CAS vs. Karpenter: The Honest Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;CAS&lt;/th&gt;
&lt;th&gt;Karpenter&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Operational maturity on AKS&lt;/td&gt;
&lt;td&gt;Production-grade&lt;/td&gt;
&lt;td&gt;Production-capable with caveats&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-SKU bin-packing&lt;/td&gt;
&lt;td&gt;Requires pre-defined pools&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spot handling&lt;/td&gt;
&lt;td&gt;Decent&lt;/td&gt;
&lt;td&gt;Better&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows nodes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debug tooling&lt;/td&gt;
&lt;td&gt;Mature&lt;/td&gt;
&lt;td&gt;Developing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure support&lt;/td&gt;
&lt;td&gt;First-party&lt;/td&gt;
&lt;td&gt;Community + Microsoft OSS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Karpenter on AKS in 2026 is the right choice if you have heterogeneous compute requirements and engineering capacity to own the operational model. It is not yet the "set it and forget it" experience that CAS is for straightforward clusters.&lt;/p&gt;

&lt;p&gt;The Azure team has been shipping at a reasonable pace and the GitHub issues backlog is actually getting shorter, which is a good sign. The API is stabilizing. The path from alpha to beta to stable is visible.&lt;/p&gt;

&lt;p&gt;Just don't copy that YAML into production without validating the API versions first. I warned you.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>aks</category>
      <category>karpenter</category>
      <category>autoscaling</category>
    </item>
  </channel>
</rss>
