<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged instance</title>
<link>https://coderlegion.com/tag/instance</link>
<description>Powered by Question2Answer</description>
<item>
<title>Kubernetes Cluster Autoscaler vs Karpenter: When to Use Each (2026)</title>
<link>https://coderlegion.com/23256/kubernetes-cluster-autoscaler-vs-karpenter-when-to-use-each-2026</link>
<description>
&lt;a href=&quot;https://alexandre-vazquez.com/cluster-autoscaler-vs-karpenter/&quot; title=&quot;Kubernetes Cluster Autoscaler vs Karpenter: When to Use Each (2026)&quot; rel=&quot;nofollow&quot;&gt;&lt;img width=&quot;1536&quot; height=&quot;1024&quot; src=&quot;https://mlk5tkvgfeoa.i.optimole.com/cb:s8WW.68/w:1536/h:1024/q:mauto/f:best/https://alexandre-vazquez.com/wp-content/uploads/2026/07/cluster-autoscaler-vs-karpenter-483d539ae1f4.avif&quot; class=&quot;webfeedsFeaturedVisual wp-post-image&quot; alt=&quot;Kubernetes Cluster Autoscaler vs Karpenter: When to Use Each (2026)&quot; style=&quot;display: block; margin: auto; margin-bottom: 5px;max-width: 100%;&quot; title=&quot;Kubernetes Cluster Autoscaler vs Karpenter: When to Use Each (2026) 16&quot;&gt;&lt;/a&gt;&lt;p&gt;Your pods are pending. Your on-call engineer is getting paged. Somewhere in the chain between &amp;ldquo;I need more compute&amp;rdquo; and &amp;ldquo;compute is available,&amp;rdquo; something is too slow. That something is almost always node provisioning &amp;mdash; and the tool you chose to manage it determines whether that delay is 4 minutes or 45 seconds.&lt;/p&gt;
&lt;p&gt;Node autoscaling is one of those infrastructure decisions that looks simple until you&amp;rsquo;re running it in production. Two schedulable pods sitting in Pending state doesn&amp;rsquo;t just mean a delayed deployment &amp;mdash; it means latency spikes, dropped traffic, breached SLOs, and engineers debugging things that should have been invisible. At scale, it also means either burning money on over-provisioned nodes or gambling on under-provisioning at the worst possible moment.&lt;/p&gt;
&lt;p&gt;Cluster Autoscaler (CA) has been the default answer for years. Karpenter emerged from AWS in 2021, graduated to stable in 2023, and by 2025 had become the default recommendation for most AWS-native clusters. In 2026, both tools are mature, widely deployed, and genuinely good &amp;mdash; but they solve the problem differently, and picking the wrong one for your environment has real consequences.&lt;/p&gt;
&lt;p&gt;This article is a deep technical comparison. It assumes you already know what Kubernetes is and have opinions about infrastructure. The goal is to give you a clear picture of &lt;em&gt;how&lt;/em&gt; each tool works, where each one wins, and a decision framework you can actually use.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;why-node-autoscaling-is-hard&quot;&gt;Why Node Autoscaling Is Hard&lt;/h2&gt;
&lt;p&gt;The fundamental tension in autoscaling is this: you want compute available before you need it, but you don&amp;rsquo;t want to pay for compute you&amp;rsquo;re not using. These goals are in direct conflict, and every autoscaling system is an attempt to find the least-bad trade-off.&lt;/p&gt;
&lt;p&gt;Without autoscaling, you&amp;rsquo;re doing one of two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Over-provisioning&lt;/strong&gt; &amp;mdash; you run enough nodes to handle peak load at all times. Your average utilization sits at 20&amp;ndash;30%, and you&amp;rsquo;re paying for the other 70&amp;ndash;80% to sit idle.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Under-provisioning&lt;/strong&gt; &amp;mdash; you run lean, and when traffic spikes, pods go Pending. Your SLOs breach. You get paged at 3am to manually scale.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A common failure mode with poorly tuned autoscaling is the &amp;ldquo;thundering herd at scale-up&amp;rdquo; pattern: HPA creates new pods faster than node autoscaling can provision capacity. The provisioning window matters. With CA and typical ASG-backed node groups on AWS, you&amp;rsquo;re looking at 4&amp;ndash;8 minutes. With Karpenter, 60&amp;ndash;90 seconds. At 100 RPS and a 3-minute window, that&amp;rsquo;s 18,000 requests under degraded conditions.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;cluster-autoscaler-how-it-actually-works&quot;&gt;Cluster Autoscaler: How It Actually Works&lt;/h2&gt;
&lt;p&gt;Cluster Autoscaler is a Kubernetes-native project under the kubernetes/autoscaler repository, in production since 2016, supporting AWS, GCP, Azure, Alibaba, DigitalOcean, and more.&lt;/p&gt;
&lt;h3 id=&quot;the-node-group-model&quot;&gt;The Node Group Model&lt;/h3&gt;
&lt;p&gt;CA operates on &lt;strong&gt;node groups&lt;/strong&gt; &amp;mdash; ASGs on AWS, MIGs on GCP, VMSSs on Azure. CA&amp;rsquo;s job is to decide when to increase or decrease the desired capacity of these groups. &lt;strong&gt;CA does not provision individual nodes. It scales node groups, and the node group provisions nodes.&lt;/strong&gt; This indirection adds latency and reduces flexibility.&lt;/p&gt;
&lt;h3 id=&quot;scale-up-detecting-unschedulable-pods&quot;&gt;Scale-Up: Detecting Unschedulable Pods&lt;/h3&gt;
&lt;p&gt;CA runs a control loop (default scan interval: 10 seconds). For each &lt;code&gt;Pending&lt;/code&gt; pod with &lt;code&gt;PodScheduled=False&lt;/code&gt;, CA simulates adding a node of each known node group type and checks if the pod would become schedulable. When a node group is selected, CA applies an &lt;strong&gt;expander&lt;/strong&gt; to choose which group to scale:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;least-waste&lt;/code&gt; &amp;mdash; minimizes CPU/memory waste after scheduling (best default for cost)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;most-pods&lt;/code&gt; &amp;mdash; maximizes pods scheduled per scale-up operation&lt;/li&gt;
&lt;li&gt;&lt;code&gt;priority&lt;/code&gt; &amp;mdash; lets you define ordering via ConfigMap&lt;/li&gt;
&lt;li&gt;&lt;code&gt;grpc&lt;/code&gt; &amp;mdash; delegates to an external gRPC service&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Cluster Autoscaler deployment &amp;mdash; AWS, production-tuned
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cluster-autoscaler
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: cluster-autoscaler
  template:
    metadata:
      labels:
        app: cluster-autoscaler
      annotations:
        cluster-autoscaler.kubernetes.io/safe-to-evict: &quot;false&quot;
    spec:
      priorityClassName: system-cluster-critical
      serviceAccountName: cluster-autoscaler
      containers:
        - image: registry.k8s.io/autoscaling/cluster-autoscaler:v1.30.3
          name: cluster-autoscaler
          resources:
            requests:
              cpu: 100m
              memory: 600Mi
            limits:
              cpu: 200m
              memory: 1Gi
          command:
            - ./cluster-autoscaler
            - --cloud-provider=aws
            - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/my-cluster
            - --expander=least-waste
            - --balance-similar-node-groups=true
            - --scale-down-delay-after-add=10m
            - --scale-down-unneeded-time=10m
            - --scale-down-utilization-threshold=0.5
            - --max-graceful-termination-sec=600
            - --scan-interval=10s
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;scale-down-the-conservative-approach&quot;&gt;Scale-Down: The Conservative Approach&lt;/h3&gt;
&lt;p&gt;A node is a scale-down candidate only if:&lt;br&gt;
&amp;ndash; CPU and memory utilization (by requests) is below threshold (default: 50%)&lt;br&gt;
&amp;ndash; All pods could be rescheduled elsewhere&lt;br&gt;
&amp;ndash; No pod has &lt;code&gt;cluster-autoscaler.kubernetes.io/safe-to-evict: &quot;false&quot;&lt;/code&gt;&lt;br&gt;
&amp;ndash; The node has been underutilized for at least &lt;code&gt;--scale-down-unneeded-time&lt;/code&gt; (default: 10m)&lt;/p&gt;
&lt;p&gt;This conservatism prevents churn &amp;mdash; a feature, not a bug.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;karpenter-how-it-actually-works&quot;&gt;Karpenter: How It Actually Works&lt;/h2&gt;
&lt;p&gt;Karpenter is a CNCF incubating project originally built by AWS, donated to CNCF in 2023, GA (v1.0) in mid-2024. Providers exist for AWS (stable), Azure (stable), and GCP (beta).&lt;/p&gt;
&lt;h3 id=&quot;the-core-insight-bypass-the-node-group&quot;&gt;The Core Insight: Bypass the Node Group&lt;/h3&gt;
&lt;p&gt;Karpenter &lt;strong&gt;calls the EC2 &lt;code&gt;RunInstances&lt;/code&gt; API directly&lt;/strong&gt; &amp;mdash; no ASG involvement. This means:&lt;br&gt;
&amp;ndash; Any instance type in a single request, without pre-configuring a node group&lt;br&gt;
&amp;ndash; No intermediary: Karpenter &amp;rarr; EC2 API &amp;rarr; node joins cluster&lt;br&gt;
&amp;ndash; Right-size nodes to exactly what workloads need, across the full instance catalog&lt;br&gt;
&amp;ndash; Karpenter handles full node lifecycle, including termination&lt;/p&gt;
&lt;h3 id=&quot;nodepool-and-ec2nodeclass&quot;&gt;NodePool and EC2NodeClass&lt;/h3&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;# EC2NodeClass &amp;mdash; cloud-specific parameters
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
  name: default
