Free — no signup required

The "Split" Architecture: Weighted NodePools

2 min read

How do you tell Kubernetes "run 20% of my app on On-Demand and 80% on Spot"? The answer is not to manage nodes directly — it's to express constraints on pods and let Karpenter figure out what nodes to build.

The Legacy Way (Hard)

With Cluster Autoscaler, you'd create two separate ASGs — one On-Demand, one Spot — and try to balance them using node labels, taints, and manual weight configurations. Every change required updating ASG definitions. Debugging required cross-referencing ASG state with pod scheduling events. It worked, but it was fragile.

The Karpenter Way: Topology Spread Constraints

Kubernetes has a native scheduling primitive called Topology Spread Constraints. It tells the scheduler: "Distribute my pods across some topology domain, and keep the distribution balanced within a defined skew."

Karpenter treats karpenter.sh/capacity-type (the label it applies to nodes indicating spot or on-demand) as a valid topology domain. This means you can spread pods across capacity types the same way you'd spread them across Availability Zones.

# In your Deployment spec
spec:
  topologySpreadConstraints:
    - maxSkew: 1
      topologyKey: karpenter.sh/capacity-type
      whenUnsatisfiable: ScheduleAnyway
      labelSelector:
        matchLabels:
          app: my-service

What this does, step by step:

  1. You deploy my-service with replicas: 10.
  2. The Kubernetes scheduler sees 10 pending pods and the topology spread constraint.
  3. It tries to place pods so that no capacity type has more than 1 extra pod compared to another (the maxSkew: 1 rule).
  4. Karpenter sees pods pending that require both spot and on-demand nodes, and launches both.
  5. Result: ~5 pods on Spot, ~5 pods on On-Demand — automatically, with no manual node management.

whenUnsatisfiable: ScheduleAnyway is important here: if Spot capacity is unavailable, the scheduler won't block the pods — it will schedule them on On-Demand and accept the imbalance. This prevents a Spot shortage from causing a deployment outage.

Pinning Critical Pods to On-Demand

For pods that must never run on Spot — databases, payment processors, admission webhooks — use a node selector or node affinity rule to hard-pin them to On-Demand nodes:

# In your critical Pod spec
spec:
  nodeSelector:
    karpenter.sh/capacity-type: on-demand

Karpenter will only schedule these pods on On-Demand nodes and will only launch On-Demand nodes to satisfy them. This is a hard constraint, not a preference.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free