DigitalOcean Kubernetes node pools can scale automatically, but the most surprising thing is how often their scaling behavior isn’t what you expect, even when the configuration seems correct.

Let’s see it in action. Imagine a node pool named default-pool in a Kubernetes cluster. Its auto-scaling is configured to keep between 1 and 5 nodes.

Here’s a snippet from a doctl command showing this configuration:

doctl k8s cluster node-pool get <your-cluster-id> default-pool --output json

The output would look something like this, with auto_scale set to true, and min_nodes and max_nodes defining the boundaries:

{
  "id": "default-pool",
  "name": "default-pool",
  "cluster_uuid": "<your-cluster-id>",
  "node_pool_id": "abcdef12-3456-7890-abcd-ef1234567890",
  "size": "s-2vcpu-4gb",
  "auto_scale": true,
  "min_nodes": 1,
  "max_nodes": 5,
  "nodes": [
    {
      "id": "node-1-abcdef12",
      "name": "abcdef12-3456-7890-abcd-ef1234567890-1",
      "droplet_id": 123456789,
      "status": "ready",
      "created_at": "2023-10-27T10:00:00Z"
    },
    {
      "id": "node-2-abcdef12",
      "name": "abcdef12-3456-7890-abcd-ef1234567890-2",
      "droplet_id": 123456790,
      "status": "ready",
      "created_at": "2023-10-27T10:05:00Z"
    }
  ],
  "tags": [],
  "auto_upgrade": true,
  "created_at": "2023-10-27T09:55:00Z",
  "updated_at": "2023-10-27T10:10:00Z"
}

This setup is designed to automatically adjust the number of nodes in default-pool based on the cluster’s resource demands, staying within the 1 to 5 node range. If your pods need more CPU or memory, and the existing nodes are full, Kubernetes will request new nodes from DigitalOcean. If nodes are underutilized for a sustained period, Kubernetes will scale down.

The problem auto-scaling solves is the manual overhead of managing cluster capacity. Instead of constantly monitoring your cluster and manually resizing node pools, you define a desired range, and the system handles the rest. This ensures your applications have the resources they need without overspending on idle infrastructure.

Internally, DigitalOcean Kubernetes (DOKS) uses the Kubernetes Cluster Autoscaler. This component watches for pods that cannot be scheduled due to resource constraints (CPU, memory) or node taints/tolerations. If it identifies that a pod could be scheduled if more nodes were available, it communicates with the DigitalOcean API to provision new Droplets for the specified node pool, up to the max_nodes limit. Conversely, it identifies nodes that have been underutilized for a configurable period and can safely be removed without impacting unschedulable pods, then scales down the node pool.

The key levers you control are:

  • min_nodes: The absolute minimum number of nodes that will always be present in the pool. This is your baseline capacity.
  • max_nodes: The absolute maximum number of nodes the pool can scale up to. This sets your upper limit for cost and availability.
  • size: The Droplet instance type (e.g., s-2vcpu-4gb) for all nodes in the pool. This determines the resources per node.

When you create or update a node pool, you specify these parameters. DigitalOcean then manages the underlying Droplets based on the Cluster Autoscaler’s decisions.

What most people miss is that the autoscaler doesn’t just look at CPU and memory requests. It also considers node taints and tolerations, node affinities, and pod anti-affinities. If a pod has a specific taint it needs to tolerate, and no available node has that toleration, the autoscaler will not add a new node unless that new node is configured (or can be configured) to tolerate the taint. This is crucial for workloads that have specific scheduling requirements.

The next concept you’ll likely encounter is how to fine-tune the autoscaler’s behavior beyond just min/max nodes, by exploring custom resource requests and limits on your pods.

Want structured learning?

Take the full Digitalocean course →