Tenant cluster nodes
A tenant cluster can take dedicated bare metal capacity. You declare how many nodes you want and which hardware they come from, and the platform provisions servers and joins them to the cluster as worker nodes. No manual kubeadm join, no agent to install.
These are private nodes. The platform allocates each server to one cluster at a time, so no other tenant shares the hardware. For how the join works underneath, see Cluster attachment.
Before you begin
Work through Set up your hardware steps 1 through 5 first, so you have a NodeProvider and at least one BareMetalHost in available state. Step 6 there is a branch point that routes to one of three guides. This is the one for servers that join a cluster as workers. It picks up where step 5 ends.
Tenant cluster configuration and NodeClaim commands use the management cluster context. Commands that inspect, cordon, or drain Kubernetes nodes use the tenant cluster context. Keep a separate management-cluster shell open after connecting to the tenant cluster.
You also need a tenant cluster to attach the nodes to. If its control plane should also run on vMetal hardware rather than on an existing Kubernetes cluster, set that up first. See Control plane machines, since that choice cannot be changed later.
1. Define a node type for worker capacity
Node types are defined on the NodeProvider. Add one describing the hardware you want tenant clusters to draw from.
nodeTypes:
- name: "compute-node"
displayName: "Compute Node"
resources:
cpu: "32"
memory: 128Gi
bareMetalHosts:
selector:
matchLabels:
role: compute
properties:
vcluster.com/os-image: ubuntu-noble
vcluster.com/ssh-keys: ops-key
Include vcluster.com/ssh-keys even though these nodes are reachable through Kubernetes. Keys are injected at provision time and cannot be added afterwards, and SSH is how you inspect a node whose kubelet never came up. See Configuration for the full set of node type fields.
2. Request nodes from the tenant cluster
Set privateNodes in the tenant cluster's configuration. This is the canonical form. Other pages that show this block are showing a variation on it.
privateNodes:
enabled: true
autoNodes:
- provider: metal3-provider
static:
- name: compute-nodes
quantity: 3
nodeTypeSelector:
- property: vcluster.com/node-type
value: compute-node
provideris the NodeProvider to claim servers from.staticis a list of named pools. Each pool holds a fixed node count, which is what makes it static.quantityis how many nodes that pool should have. The platform creates and deletes Machines to match it.nodeTypeSelectormatches the node type by property.vcluster.com/node-typeis the property carrying the node type's own name.
The platform creates one Machine per requested node, each claiming an eligible server. Machines wait for the tenant cluster to be online before they provision, because a node needs a live API server to join.
3. Verify the nodes joined
# Run from a management-cluster shell; this opens a tenant-cluster context.
vcluster connect my-cluster
kubectl get nodes
Each provisioned server appears as a standard Kubernetes node. Watch the Machines from the platform side at the same time:
kubectl --context <management-context> get nodeclaims \
-n loft-p-my-project
A Machine reaching Available with its Joined condition true means the server registered with the cluster. If a Machine provisions but never joins, the server booted but the bootstrap script did not complete. Follow Worker Machine is provisioned but not joined.
4. Change how many nodes you have
Edit quantity and apply. The platform adds Machines to reach a higher count and deletes them to reach a lower one.
Reducing quantity deletes Machines and deprovisions their servers. The platform does not cordon or drain the node first, so anything still running on a selected server stops when it is taken offline for deprovisioning.
Cordon and drain the node through the tenant cluster before you scale down, and confirm the workloads rescheduled.
# Tenant cluster context
kubectl cordon <node-name>
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data
To keep node counts tracking demand instead of managing quantity by hand, use Auto Nodes, which adds and removes nodes against configurable resource requirements.
5. Release the nodes
Set quantity to zero, remove the pool, or delete the tenant cluster. Each removes the Machines it owns.
The driver then cleans each server and returns it to the available pool. A later Machine can claim it, including one belonging to a different project or cluster. Deleting a Machine never deletes the BareMetalHost. For what the server itself does during cleanup, see BareMetalHost states.
The same drain warning applies. Releasing nodes is a scale-down to zero.
Related tasks
| If you want to... | Go to |
|---|---|
| Understand how the join works and what the platform generates | Cluster attachment |
| Apply reusable taints and labels to joined nodes | Node profiles |
| Attach GPU servers instead of general compute | GPU Quickstart |
| Pin a node to one specific physical server | Server pinning |
| Restrict which node types a project may claim | Production and Security |
| Inspect a node's underlying server | Checking fleet capacity |