How to Build an Awesome Kubernetes Cluster using Proxmox Virtual Environment

Proxmox Virtual Environment is an awesome virtualization solution. Kubernetes is an awesome containerization solution. So why not combine those great technologies? In this video, you’ll see the entire process of setting up your very own Kubernetes cluster from scratch, with Proxmox shown as the platform. But even if you don’t plan on using Proxmox, this method will work just fine on other solutions as well, including physical servers. By the end of this video, you’ll have your own cluster ready to go!

YouTube player

Also, be sure to check out the brand-new book, Mastering Ubuntu Server 4th Edition! It’s available now, and covers Ubuntu Server 22.04 LTS.


To follow along with this tutorial, you’ll need:

  • At least two Ubuntu Server 22.04 instances (one for the controller, one for at least one node)
  • A static IP address or DHCP reservation on those instances, so their IP addresses cannot change
  • The controller node should have at least 2GB of RAM and 2 cores
  • The node instances can have a single gigabyte of RAM and a single CPU core (or more if you prefer)

Note: This tutorial utilizes Ubuntu Server 22.04. If you choose to use a different distribution or a different version of Ubuntu, these commands may not work.

Setting up the cluster

The following commands are to be run on the controller node (unless otherwise stated).

Setting up a static IP

Note, a static lease is preferred, but you can use the following Netplan config example to serve as a basis of yours if you need to set up a static IP.

    version: 2
            addresses: []
                addresses: []
                - to: default

Installing containerd

This Kubernetes cluster will utilize the containerd runtime. To set that up, we’ll first need to install the required package:

sudo apt install containerd

Create the initial configuration:

sudo mkdir /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml

For this cluster to work properly, we’ll need to enable SystemdCgroup within the configuration. To do that, we’ll need to edit the config we’ve just created:

sudo nano /etc/containerd/config.toml

Within that file, find the following line of text:


Underneath that, find the SystemdCgroup option and change it to true, which should look like this:

SystemdCgroup = true

Disable swap

Kubernetes requires swap to be disabled. To turn off swap, we can run the following command:

sudo swapoff -a

Next, edit the /etc/fstab file and comment out the line that corresponds to swap (if present). This will help ensure swap doesn’t end up getting turned back on after reboot.

Enable bridging

To enable bridging, we only need to edit one config file:

sudo nano /etc/sysctl.conf

Within that file, look for the following line:


Uncomment that line by removing the # symbol in front of it, which should make it look like this:


Enable br_netfilter

The next step is to enable br_netfilter by editing yet another config file:

sudo nano /etc/modules-load.d/k8s.conf

Add the following to that file (the file should actually be empty at first):


Reboot your servers

Reboot each of your instances to ensure all of our changes so far are in place:

sudo reboot

Installing Kubernetes

The next step is to install the packages that are required for Kubernetes. First, we’ll add the required GPG key:

sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://

After that, install the packages that are required for Kubernetes:

sudo apt install kubeadm kubectl kubelet

Controller node only: Initialize our Kubernetes cluster

So long as you have everything complete so far, you can initialize the Kubernetes cluster now. Be sure to customize the first IP address shown here (not the second) and also change the name to match the name of your controller.

sudo kubeadm init --control-plane-endpoint= --node-name
controller --pod-network-cidr=

After the initialization finishes, you should see at least four commands printed within the output.

Setting up our user account to manage the cluster

Three commands will be shown in the output from the previous command, and these commands will give our user account access to manage our cluster. Here are those related commands to save you from having to search the output for them:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
suod chown $(id -u):$(id -g) $HOME/.kube/config

Those commands should allow you to manage the cluster, without needing to use the root account to do so.

Install an Overlay Network

The following command will install the Flannel overlay network (an overlay network is required for this to function).

kubectl apply -f

Adding Nodes

The join command, which you will receive from the output once you initialize the cluster, can be ran on your node instances now to get them joined to the cluster. The following command will help you monitor which nodes have been added to the controller (it can take several minutes for them to appear):

kubectl get nodes

If for some reason the join command has expired, the following command will provide you with a new one:

kubeadm token create --print-join-command

Deploying a container within our cluster

Create the file pod.yml with the following contents:

apiVersion: v1
kind: Pod
Chapter 18 25
name: nginx-example
    app: nginx
    - name: nginx
      image: linuxserver/nginx
        - containerPort: 80
          name: "nginx-http"

Apply the file with the following command:

kubectl apply -f pod.yml

You can check the status of this deployment with the following command:

kubectl get pods

Creating a NodePort Service

Setting up a NodePort service is one of the methods we can use to be able to access the container from outside the pod network. To set this up, first create the following file as service-nodeport.yml:

apiVersion: v1
kind: Service
  name: nginx-example
  type: NodePort
    - name: http
      port: 80
      nodePort: 30080
      targetPort: nginx-http
app: nginx

You can apply that file with the following command:

kubectl apply -f service-nodeport.yml

To check the status of the service deployment, you can use the following command:

kubectl get service

And now, you have your very own Kubernetes cluster, congratulations!

Brand-New Course!

Discount Vouchers

Receive 5% off an LPI exam voucher!

Exclusive Member Features

Support the channel and receive exclusive perks!