spec:
  amiSelectorTerms:
    - alias: al2023@latest
  role: &quot;KarpenterNodeRole-my-cluster&quot;
  subnetSelectorTerms:
    - tags:
        karpenter.sh/discovery: &quot;my-cluster&quot;
  securityGroupSelectorTerms:
    - tags:
        karpenter.sh/discovery: &quot;my-cluster&quot;
  blockDeviceMappings:
    - deviceName: /dev/xvda
      ebs:
        volumeSize: 50Gi
        volumeType: gp3
        encrypted: true
  metadataOptions:
    httpTokens: required
    httpPutResponseHopLimit: 1
---
# NodePool &amp;mdash; intent and constraints
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: general-purpose
spec:
  template:
    spec:
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: default
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: [&quot;on-demand&quot;, &quot;spot&quot;]
        - key: kubernetes.io/arch
          operator: In
          values: [&quot;amd64&quot;, &quot;arm64&quot;]
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: [&quot;c&quot;, &quot;m&quot;, &quot;r&quot;]
        - key: karpenter.k8s.aws/instance-generation
          operator: Gt
          values: [&quot;5&quot;]
        - key: karpenter.k8s.aws/instance-size
          operator: NotIn
          values: [&quot;nano&quot;, &quot;micro&quot;, &quot;small&quot;, &quot;medium&quot;, &quot;large&quot;]
      expireAfter: 720h
  limits:
    cpu: &quot;1000&quot;
    memory: 1000Gi
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 5m
    budgets:
      - nodes: &quot;5%&quot;
        schedule: &quot;0 8 * * mon-fri&quot;
        duration: 10h
      - nodes: &quot;25%&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;just-in-time-provisioning-and-bin-packing&quot;&gt;Just-in-Time Provisioning and Bin Packing&lt;/h3&gt;
