> For the complete documentation index, see [llms.txt](https://docs.platform9.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.platform9.com/private-cloud-director/kubernetes-clusters/setup-bare-metal-kubernetes-clusters.md).

# Set up your Bare Metal Kubernetes Cluster

You can deploy Kubernetes clusters on physical machines using the bare metal support for <code class="expression">space.vars.product\_name</code>. Each cluster contains all the resources for your containerized workloads, such as nodes, pods, and services.

Learn more on how you can onboard physical machines to <code class="expression">space.vars.product\_name</code> , create a Kubernetes cluster through the <code class="expression">space.vars.product\_name</code> console, and verify if your cluster is working.

{% hint style="warning" %}
**Information**

Bare metal support for Kubernetes in <code class="expression">space.vars.product\_name</code> is currently in `beta`
{% endhint %}

### Prerequisites

Before you start, ensure you have:

* One or more Ubuntu physical machines for your Kubernetes nodes. <code class="expression">space.vars.product\_acronym</code> supports Ubuntu 22.04 LTS and Ubuntu 24.04 LTS.
* Network connectivity between all machines and the <code class="expression">space.vars.product\_name</code> management cluster.
* Administrator requires sudo or root access on all target machines.
* Valid <code class="expression">space.vars.product\_name</code> account credentials.
* Access to your <code class="expression">space.vars.product\_name</code> management console.

#### Step 1: Onboard your machines

Onboarding installs the host agent on each physical machine and registers it with <code class="expression">space.vars.product\_name</code>. The console generates the commands for you, filled in with your own account values, so you never assemble them by hand.

**Get your onboarding commands**

1. In the <code class="expression">space.vars.product\_name</code> console, navigate to **Kubernetes** > **Infrastructure** > **Physical Hosts**.
2. Select **+ Add Physical Host**. The **Add New Physical Host** drawer opens.

The drawer's **Adding a New Physical Host** section holds two commands, each with its own copy button:

* The first installs the host agent.
* The second is a complete `byohctl onboard` command, with your **Account URL**, **Username**, **Domain**, **Tenant**, **Region**, and **client-token** already substituted. Only the password is left as a placeholder.

The **Here is your info for quick use** panel below the commands lists those same values individually, each with a copy button, if you need any of them on their own.

{% hint style="warning" %}
**The host agent package is personalized for your account.** The generated commands embed credentials tied to your organization. Do not share them, or the package they install, with anyone outside your organization.
{% endhint %}

**Install the host agent on each machine**

Repeat this for every physical machine you want to add as a Kubernetes node.

1. Log in to the host terminal.
2. As the root user, run the first command from the drawer. It downloads and runs the setup script that installs the host agent on the machine.
3. As the root user, run the second command from the drawer, replacing `<password>` with your own password.

Once the host agent is installed and registered, the machine appears on the **Physical Hosts** page.

**Verify successful onboarding**

Confirm that your machine has been properly registered with <code class="expression">space.vars.product\_name</code> and the agent is communicating correctly.

Verify that the agent service is active and communicating by running the following command.

{% tabs %}
{% tab title="Bash" %}

```bash
systemctl status pf9-byohost-agent.service
```

{% endtab %}
{% endtabs %}

You should see the agent service is active and running.

Review the agent logs to confirm registration with <code class="expression">space.vars.product\_name</code> by running the following command.

{% tabs %}
{% tab title="Bash" %}

```bash
cat /var/log/pf9/byoh/byoh-agent.log
```

{% endtab %}
{% endtabs %}

Confirm you see registration success messages in the logs.

Finally, confirm that <code class="expression">space.vars.product\_name</code> has picked the machine up.

1. In the <code class="expression">space.vars.product\_name</code> console, navigate to **Kubernetes** > **Infrastructure** > **Physical Hosts**.
2. Find your machine in the table by its **Name**. Use the **Search** box if you have many hosts.
3. Check the row:
   * **Connection Status** reads **Online**, which means the host agent is registered and communicating.
   * **Cluster** reads **Not Assigned**, because the machine is onboarded but not yet part of a cluster. It changes to the cluster name in Step 2.
   * **IP Addresses**, **OS Image**, and **OS Name** show what <code class="expression">space.vars.product\_acronym</code> detected on the machine, for example an **OS Image** of `Ubuntu 22.04.5 LTS`.

Once the host shows as **Online**, onboarding is complete and the machine is ready to join a cluster.

#### Step 2: Create your Kubernetes cluster

1. Log in to your <code class="expression">space.vars.product\_name</code> console.
2. Navigate to **Kubernetes** > **Infrastructure** > **Clusters** in the left-hand navigation menu.
3. Open the deployment wizard:
   * If you have not created a cluster yet, select **Create New Cluster with Physical Nodes**.
   * If you already have clusters, select **Deploy New Cluster**, then choose **with Physical Nodes**.

The **Deploy A New Cluster** wizard opens on the **Cluster Architecture** step. On the physical-node path, that step holds the cluster name and the control plane type. You select the machines themselves on the later steps.

4. In **Cluster Name**, enter a name that is unique among your clusters. This name identifies your cluster in the <code class="expression">space.vars.product\_name</code> console.
5. Under **Select the type of control plane**, choose one of the two cards, then select **Next**.

| **Control plane type**  | **Where it runs**                                                                                  | **What the wizard asks for**                                                                            |
| ----------------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| Managed Control Plane   | The <code class="expression">space.vars.product\_acronym</code> management plane, operated for you | Nothing further. The wizard goes straight to **Add Worker Nodes**.                                      |
| Colocated Control Plane | Dedicated nodes among the physical machines you onboarded                                          | An extra **Add Control Plane Nodes** step, plus a **Virtual IP** and a **Network Interface** in step 8. |

To compare the two types before you choose, see [Control Plane Types](/private-cloud-director/kubernetes-clusters/control-plane-types.md).

6. Colocated control plane only: on the **Add Control Plane Nodes** step, select the onboarded machines that host the control plane. Choose an odd number of at least three nodes so that the control plane retains a quorum if a node is lost. Select **Next**.
7. On the **Add Worker Nodes** step, select the onboarded machines that run your workloads. At least one worker node is required. Select **Next**.
8. On the **Configure your Cluster** step, configure your Kubernetes cluster settings.

| **Settings**       | **Action**                    | **Description**                                                                                                                                                                                                                                                                                             |
| ------------------ | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kubernetes Version | Select from dropdown          | Choose the Kubernetes version supported by your workloads.                                                                                                                                                                                                                                                  |
| Kubernetes Flags   | Enable this flag              | Customize kube-apiserver, Controller Manager, and Scheduler flags using the cluster API.                                                                                                                                                                                                                    |
| Core Add-ons       | Enable as required            | CoreDNS and Calico can be enabled individually. Customize add-ons using cluster API add-on configuration.                                                                                                                                                                                                   |
| Other Add-ons      | Enable as required            | Optional add-ons like MetalLB and Nvidia GPU Operator are available.                                                                                                                                                                                                                                        |
| Virtual IP         | Enter an available IP address | Colocated control plane only. Use an address from the network on which your control plane hosts reside. `kube-vip` advertises it to provide a stable Kubernetes API server endpoint. Reserve the address for this cluster, and make sure it is not already assigned to another host or part of a DHCP pool. |
| Network Interface  | Enter the interface name      | Colocated control plane only. The network interface on the control plane hosts that `kube-vip` uses to advertise the virtual IP via ARP, for example `ens3`. The interface name must be the same on all control plane hosts.                                                                                |

9. Select **Submit** to start the deployment process.

The <code class="expression">space.vars.product\_name</code> console now provisions your cluster using the physical machines you onboarded.

#### Step 3: Verify your cluster

**Monitor cluster creation**

Monitor your cluster creation progress in the <code class="expression">space.vars.product\_name</code> console.

1. Navigate to **Kubernetes** > **Infrastructure** > **Clusters**.
2. Find your cluster in the list and watch its status until it becomes Active.

**Confirm your machines joined the cluster**

Each physical machine you selected in the wizard is claimed by the cluster as it is provisioned.

1. Navigate to **Kubernetes** > **Infrastructure** > **Physical Hosts**.
2. For each machine you selected, check the **Cluster** column. It shows **Not Assigned** until the machine is claimed, then changes to a link carrying your cluster's name.
3. Confirm that **Connection Status** stays **Online** for each of those hosts.

To narrow the table to one cluster's hosts, use the **All Clusters** filter above it and select your cluster.

When every machine you selected shows your cluster's name and an **Online** connection status, your cluster nodes have joined successfully.

**Access your cluster**

Download the `kubeconfig` file from the <code class="expression">space.vars.product\_name</code> console.

1. Navigate to **Kubernetes > Infrastructure > Clusters** and then to your cluster.
2. Choose **Download Kubeconfig.**
3. Save the downloded file as `cluster-kubeconfig.yaml`.

* Set your `kubectl` context by running the following command.

{% tabs %}
{% tab title="Bash" %}

```bash
export KUBECONFIG=<CLUSTER_KUBECONFIG.YAML>
```

{% endtab %}
{% endtabs %}

* Verify your cluster is working by running the following command.

{% tabs %}
{% tab title="Bash" %}

```bash
kubectl get nodes -A 
kubectl get ns 
kubectl get pods -A
```

{% endtab %}
{% endtabs %}

These commands show your cluster nodes, namespaces, and running pods.

You have successfully created and verified your bare metal Kubernetes cluster. Your physical machines are now ready to run containerized workloads.

{% hint style="info" %}
**Info**

Cluster Autoscaling is not currently supported in BYOH Kubernetes clusters
{% endhint %}

## Best Practices

* Make sure your physical machines meet the minimum system requirements for Kubernetes nodes.
* The `byohctl` agent logs at `/var/log/pf9/byoh/byoh-agent.log` are useful for troubleshooting onboarding issues.
* Core add-ons are required for basic cluster functionality.
* Your Kubernetes version must be supported by your <code class="expression">space.vars.product\_name</code> management plane.

## Related Pages

* [Control Plane Types](/private-cloud-director/kubernetes-clusters/control-plane-types.md): how Managed and Colocated control planes differ, and how to choose between them
* [Getting Started](/private-cloud-director/kubernetes-clusters/getting-started-with-kubernetes-in-pcd.md): the same deployment flow on virtualized nodes
* [Cluster Access - Kubeconfig](/private-cloud-director/kubernetes-clusters/cluster-lifecycle/cluster-access-kubeconfig.md): other ways to reach your cluster with `kubectl`


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.platform9.com/private-cloud-director/kubernetes-clusters/setup-bare-metal-kubernetes-clusters.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
