Sometimes you just want one specific node gone.

⚠️ Anti-Pattern Alert!

Yes, in theory nodes are cattle, not pets. But in real environments—especially in enterprise setups—you don’t always have that luxury. Maybe a node is flaky, maybe it’s tied to something broken, or maybe you just know that one needs to go.

Here’s how to do it in a Cluster API (CAPI) cluster without it coming back.


The problem

CAPI is declarative. If your cluster says “I want N nodes,” it will keep N nodes.

So if you run:

kubectl delete node <node>

that node will come back. The same happens if you delete the Machine object—CAPI will simply recreate it to match the desired state.


The trick

The only reliable way to control which node gets removed is to mark it before reducing capacity.

If you scale down first, CAPI will pick a Machine on its own, and at that point you’ve already lost control.

So the flow is simple:

flowchart TD
    A[Find target node] --> B[Find corresponding Machine]
    B --> C[Annotate Machine for deletion]
    C --> D{Using Cluster Autoscaler?}
    D -->|Yes| E[Update min/max size]
    D -->|No| F[Scale MachineDeployment replicas]
    E --> G[Node is removed]
    F --> G[Node is removed]

Step 1 — Find the Machine

Start by listing your nodes and picking the one you want to remove:

kubectl get nodes

Then list the Machines. You’re looking for the Machine that matches your node. The easiest way is to use:

kubectl get machines -A -o wide

This adds a NODE column, so you can match it directly with the node name:

NAMESPACE   NAME            NODE
default     worker-abc123   node-1

The NODE value should match the Kubernetes node you want to remove. If that column is empty, you can check manually:

kubectl get machine <machine-name> -n <namespace> -o yaml

and look for:

status:
  nodeRef:
    name: <node-name>

At the end of this step, you should have the Machine name and its namespace.


Step 2 — Annotate the Machine

Now mark that Machine for deletion:

kubectl annotate machine <machine-name> -n <namespace> \
  cluster.x-k8s.io/delete-machine="true"

This tells CAPI: “when you scale down, remove this one.”


Step 3 — Reduce capacity

At this point, you’ve told CAPI which Machine to remove. Now you just need to reduce the desired number of nodes so that a scale-down actually happens.

How you do that depends on whether your cluster is using the Cluster Autoscaler.


If you’re NOT using autoscaler

First, find your MachineDeployment:

kubectl get machinedeployments -A

Then scale it down:

kubectl scale machinedeployment <md-name> -n <namespace> --replicas=<new-count>

If you ARE using autoscaler

In this case, you don’t scale replicas directly because the autoscaler controls the node count.

If you’re not sure whether autoscaler is enabled, you can check quickly:

kubectl get machinedeployment <md-name> -n <namespace> -o yaml | grep autoscaler

If you see annotations like:

cluster.x-k8s.io/cluster-api-autoscaler-node-group-min-size
cluster.x-k8s.io/cluster-api-autoscaler-node-group-max-size

then autoscaler is managing your nodes. This is common on platforms like Nutanix Kubernetes Platform.

Instead of scaling replicas, update those limits:

kubectl annotate machinedeployment <md-name> -n <namespace> \
  cluster.x-k8s.io/cluster-api-autoscaler-node-group-min-size="<new-min>" \
  cluster.x-k8s.io/cluster-api-autoscaler-node-group-max-size="<new-max>" \
  --overwrite

Once the autoscaler decides to scale down, it will pick the Machine you annotated.


Verify

Finally, check that the node is gone and not replaced:

kubectl get machines -A
kubectl get nodes

TL;DR

flowchart LR
    A[Find the Machine] --> B[[Annotate it]]
    B --> C[Then reduce capacity]
  • No autoscaler → scale the MachineDeployment
  • Autoscaler → update min/max instead

If you do it in that order, CAPI will remove the node you chose—and it won’t come back.