Skip to content
Install the CLI

Explanation

Availability levels

When you move a Kubernetes cluster from a single-node laptop environment to a multi-zone cloud environment, you normally have to revisit every Deployment and StatefulSet to bump replica counts, add pod anti-affinity rules, and create PodDisruptionBudgets. In Kix, you declare the failure scope your cluster needs (none, pod, node, or zone) in one place, and Kix works with each package to configure replicas, placement constraints, and disruption budgets automatically.

Rather than asking a cluster operator to know the replica flags of every package in the cluster, Kix defines four availability levels based on what kind of failure the cluster must survive without downtime:

LevelWhat the service must survive
noneNothing guaranteed; a pod crash or rolling update may cause brief downtime.
podLosing a single pod, or replacing pods during a rolling update, must not cause downtime.
nodeLosing an entire Kubernetes worker node must not cause downtime.
zoneLosing an entire cloud availability zone must not cause downtime.

The cluster’s declared hardware capabilities establish the read-only cluster.availability.substrate option, which records the highest level the underlying nodes can support and provides the default for cluster.availability.default. Each package then translates the active level into its own replica and quorum counts, and Kix adds the matching placement rules and PodDisruptionBudgets.

One requirement, several compiled decisions

Section titled “One requirement, several compiled decisions”

Different kinds of software need different numbers of replicas to survive the same failure. A stateless HTTP server only needs 2 replicas to survive a pod, node, or zone outage, as long as those 2 pods sit in different failure domains. A Raft or Paxos quorum store needs at least 3 members so it can lose one member and still keep a majority. A legacy controller that does not support leader election may only be able to run 1 replica no matter what the cluster asks for.

Kix splits this decision cleanly between the package author and the cluster operator:

  • The package author knows the software’s architecture and uses kix.availability.pick availability { ... } to map none, pod, node, and zone to appropriate replica counts.
  • The cluster operator sets cluster.availability.default on the cluster (or overrides availability on a specific instance) without needing to memorize each package’s internal options.

Whenever a Deployment or StatefulSet resolves to more than one replica under an availability level above none, Kix automatically derives:

  • topologySpreadConstraints across the cluster’s failure-domain labels (kubernetes.io/hostname and topology.kubernetes.io/zone);
  • hard placement (DoNotSchedule) on the domain required by the chosen level, and best-effort placement (ScheduleAnyway) on the remaining domains;
  • a PodDisruptionBudget with maxUnavailable = 1 selecting the workload’s pods.

The generated topology spread constraints use maxSkew = 1. That balances pods evenly across the available failure domains without requiring the replica count to be an exact multiple of the zone count (for example, 5 replicas across 3 zones settle cleanly as 2/2/1).

Hardware capabilities keep configuration honest

Section titled “Hardware capabilities keep configuration honest”

Setting replicas = 3 on a single-node cluster gives a false sense of security: if the one node goes down, all three pods go down with it. Similarly, adding zone spread constraints on a cluster whose nodes have no topology.kubernetes.io/zone labels will either leave pods Pending or pack them onto the same hardware.

Kix checks the requested availability level against cluster.capabilities.multiNode and cluster.capabilities.availabilityZones:

  • A confirmed single-node cluster (multiNode = false, such as kix.flavors.kind) supports at most none.
  • A multi-node cluster without multiple zones supports up to node.
  • A multi-node cluster with two or more declared zones supports zone.

If you request a level higher than the cluster’s substrate and the deciding capabilities are explicitly set (multiNode = false or an explicit availabilityZones list with fewer than two zones), evaluation fails immediately with a clear error. When the requested level is above the inferred substrate and the substrate is uncertain because a deciding capability is left unset (null), Kix emits a warning so you know the substrate guarantees could not be verified at build time.

Some programs cannot run multiple active replicas safely. When a package declares meta.availability.max (for example, max = "none" or max = "pod"), Kix caps the resolved availability level for that package at its ceiling and emits a warning when the cluster requested a higher level.

Other packages combine a replicated data plane with a single-replica management component in the same package. For those cases, the individual workload builder (scope.mkDeployment or scope.mkStatefulSet) can set availability.max = "none" on just that workload while the rest of the package honors the full cluster level. Because a none ceiling means the workload cannot safely run concurrent copies, Kix rejects a workload that sets availability.max = "none" alongside replicas > 1.

When a package explicitly sets its own topologySpreadConstraints on a workload, Kix steps back: it neither injects generated spread constraints nor generates a default PodDisruptionBudget for that workload. If a multi-replica workload supplies custom placement constraints without shipping a matching PodDisruptionBudget in the same instance, Kix emits a warning so voluntary-disruption protection is not forgotten by accident.