Skip to content

How-to

Cluster autoscaling

Let a BKS cluster add worker nodes when pods can't be scheduled, and remove them when they're no longer needed, between a minimum and a maximum you set.

The cluster autoscaler watches for pods that can't be scheduled because no worker has room for them, and adds a worker. When a worker has been underused for a while and its pods fit elsewhere, it moves them and removes the worker. It works with the resource requests in your pods, so give every container a CPU and memory request. To change the number of pods with load instead, see Horizontal pod autoscaling; the two work together.

You turn autoscaling on when you create the cluster, with labels. The portal's New cluster form has no autoscaling settings, so use the CLI or OpenTofu.

Before you start

Create a cluster with autoscaling

Label Value
auto_scaling_enabled true
min_node_count The fewest workers to keep
max_node_count The most workers to add

Merge these labels with the template's, which set the Kubernetes version. Without merging, they replace the template's labels.

openstack --os-cloud <cloud-name> coe cluster create web-cluster \
  --cluster-template debian-13-v1.36.1 \
  --master-count 1 --node-count 1 \
  --keypair <key-name> \
  --merge-labels --labels auto_scaling_enabled=true,min_node_count=1,max_node_count=3
resource "openstack_containerinfra_cluster_v1" "web" {
  name                = "web-cluster"
  cluster_template_id = data.openstack_containerinfra_clustertemplate_v1.k8s.id
  master_count        = 1
  node_count          = 1
  keypair             = "<key-name>"
  merge_labels        = true
  labels = {
    auto_scaling_enabled = "true"
    min_node_count       = "1"
    max_node_count       = "3"
  }
}

Start --node-count or node_count within the range. Once the autoscaler manages the workers, leave the count to it rather than resizing by hand.

Check the settings

openstack --os-cloud <cloud-name> coe nodegroup show web-cluster default-worker -c labels -c min_node_count -c max_node_count

The labels include auto_scaling_enabled set to true, with your minimum and maximum.

Watch it scale

Run more replicas than the workers have room for. This deployment asks for half a vCPU per pod:

scale-test.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: scale-test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: scale-test
  template:
    metadata:
      labels:
        app: scale-test
    spec:
      containers:
        - name: pause
          image: registry.k8s.io/pause:3.10
          resources:
            requests:
              cpu: 500m
              memory: 256Mi
kubectl apply -f scale-test.yaml
kubectl scale deployment scale-test --replicas=20
kubectl get pods --field-selector=status.phase!=Running
kubectl get nodes

The first command lists the pods that don't fit yet. Within a few minutes a new worker joins, shows Ready, and the pods start on it. If the maximum is reached and pods still don't fit, they wait until the replicas go down or the maximum goes up.

Scale back down, and the autoscaler removes the extra workers once they've been underused for about 10 minutes, down to the minimum:

kubectl scale deployment scale-test --replicas=1
kubectl get nodes

Check it worked

  • With more pods than fit, kubectl get nodes shows more workers, up to the maximum.
  • After scaling back, the workers drop back towards the minimum.
  • kubectl delete -f scale-test.yaml removes the test.