Skip to main content

Scheduling

Scheduling is the process Kubernetes uses to decide which node a pod runs on. The operator gives you control over where the SQL Server pods of an MSSQLInstance or MSSQLAvailabilityGroup are placed, so you can spread replicas across failure domains, isolate SQL Server on dedicated nodes, and tolerate node taints.

See the Kubernetes scheduling documentation for background on affinity, anti-affinity, node selectors, taints, and tolerations.

Placement is configured through fields shared by both kinds:

  • spec.placement — high-level pod anti-affinity knob (the common case)
  • spec.nodeSelector — restrict pods to nodes with matching labels
  • spec.tolerations — allow pods onto tainted nodes
  • spec.topologySpreadConstraints — even pod spread across topology domains
  • spec.affinity — raw, full affinity override (escape hatch)
  • spec.priorityClassName — scheduling priority

Pod anti-affinity (spec.placement)​

By default, the operator generates soft pod anti-affinity so that replicas of the same instance or Availability Group prefer to run on different nodes. A single node failure then cannot take down every replica at once.

apiVersion: mssql.solanica.io/v1alpha1
kind: MSSQLAvailabilityGroup
metadata:
name: ag-example
spec:
size: 3
placement:
antiAffinity: preferred # default
topologyKey: kubernetes.io/hostname # default
storage:
size: 20Gi

This produces the following pod anti-affinity, selecting the pods of this specific resource by their app.kubernetes.io/instance label:

affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/instance: ag-example
topologyKey: kubernetes.io/hostname

antiAffinity modes​

ModeBehavior
preferredSoft anti-affinity (default). The scheduler tries to spread replicas but still schedules a pod if no separate node is available.
requiredHard anti-affinity. Two replicas are never co-located in the same topologyKey domain. Pods stay Pending if there are not enough domains.
noneThe operator generates no anti-affinity.

Setting required enforces strict separation:

spec:
placement:
antiAffinity: required
topologyKey: kubernetes.io/hostname

Note: With required, a 3-replica Availability Group needs at least three schedulable nodes (or zones). If fewer are available, the surplus pods remain Pending. This is especially relevant with a cluster autoscaler.

Topology considerations​

Set topologyKey to topology.kubernetes.io/zone to spread replicas across availability zones rather than individual nodes:

spec:
placement:
antiAffinity: required
topologyKey: topology.kubernetes.io/zone

See Well-Known Labels, Annotations, and Taints for other topology keys.

Fine-grained control with custom rules​

For scenarios needing more precise control, add your own rules with placement.additionalPodAffinity and placement.additionalPodAntiAffinity. These are merged with the operator-generated anti-affinity (or used on their own when antiAffinity: none). Provide the full pod affinity structure expected by the pod spec.

spec:
placement:
antiAffinity: preferred # generated soft rule is kept
additionalPodAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: workload
operator: In
values: [sqlserver]
topologyKey: kubernetes.io/hostname

Raw affinity override​

When you need complete control, set spec.affinity with the raw Kubernetes Affinity object. It takes full precedence: the generated anti-affinity and the additionalPod* rules are ignored.

spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.kubernetes.io/mssql
operator: Exists

Node selection (spec.nodeSelector)​

Restrict the SQL Server pods to nodes carrying specific labels. Every key-value pair must be present on a node for a pod to schedule there.

spec:
nodeSelector:
node-role.kubernetes.io/mssql: ""

Tolerations (spec.tolerations)​

If nodes are tainted to repel general workloads, add matching tolerations so the SQL Server pods can schedule onto them. Uses the standard Kubernetes toleration syntax.

spec:
tolerations:
- key: node-role.kubernetes.io/mssql
operator: Exists
effect: NoSchedule

See the Kubernetes taints and tolerations documentation for details.

Topology spread constraints (spec.topologySpreadConstraints)​

For even distribution (rather than just "keep apart"), apply topologySpreadConstraints. They are passed through to the pod spec verbatim.

spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/instance: ag-example

Priority (spec.priorityClassName)​

Assign a PriorityClass so SQL Server pods are scheduled ahead of, and evicted after, lower-priority workloads under resource pressure.

spec:
priorityClassName: high-priority

Isolating SQL Server workloads​

For production, a common pattern combines dedicated nodes with hard replica separation:

spec:
size: 3
placement:
antiAffinity: required
topologyKey: kubernetes.io/hostname
nodeSelector:
node-role.kubernetes.io/mssql: ""
tolerations:
- key: node-role.kubernetes.io/mssql
operator: Exists
effect: NoSchedule

This runs SQL Server only on nodes reserved (labeled and tainted) for it, with each replica on a distinct node.