Set up your hardware
Before you begin
To use vMetal, ensure you have the following:
-
An existing vCluster Platform installation.
-
A license plan that includes vMetal. If you intend to hand out servers over SSH rather than join them to tenant clusters, your plan also needs the
machine-managementfeature. See Independently provisioned machines.noteTo check your plan, in the platform navigate to Admin > License and Billing. If your plan doesn't include vMetal, contact support@vcluster.com.
-
A control plane cluster connected to vCluster Platform where Metal3 and Ironic run.
-
Network access from the control plane cluster to the BMC endpoints (Redfish or IPMI) of your bare metal servers.
-
Physical servers with BMC (Baseboard Management Controller) support and a NIC configured for PXE boot.
-
A provisioning network that carries DHCP, TFTP, and HTTP traffic between the servers and the vMetal components.
-
An OS image URL reachable from the bare metal servers themselves.
Review the complete hardware, network, BMC, and platform requirements before continuing. In particular, decide whether the DHCP component needs a Multus interface on the provisioning network or can use hostNetwork on a flat network.
Quick start
This walkthrough covers the essential steps to go from a connected control plane cluster to a provisioned bare metal server.
Steps 1 through 5 set up your hardware and apply to every use of vMetal. Step 6 is where the paths diverge, depending on what you want the server to become.
This workflow uses two Kubernetes contexts:
| Context | Resources and commands |
|---|---|
| Management cluster | vCluster Platform resources such as OSImage, NodeProvider, SSHKey, and NodeClaim. |
| Control plane cluster | Metal3 resources such as BareMetalHost, BMC credential Secrets, and Metal3 component logs. This is the cluster named by NodeProvider.spec.metal3.clusterRef.cluster. |
Keep both contexts available. Each step below identifies which one to use. Replace <management-context> and <control-plane-context> in commands with names from kubectl config get-contexts.
1. Create an OSImage
Context: management cluster. Node types reference an OS image by name. Create the OSImage resource before the NodeProvider that references it.
apiVersion: management.loft.sh/v1
kind: OSImage
metadata:
name: ubuntu-noble
spec:
properties:
metal3.vcluster.com/image-url: https://your-registry.example.com/ubuntu-noble-amd64.img
metal3.vcluster.com/image-checksum: "<sha256-checksum>"
metal3.vcluster.com/image-checksum-type: sha256
kubectl --context <management-context> apply -f os-image.yaml
The bare metal server downloads this image itself during provisioning, so the URL must be reachable from the server's network. You can skip the OSImage resource and set the image URL and checksum directly on the node type instead. See Image configuration.
2. Create a NodeProvider
Context: management cluster. A NodeProvider tells the platform which control plane cluster to use, what infrastructure to deploy, and how to categorize your servers.
apiVersion: management.loft.sh/v1
kind: NodeProvider
metadata:
name: metal3-provider
spec:
displayName: "Metal3 Bare Metal Provider"
metal3:
clusterRef:
cluster: bare-metal-cluster
namespace: metal3-system
deploy:
metal3:
enabled: true
dhcp:
enabled: true
helmValues: |
hostNetwork: true
dhcp:
listenAddr: "$(SERVER_IP):67"
nodeTypes:
- name: "compute-node"
displayName: "Compute Node"
resources:
cpu: "32"
memory: 128Gi
bareMetalHosts:
selector:
matchLabels:
role: compute
properties:
vcluster.com/os-image: ubuntu-noble
kubectl --context <management-context> apply -f metal3-provider.yaml
This example uses hostNetwork and assumes the control plane cluster nodes are directly attached to the provisioning network. If the provisioning network needs a separate pod interface, use the Multus bridge or macvlan configuration instead before applying the resource.
Wait for Metal3 and Ironic to be running on the control plane cluster before creating BareMetalHost resources. The Metal3 webhook must be ready to validate them.
The platform injects SSH keys into the operating system at provision time. A server that is already provisioned does not pick up a key you add later. Fixing it means releasing the Machine and claiming the server again.
If you will need to log in to these servers, add vcluster.com/ssh-keys to the node type before you provision anything. This is required for independently provisioned machines, which have no other way in, and useful for tenant cluster nodes you may need to debug. See Register an SSH key.
3. Create BMC credentials
Context: control plane cluster. Create a Secret with the BMC username and password for your server. The BareMetalHost resource references this Secret.
apiVersion: v1
kind: Secret
metadata:
name: server-01-bmc
namespace: metal3-system
type: Opaque
stringData:
username: admin
password: <BMC-PASSWORD>
kubectl --context <control-plane-context> apply -f server-01-bmc-secret.yaml
4. Register a bare metal server
Context: control plane cluster. Create a BareMetalHost resource. The bmc.address scheme determines which driver Metal3 uses, such as Redfish or IPMI. The bootMACAddress identifies the NIC used for PXE boot.
apiVersion: metal3.io/v1alpha1
kind: BareMetalHost
metadata:
name: server-01
namespace: metal3-system
labels:
role: compute
spec:
bmc:
address: redfish://192.168.1.100/redfish/v1/Systems/1
credentialsName: server-01-bmc
disableCertificateVerification: true
bootMACAddress: "aa:bb:cc:dd:ee:01"
kubectl --context <control-plane-context> apply -f server-01-bmh.yaml
The server moves through registering and inspecting states as Metal3 verifies BMC access and collects hardware inventory.
5. Verify the server reaches available state
Context: control plane cluster. Once the BareMetalHost passes inspection, it transitions to available. The server is registered, its hardware inventory is collected, and it's ready for provisioning.
kubectl --context <control-plane-context> get baremetalhost -n metal3-system
NAME STATE CONSUMER ONLINE ERROR
server-01 available false
6. Claim the server
Your hardware is now set up. What you do next depends on what the server is for. Each option below is its own guide, and each picks up exactly here.
Hand out the server with SSH access only. Request a Machine on its own. Nothing installs Kubernetes, and no tenant cluster is involved. Follow Independently provisioned machines.
Give a tenant cluster dedicated capacity. Request nodes from the tenant cluster and the platform provisions servers and joins them as workers. Follow Tenant cluster nodes.
Run a tenant cluster's control plane on the server. The platform installs vCluster on it rather than joining it to anything. Follow Control plane machines. That choice is made when you create the cluster and cannot be changed afterwards.
Underneath, the three differ only in what the platform sets on the Machine and in the cloud-init it generates:
| Independently provisioned | Worker | Control plane | |
|---|---|---|---|
spec.vClusterRef | Empty | Names the cluster | Names the cluster |
spec.controlPlane | false | false | true |
| Cloud-init appends | Nothing beyond SSH keys | A kubeadm join command | The vCluster install script |
| Result | A server you reach over SSH | A worker node in the cluster | The cluster's control plane |
Everything in steps 1 through 5 is identical across all three.
Try it locally
The vCluster Bare Metal with KubeVirt guide lets you run the full Metal3 bare metal provisioning flow locally using KubeVirt VMs as simulated bare metal servers. It sets up a cluster with KubeVirt, a Metal3 NodeProvider, and simulated BareMetalHosts with Redfish BMC endpoints. No physical hardware required.