&lt;p&gt;When pods go Pending, Karpenter watches the event (not polls) and immediately:&lt;br&gt;
1. Collects all Pending pods&lt;br&gt;
2. Simulates bin packing &amp;mdash; fewest possible nodes across the full instance catalog&lt;br&gt;
3. Selects instances that satisfy all pod requirements&lt;br&gt;
4. Calls EC2 API to provision the optimal instance(s)&lt;/p&gt;
&lt;h3 id=&quot;disruption-and-consolidation&quot;&gt;Disruption and Consolidation&lt;/h3&gt;
&lt;p&gt;Karpenter&amp;rsquo;s differentiated value: active cluster consolidation. It evaluates whether nodes can be removed by redistributing pods onto others, or &lt;strong&gt;replaced with a smaller instance type&lt;/strong&gt;. A &lt;code&gt;c5.4xlarge&lt;/code&gt; running 4 vCPU worth of pods gets replaced with a &lt;code&gt;c5.xlarge&lt;/code&gt;. Teams commonly report 30&amp;ndash;50% compute cost reduction.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;consolidationPolicy&lt;/code&gt; options:&lt;br&gt;
&amp;ndash; &lt;code&gt;WhenEmpty&lt;/code&gt; &amp;mdash; only remove nodes with no workload pods (safest)&lt;br&gt;
&amp;ndash; &lt;code&gt;WhenEmptyOrUnderutilized&lt;/code&gt; &amp;mdash; also replace underutilized nodes with smaller ones&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;architecture-comparison&quot;&gt;Architecture Comparison&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Cluster Autoscaler&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;&lt;strong&gt;Node provisioning model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Scales node groups (ASG/MIG/VMSS)&lt;/td&gt;
&lt;td&gt;Direct cloud API, no node groups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Instance flexibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pre-defined node group types&lt;/td&gt;
&lt;td&gt;Full instance catalog at runtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scale-up trigger&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Polling (10s scan interval)&lt;/td&gt;
&lt;td&gt;Watch-based event (near-instant)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scale-down&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Removes underutilized nodes&lt;/td&gt;
&lt;td&gt;Removes + consolidates + right-sizes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Spot handling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Via ASG + AWS Node Termination Handler&lt;/td&gt;
&lt;td&gt;Native, first-class, no NTH needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Configuration model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Deployment flags&lt;/td&gt;
&lt;td&gt;Declarative CRDs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cloud support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All major + on-prem&lt;/td&gt;
&lt;td&gt;AWS (GA), Azure (stable), GCP (beta)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Consolidation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Community maturity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Very mature (since 2016)&lt;/td&gt;
&lt;td&gt;Mature (GA 2024)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&quot;scaling-speed-the-numbers&quot;&gt;Scaling Speed: The Numbers&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Cluster Autoscaler on AWS (typical):&lt;/strong&gt;&lt;br&gt;
1. Pod Pending &amp;rarr; CA scan detects (0&amp;ndash;10s)&lt;br&gt;
2. ASG UpdateAutoScalingGroup API call (~15&amp;ndash;30s)&lt;br&gt;
3. EC2 instance starts (1&amp;ndash;2 min)&lt;br&gt;
4. Node bootstrap + kubelet registration (30&amp;ndash;60s)&lt;br&gt;
5. Pod scheduled (5&amp;ndash;10s)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Total: 3&amp;ndash;6 minutes&lt;/strong&gt; (up to 12 min during high-demand periods)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Karpenter on AWS (typical):&lt;/strong&gt;&lt;br&gt;
1. Pod Pending &amp;rarr; watch event fires (~1s)&lt;br&gt;
2. EC2 RunInstances API call (~2&amp;ndash;3s)&lt;br&gt;
3. EC2 instance starts (same hardware &amp;mdash; 1&amp;ndash;2 min)&lt;br&gt;
4. Node bootstraps + Ready (30&amp;ndash;60s)&lt;br&gt;
5. Pod scheduled (~5s)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Total: 90 seconds to 3 minutes&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;cost-optimization-where-karpenter-pulls-ahead&quot;&gt;Cost Optimization: Where Karpenter Pulls Ahead&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Right-sizing:&lt;/strong&gt; CA requires pre-defined node groups. Karpenter selects the minimum viable instance for the pending workload from the full catalog.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Consolidation vs scale-down:&lt;/strong&gt; CA removes underutilized nodes. Karpenter replaces a large underutilized node with a smaller one that still fits all pods. This produces compounding savings over time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spot handling:&lt;/strong&gt; Karpenter receives EC2 interruption notices, pre-provisions a replacement, and drains the node &amp;mdash; all within the 2-minute window. No AWS Node Termination Handler required. It also diversifies spot requests across instance types automatically to reduce simultaneous interruption risk.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;multi-cloud-support-in-2026&quot;&gt;Multi-Cloud Support in 2026&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cloud&lt;/th&gt;
&lt;th&gt;Cluster Autoscaler&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;AWS&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;https://s.w.org/images/core/emoji/16.0.1/72x72/2705.png&quot; alt=&quot;&amp;#9989;&quot; class=&quot;wp-smiley&quot; style=&quot;height: 1em; max-height: 1em;&quot;&gt; Production-stable&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;https://s.w.org/images/core/emoji/16.0.1/72x72/2705.png&quot; alt=&quot;&amp;#9989;&quot; class=&quot;wp-smiley&quot; style=&quot;height: 1em; max-height: 1em;&quot;&gt; Production-stable (reference impl.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GCP&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;https://s.w.org/images/core/emoji/16.0.1/72x72/2705.png&quot; alt=&quot;&amp;#9989;&quot; class=&quot;wp-smiley&quot; style=&quot;height: 1em; max-height: 1em;&quot;&gt; Production-stable&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;https://s.w.org/images/core/emoji/16.0.1/72x72/26a0.png&quot; alt=&quot;&amp;#9888;&quot; class=&quot;wp-smiley&quot; style=&quot;height: 1em; max-height: 1em;&quot;&gt; Beta (karpenter-provider-gcp)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;https://s.w.org/images/core/emoji/16.0.1/72x72/2705.png&quot; alt=&quot;&amp;#9989;&quot; class=&quot;wp-smiley&quot; style=&quot;height: 1em; max-height: 1em;&quot;&gt; Production-stable&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;https://s.w.org/images/core/emoji/16.0.1/72x72/2705.png&quot; alt=&quot;&amp;#9989;&quot; class=&quot;wp-smiley&quot; style=&quot;height: 1em; max-height: 1em;&quot;&gt; Stable (karpenter-provider-azure)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alibaba&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;https://s.w.org/images/core/emoji/16.0.1/72x72/2705.png&quot; alt=&quot;&amp;#9989;&quot; class=&quot;wp-smiley&quot; style=&quot;height: 1em; max-height: 1em;&quot;&gt; Supported&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;https://s.w.org/images/core/emoji/16.0.1/72x72/274c.png&quot; alt=&quot;&amp;#10060;&quot; class=&quot;wp-smiley&quot; style=&quot;height: 1em; max-height: 1em;&quot;&gt; No provider&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DigitalOcean&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;https://s.w.org/images/core/emoji/16.0.1/72x72/2705.png&quot; alt=&quot;&amp;#9989;&quot; class=&quot;wp-smiley&quot; style=&quot;height: 1em; max-height: 1em;&quot;&gt; Supported&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;https://s.w.org/images/core/emoji/16.0.1/72x72/274c.png&quot; alt=&quot;&amp;#10060;&quot; class=&quot;wp-smiley&quot; style=&quot;height: 1em; max-height: 1em;&quot;&gt; No provider&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;On-premises / Cluster API&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;https://s.w.org/images/core/emoji/16.0.1/72x72/2705.png&quot; alt=&quot;&amp;#9989;&quot; class=&quot;wp-smiley&quot; style=&quot;height: 1em; max-height: 1em;&quot;&gt; Supported&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;https://s.w.org/images/core/emoji/16.0.1/72x72/274c.png&quot; alt=&quot;&amp;#10060;&quot; class=&quot;wp-smiley&quot; style=&quot;height: 1em; max-height: 1em;&quot;&gt; Not supported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&quot;when-cluster-autoscaler-is-still-the-right-choice&quot;&gt;When Cluster Autoscaler Is Still the Right Choice&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Non-AWS environments&lt;/strong&gt; &amp;mdash; GCP, Alibaba, DigitalOcean, on-prem with Cluster API&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Existing node group architecture&lt;/strong&gt; &amp;mdash; significant investment in ASG design, compliance tooling&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Regulatory constraints&lt;/strong&gt; &amp;mdash; some frameworks require ASG-backed provisioning audit trails&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cluster API / bare metal&lt;/strong&gt; &amp;mdash; CA is the only mature option&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Team familiarity and working-well CA deployment&lt;/strong&gt; &amp;mdash; migration cost may not justify benefit&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&quot;when-karpenter-is-the-right-choice&quot;&gt;When Karpenter Is the Right Choice&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;AWS-native, cost optimization priority&lt;/strong&gt; &amp;mdash; right-sizing + consolidation = meaningful cost reduction&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Diverse and variable workloads&lt;/strong&gt; &amp;mdash; batch, spot, GPU, stateless APIs &amp;mdash; Karpenter handles all with a few NodePools&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spot-heavy clusters&lt;/strong&gt; &amp;mdash; native interruption handling, diversification, no NTH&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Declarative infrastructure-as-code culture&lt;/strong&gt; &amp;mdash; NodePools version cleanly in Git&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Low-latency scaling requirements&lt;/strong&gt; &amp;mdash; event-driven workloads, KEDA-triggered jobs, sharp traffic spikes&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&quot;running-both-migration-path-and-gotchas&quot;&gt;Running Both: Migration Path and Gotchas&lt;/h2&gt;
&lt;h3 id=&quot;separating-responsibility&quot;&gt;Separating Responsibility&lt;/h3&gt;
&lt;p&gt;Use labels and taints to prevent CA and Karpenter from managing the same nodes:&lt;/p&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;# NodePool with taint &amp;mdash; CA-managed pods won't tolerate this
spec:
  template:
    metadata:
      labels:
        provisioner: karpenter
    spec:
      taints:
        - key: karpenter.sh/provisioned
          value: &quot;true&quot;
          effect: NoSchedule
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;gradual-migration&quot;&gt;Gradual Migration&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Phase 1&lt;/strong&gt; &amp;mdash; Karpenter manages spot/batch workloads. CA manages on-demand production nodes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phase 2&lt;/strong&gt; &amp;mdash; Migrate spot workloads fully. Remove AWS NTH.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phase 3&lt;/strong&gt; &amp;mdash; Migrate on-demand. Reduce CA node group capacity gradually.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phase 4&lt;/strong&gt; &amp;mdash; Decommission CA once all groups are empty.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;key-gotchas&quot;&gt;Key Gotchas&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Karpenter consolidation + permissive PDBs&lt;/strong&gt; &amp;mdash; &lt;code&gt;maxUnavailable: 100%&lt;/code&gt; will cause disruptive consolidation. Audit PDBs before enabling &lt;code&gt;WhenEmptyOrUnderutilized&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NodePool limits are hard stops&lt;/strong&gt; &amp;mdash; pods go Pending indefinitely at limit. Monitor utilization.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AMI drift&lt;/strong&gt; &amp;mdash; &lt;code&gt;@latest&lt;/code&gt; alias picks up new AMIs on new nodes. Consider pinning for strict change control.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simultaneous scale-down conflicts&lt;/strong&gt; &amp;mdash; use strict label/taint segregation during migration.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;decision-framework&quot;&gt;Decision Framework&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Factor&lt;/th&gt;
&lt;th&gt;Cluster Autoscaler&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;Cloud support&lt;/td&gt;
&lt;td&gt;All clouds +&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/23256/kubernetes-cluster-autoscaler-vs-karpenter-when-to-use-each-2026</guid>
<pubDate>Thu, 30 Jul 2026 10:00:00 +0000</pubDate>
</item>
</channel>
</rss>