Manage Nodes on Bare Metal
This document explains how to scale worker nodes up and down, replace specific machines, and recover failed nodes on the bare-metal provider. Node management uses Cluster API Machine resources orchestrated through MachineDeployment; the provider binds each Machine to one MachineInventory from a pool and drives the host through clean / reprovision plans.
To upgrade the Kubernetes version of the nodes, see Upgrade Kubernetes on Bare Metal.
TOC
PrerequisitesOverviewNode Management OperationsScaling Worker NodesAdding Worker NodesRemoving Worker NodesReplacing a Single Failed NodeMoving Workers to a Different PoolUpdating Bootstrap TemplatesPool and Inventory ObservabilityCommon Failure ModesNext StepsPrerequisites
Important Prerequisites
- The control plane must already be running. See Create Cluster.
- The worker
MachineInventoryPoolmust contain at least as manyAvailableinventories as the target replica count, plus the headroom required by the rollout strategy. - The target
Machine.spec.versionmust be a key in theelemental-image-catalogConfigMap. - Any inventory with non-empty
spec.storage.volumes[]must already reportstatus.storage.phase=PreparedandStoragePrepared=Truebefore it can count asAvailable. Follow Manage Data Disks on Bare-Metal Hosts before adding a newly registered storage-managed inventory to the worker pool. - To manage the nodes of the
globalcluster itself, the provider must be installed onglobalfirst; see Manage Nodes on Alauda OS Clusters.
Configuration Guidelines
When working with the configurations in this document:
- Only modify values enclosed in
<>brackets. - Replace placeholder values with your environment-specific settings.
- Preserve all other default configurations unless explicitly required.
Overview
The four resources that compose a worker node group:
MachineInventoryPool(<cluster-name>-worker-pool) — the allowed set ofMachineInventorynames. Already created in Create Cluster → Step 2.BaremetalMachineTemplate(<cluster-name>-worker-template) — references the worker pool. To move the workers to a different pool, see Moving Workers to a Different Pool.KubeadmConfigTemplate(<cluster-name>-worker-bootstrap) — cloud-inituser-dataforkubeadm join. The bare-metal provider normalizes this user-data at reprovision time (hostname,provider-id,criSocket); operators should not pre-fill those fields.MachineDeployment— controls replica count, version, rollout strategy.
Managed data disks are not part of BaremetalMachineTemplate. Their declaration and retained data belong to each long-lived MachineInventory, so two members of the same worker pool may expose different host-local datasets unless operators standardize and verify their storage declarations. Managed storage is changed separately on an unallocated, inactive MachineInventory; see Manage Data Disks on Bare-Metal Hosts.
To add another worker node pool with YAML, follow Step 4: Deploy Worker Nodes on the cluster creation page.
Node Management Operations
Scaling Worker Nodes
Adding Worker Nodes
Use Case: Increase cluster capacity.
Prerequisites:
- The worker pool has enough
Availableinventories. If not, register the additional hosts (boot the SeedImage ISO and confirm the newMachineInventoryobjects), prepare any managed storage, and append them toMachineInventoryPool.spec.machineInventories[].
Procedure:
-
Check current state
Confirm that
MachineInventoryPool.status.availableis high enough for the planned increment. -
Extend the worker pool when more inventories are needed
Append the new
MachineInventorynames — they must already be registered and Ready. Inventories with managed volumes must also be Prepared; otherwise they increasestatus.totalbut remain unavailable for allocation. Save and exit, then confirm the expected increase instatus.available. -
Scale up the
MachineDeployment -
Monitor
New
BaremetalMachineobjects advancePending → Allocated → Reprovisioning → Running; the pool'savailablecounter decreases as new nodes are bound.
Removing Worker Nodes
Two strategies are supported, identical in shape to the upstream Cluster API contract:
Inventory recycling
A clean plan stops kubelet, deactivates declared storage mounts, clears CRI workload, and stops containerd. It does not wipe managed filesystems, Kubernetes persistent directories, or reset the OS — OS cleanup happens later, when the same or a different inventory is picked for a new BaremetalMachine and runs the reprovision plan. Until then, the inventory returns to Available and may be allocated again. Deleting a Machine performs Deactivate, not storage Release, so the storage declaration, filesystem UUIDs, and data remain on that inventory.
Random Removal
CAPI selects machines for deletion in its standard order. Each selected BaremetalMachine moves to Preparing, the provider writes a clean plan, and once the plan reports Applied, the inventory returns to Available.
Targeted Removal
-
Identify the machines
-
Annotate the target machines
Repeat for every machine you want to remove.
-
Scale down by exactly the number of annotated machines
Reducing by fewer leaves annotated machines in place; reducing by more sends random machines through the
cleanplan as well. -
Verify cleanup
The released inventory must show
baremetal.alauda.io/allocation-state=Available, thebaremetal.alauda.io/owner-*annotations must be cleared, and the pool annotation must remain.MachineInventoryitself is not deleted. If it declares managed volumes, it must return tostatus.storage.phase=PreparedwithStorageActive=False/Inactive; its business mount paths must be inactive while filesystem UUIDs and data remain unchanged.
Replacing a Single Failed Node
If a BaremetalMachine lands in Failed, the safest recovery is to delete the failed Machine. CAPI immediately creates a replacement Machine (because replicas did not change), and the bare-metal provider picks an Available inventory from the same pool. Most often the replacement is a different MachineInventory; the provider does not guarantee that the freshly released inventory will be re-picked. Host-local managed data does not follow the replacement Machine. If the application must reuse a specific inventory's data, use a dedicated or deliberately ordered pool and verify BaremetalMachine.status.machineInventoryRef before relying on that data.
Investigate the original failure separately: read BaremetalMachine.status.conditions, MachineInventory.status.plan.state, and the failing plan secret's failed-output key on the host that ran the plan. Common root causes are documented in the Common Failure Modes section below.
Moving Workers to a Different Pool
BaremetalMachineTemplate carries only the pool reference — there is no CPU, memory, or disk declaration on the template.
Use Case: New hosts have been registered and placed in a new MachineInventoryPool, and the nodes should move onto them. Create a new BaremetalMachineTemplate that points to the new pool, then point the MachineDeployment at it. Nodes are replaced one by one.
Before you start:
-
The target pool is in the same namespace as the template.
-
The target pool has at least as many
Availableinventories as theMachineDeploymenthas replicas. Each moved node uses one host of the target pool; hosts released by the old nodes return to the old pool and do not join the target pool. Read the count fromstatus.available: -
The new hosts meet the same prerequisites as the current ones: registered and ready, managed data disks prepared if you use them, the target Kubernetes version and CPU architecture in the image catalog, and the CNI network device present. See Confirm the Worker Pool Capacity.
-
Keep the old template and the old pool until the move is finished.
Procedure:
-
Create a new
BaremetalMachineTemplatewith a newmetadata.namereferencing the target pool. Use the format in Configure the WorkerBaremetalMachineTemplate. -
Apply the new template.
-
Patch the
MachineDeployment: -
Watch the rolling replacement (
maxSurge: 0, one node at a time) and the target pool'sstatus.available:
What to expect:
- The old node is deleted before its replacement is created. If the target pool runs out of hosts, the node pool stays one node short until you add hosts.
- Node names and IP addresses change.
- Node-local data is not carried over. Data on managed data disks stays on the old host, bound to its
MachineInventory, and does not appear on the new host. Declare storage on the new hosts separately; see Manage Data Disks on Bare-Metal Hosts.
If the move stalls with no free host (BaremetalMachine shows InventoryAllocated=False / Reason=PoolExhausted), add Available hosts to the target pool; they are picked up automatically. Alternatively, roll back by patching infrastructureRef.name back to the old template. Nodes that were already moved are replaced again one by one, so the old pool must still have enough Available hosts.
To move control plane nodes, use the same steps and patch KubeadmControlPlane.spec.machineTemplate.infrastructureRef.name instead. Nodes are replaced one at a time. In addition:
maxSurge: 0requiresreplicasof 3 or more.- During each replacement only two etcd members run. Start only when the control plane is healthy, and keep 3
Availablehosts ready in the target pool. - The new hosts must be in the same layer-2 network as the control plane VIP.
After the move is complete, you can delete the old template and the old pool. Hosts released by the old nodes stay in the old pool.
Updating Bootstrap Templates
Modifying an existing KubeadmConfigTemplate in place does not roll out existing machines; only newly created machines pick up the change.
To roll out a bootstrap change:
-
Export the existing template:
-
Change
metadata.name, remove server-generated fields (resourceVersion,uid,creationTimestamp,managedFields,kubectl.kubernetes.io/last-applied-configuration) and the entirestatus, and edit the desired fields. For Kubernetes 1.35 or later, add the required kubelet patch settings to/etc/kubernetes/patches/kubeletconfiguration0+strategic.json. -
Apply the new template:
-
Patch the
MachineDeploymentto reference the new template:This triggers a rolling replacement.
Pool and Inventory Observability
The annotations the provider maintains on each MachineInventory are the authoritative source for "what is this host being used for right now":
Each inventory's default plan secret also carries baremetal.alauda.io/plan.type. Normal node lifecycle uses clean or reprovision; inventory storage reconciliation additionally uses storage-prepare and storage-release. Inspect MachineInventory.status.storage.conditions and .operation together with the plan type when diagnosing storage.
Common Failure Modes
For the full operator-side state machine reference, see Provider Overview → BaremetalMachine.