Deploy Kubernetes on Proxmox: a step-by-step tutorial
In this tutorial, we’ll set up a Kubernetes cluster on Proxmox using the Cloudfleet Kubernetes Engine (CFKE) free plan. Step by step, we’ll guide you from a virtual machine in your on-premises environment to a highly available Kubernetes cluster, ready for deploying your first applications.
Cloudfleet is a next-generation Kubernetes solution that provides managed Kubernetes services. It enables you to integrate virtual machines from multiple public cloud providers and on-premises environments into a unified Kubernetes cluster. This allows you to manage deployments seamlessly across diverse infrastructure locations from a single Kubernetes API. Cloudfleet also offers a generous free tier, making it easy to get started at no cost.
This tutorial assumes you already have a running Proxmox server with SSH access to its console. If you haven’t installed Proxmox yet, refer to the Proxmox documentation for installation instructions.
Proxmox Virtual Environment (Proxmox VE) is an open-source server virtualization platform that provides a robust and flexible solution for running virtual machines and containers. Built on Linux’s KVM hypervisor, Proxmox offers a powerful management interface and API for creating and managing virtualization infrastructure—completely free. Its growing adoption in recent years has solidified its place in enterprise environments.
Step 1: Install an Ubuntu VM using the cloud image
In this section, we’ll install an Ubuntu VM using the cloud image. Cloud images are official, pre-installed Ubuntu images customized by Canonical for use in public clouds that provide Ubuntu Certified Images, OpenStack, LXD, and more. These images include cloud-init, a tool that automates OS configuration upon startup. With cloud-init, you can create users, inject SSH keys, install packages, and perform various customizations, enabling the rapid deployment of hundreds of VMs.
If you’re familiar with public cloud providers, you’ve likely encountered cloud-init as a standard tool for automated VM provisioning. However, this technology is not limited to public clouds. With Proxmox’s cloud-init support, you can provision VMs in the same efficient way within your own infrastructure.
Now, let’s use the Ubuntu cloud image and cloud-init to deploy a VM. While many of these steps can be performed through the Proxmox UI, we’ll use the command line for greater control and automation.
First, log in to the Proxmox SSH console. You can use your preferred SSH client or open the Shell section by selecting the node in the Proxmox UI.
Next, download the latest cloud image from the internet. In this example, we’ll use Ubuntu Noble (24.04).
wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
As the next step, let’s create a VM with 4 cores and 8 GB of RAM.
qm create 9000 --cores 4 --memory 8096 \
--net0 virtio,bridge=vmbr0 \
--scsihw virtio-scsi-pci \
--name kubernetes-node
Ensure that the VM ID is unique. If a VM with ID 9000 already exists, choose a different ID. You can also adjust the CPU and memory allocation based on your requirements.
Now, import the cloud-init image into the newly created VM:
qm set 9000 --scsi0 local-lvm:0,import-from=/path/to/image/noble-server-cloudimg-amd64.img
Replace /path/to/image
with the actual path where you downloaded the image.
Next, configure a CD-ROM drive to pass cloud-init data to the VM:
qm set 9000 --ide2 local-lvm:cloudinit
Set the boot parameter to order=scsi0 to ensure the VM boots directly from the cloud-init image. This prevents the BIOS from checking for a bootable CD-ROM, speeding up the boot process:
qm set 9000 --boot order=scsi0
Configure a serial console and use it as the display:
qm set 9000 --serial0 socket --vga serial0
Now it’s time to configure cloud-init. We’ll add our SSH public key to enable secure login to the VM. First, save the public key to a file on Proxmox and reference it in the qm set
command:
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJo6pQZjKDewUw9ihxX/z/MLE4aJ9CW8OIrJCIK3k2cx" > ssh.pub
qm set 9000 --sshkeys ssh.pub
Cloud-init also allows setting a static IP address for the VM. By default, the VM will obtain an IP from your DHCP server. To configure cloud-init for DHCP, use:
qm set 9000 --ipconfig0 ip=dhcp
If you prefer to assign a static IP, use the following command, replacing the values with your desired IP configuration:
qm set 123 --ipconfig0 ip=10.0.10.123/24,gw=10.0.10.1
Before starting the VM, we need to resize the main disk. The Ubuntu cloud image is small, and installing packages may quickly consume available space. To prevent this, add 5 GB of extra storage:
qm resize 9000 scsi0 +5G
Size of logical volume pve/vm-9000-disk-0 changed from 3.50 GiB (896 extents) to 8.50 GiB (2176 extents).
Logical volume pve/vm-9000-disk-0 successfully resized.
Everything is set up. Now, start the VM from the Proxmox UI.
Once the VM starts, find its IP address on your network (or use the static IP you assigned) and connect via SSH using your private key:
ssh [email protected] -i ~/.ssh/privkey.pem
The default username for the cloud image is “ubuntu”. While cloud-init allows you to change this, we skipped that step in this guide.
You can also create a template from the VM to replicate it multiple times and set up additional Kubernetes nodes. For more details on VM templating in Proxmox, refer to the official documentation.
Step 2: Create a Cloudfleet account and cluster
After setting up the VM, the next step is to create a Kubernetes cluster in Cloudfleet. Each Cloudfleet account includes one free Kubernetes cluster, supporting up to 48 vCPUs.
Follow these steps to create a Cloudfleet cluster:
- Go to https://console.cloudfleet.ai/account/signup.
- Complete the account registration and sign in to the Cloudfleet console.
- In the console, click Create Cluster and follow the setup wizard. You can select a control plane region close to you, but remember that you can add nodes from any location, regardless of the control plane’s region.
- Once the cluster is created, click Connect to Cluster and follow the instructions to install the Cloudfleet CLI and configure authentication. At the end of the setup, you’ll see instructions on how to access the cluster with
kubectl
.
After completing these steps, verify that the cluster is running:
$ kubectl cluster-info
Kubernetes control plane is running at https://c515a6f3-b61a-451f-87c1-cc4600b172e3.northamerica-central-1.cfke.cloudfleet.dev:6443
CoreDNS is running at https://c515a6f3-b61a-451f-87c1-cc4600b172e3.northamerica-central-1.cfke.cloudfleet.dev:6443/api/v1/namespaces/kube-system/services/coredns:udp-53/proxy
Your cluster ID will be different from the example above. Next, confirm that no nodes are currently registered:
$ kubectl get nodes
No resources found.
At this stage, the cluster has no nodes because we haven’t added any yet. Let’s add one now.
Step 3: Add the Proxmox VM to the Cloudfleet Kubernetes cluster
For on-premises platforms like Proxmox, Cloudfleet’s self-managed nodes feature enables seamless integration of regular Linux VMs into Kubernetes clusters.
Self-managed nodes have minimal requirements:
- The VM must run a supported operating system (Ubuntu 24.04 is supported).
- The VM must have internet connectivity but does not need to be publicly accessible. Self-managed nodes establish a secure peer-to-peer VPN tunnel to the control plane for private communication and can also work behind a NAT. For more details, refer to the CFKE node-to-node communication documentation.
Now, let’s add the Proxmox VM to the cluster using the Cloudfleet CLI, which we previously installed and configured:
cloudfleet clusters add-self-managed-node CLUSTER_ID --host 10.0.10.123 --ssh-username SSH_USERNAME --ssh-key SSH_KEY_LOCATION --region DATACENTER_REGION --zone DATACENTER_ZONE
region
and zone
are mandatory flags used to specify the node’s region and zone. You can assign any meaningful string to these values, which are then mapped to Kubernetes node labels (topology.kubernetes.io/region
and topology.kubernetes.io/zone
). These labels enable workload scheduling based on node topology.
The recommended best practice is to set the region to the datacenter location and the zone to the failure domain (e.g., rack). Other parameters are straightforward. Below is an example command using our values:
cloudfleet clusters add-self-managed-node c515a6f3-b61a-451f-87c1-cc4600b172e3 --host HOST_IP --ssh-username ubuntu --ssh-key ~/.ssh/privkey.pem --region barcelona --zone bar-1a
When you execute the command, the Cloudfleet CLI installs the required packages and files on the VM. Once complete, it starts the kubelet, which automatically registers the node with the Kubernetes cluster.
In a few seconds, you can list the nodes again to confirm that the new node has joined the cluster:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
kubernetes-node Ready <none> 46s v1.31.3
Next steps
In this tutorial, we have successfully created a Proxmox VM using an Ubuntu Cloud image. Now, we have a managed Kubernetes cluster on Proxmox VE, ready to deploy applications with the full range of Kubernetes ecosystem tools.
As a next step, you can create a custom template from your VM and automate the entire process of VM creation and cluster integration.
Cloudfleet also provides BGP-based load balancing for advanced on-premises setups. See the documentation to learn more about exposing web applications to the public internet from your Proxmox cluster.
For more information about Cloudfleet Kubernetes Engine, visit the Hybrid and on-premises Kubernetes page page.