Install Kubernetes on Ubuntu Server 22.04 LTS

This article is for those looking for a detailed and straightforward guide on installing Kubernetes on Ubuntu Server 22.04 LTS.
Kubernetes is an open-source container orchestration system for automating software deployment, scaling, and management.
IMPORTANTOpenSSH must be installed on the server, and port 22 must be open in order to be able to connect to the server using the SSH protocol.
To install OpenSSH on a server, you can use the command:
sudo apt install openssh-server
NOTETo connect to the server from a Windows system, you can use tools like PuTTY or MobaXterm.
NOTEThis guide walks you through connecting to a server with the iTerm2 terminal emulator on macOS.
CAUTIONYou will need to open the following TCP ports for access to the services:
Kubernetes Master (Control Plane):
- TCP port 6443 - for the Kubernetes API to work.
- TCP port 2379-2380 - for the etcd server client API to work.
- TCP port 10250 - for the Kubelet API to work.
- TCP port 10259 - for kube-scheduler to work.
- TCP port 10257 - for kube-controller-manager to work.
Kubernetes Worker:
- TCP port 0250 - for the Kubelet API to work.
- TCP port 30000-32767 - for NodePort Services to work.
IMPORTANTWe will consider installing one server with the Master role and one server with the Worker role. In the future, you can independently add the required number of servers to ensure high availability.
We connect to the server on which we plan to install the Kubernetes Master role.
Assign a name to the server using the command:
sudo hostnamectl set-hostname kubernetes-master-1.heyvaldemar.net
NOTEIn this tutorial,
kubernetes-master-1.heyvaldemar.net
is used as the name of the server with the Master role.
The server with the Worker role must resolve the name of the server with the Master role, and also the server with the Master role must resolve the name of the server with the Worker role.
Next, add the IP address and name of the server with the Master role to the “/etc/hosts” file using the command:
echo "10.0.5.140 kubernetes-master-1.heyvaldemar.net kubernetes-master-1" | sudo tee -a /etc/hosts
Having this entry will allow the server with the agent installed to resolve the Kubernetes server name even without a DNS entry.
NOTEIn this guide, the server name with the Master role is
kubernetes-master-1.heyvaldemar.net
, and the IP address is 10.0.5.140.
Make sure that the name of the server with the Worker role has the correct DNS entry, and also update the “/etc/hosts” file on the server with the command:
echo "10.0.6.19 kubernetes-worker-1.heyvaldemar.net kubernetes-worker-1" | sudo tee -a /etc/hosts
Having this entry will allow the server with the agent installed to resolve the Kubernetes server name even without a DNS entry.
NOTEIn this guide, the Master server name is
kubernetes-worker-1.heyvaldemar.net
and the IP address is 10.0.6.19.
Restart the hostamed service for the server name changes to take effect using the command:
sudo systemctl restart systemd-hostnamed
Check the correctness of the server name using the command:
hostname
Now let’s replace the current shell process with the new one using the command:
exec bash
Next, you need to disable the paging file using the command:
sudo swapoff -a
The command above disables the swap file until the system is rebooted. We have to make sure that it stays off even after a reboot. To do this, edit the “fstab” file by commenting out the “/swapfile” line with the ”#” symbol.
We execute the command:
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
Load the kernel modules with the command:
sudo tee /etc/modules-load.d/containerd.conf <<EOFoverlaybr_netfilterEOF
Load the “overlay” module with the command:
sudo modprobe overlay
Load the “br_netfilter” module with the command:
sudo modprobe br_netfilter
Set the kernel options for Kubernetes with the command:
sudo tee /etc/sysctl.d/kubernetes.conf <<EOFnet.bridge.bridge-nf-call-ip6tables = 1net.bridge.bridge-nf-call-iptables = 1net.ipv4.ip_forward = 1EOF
Apply the changes made using the command:
sudo sysctl --system
Now let’s add the official Docker key with the command:
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/docker.gpg
Next, we connect the Docker repository using the command:
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
We press the “Enter” button.
Update the local package index to the latest changes in the repositories using the command:
sudo apt update
Now let’s install the packages required for Kubernetes to work using the command:
sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates containerd.io
Now you need to configure containerd.
containerd - an industry-standard container runtime with an emphasis on simplicity, robustness and portability
We execute the command:
containerd config default | sudo tee /etc/containerd/config.toml >/dev/null 2>&1
We execute the command:
sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml
Restart containerd to apply the changes, using the command:
sudo systemctl restart containerd
We enable autostart of the containerd service at the start of the operating system using the command:
sudo systemctl enable containerd
Now let’s add the official Kubernetes key using the command:
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
Next, we connect the Kubernetes repository using the command:
sudo apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main"
NOTEAt the time of writing this guide, Xenial is the current Kubernetes repository, but when the repository is available for Ubuntu 22.04 (Jammy Jellyfish), you will need to change the word in the command above from “xenial” to “jammy”.
We press the “Enter” button.
Update the local package index to the latest changes in the repositories using the command:
sudo apt update
Now install the kubelet, kubeadm and kubectl packages using the command:
sudo apt install -y kubelet kubeadm kubectl
The next step is to disable automatic updates and removal of installed packages using the command:
sudo apt-mark hold kubelet kubeadm kubectl
Now you need to start the initialization of the Kubernetes cluster using the command:
sudo kubeadm init --control-plane-endpoint=kubernetes-master-1.heyvaldemar.net
NOTEIn this tutorial,
kubernetes-master-1.heyvaldemar.net
is used as the name of the server with the Master role.
NOTETo add another server to the cluster, you will need to do the same work of installing and configuring the server, and then run the kubeadm join command with the appropriate token for the server with the Master or Worker role.
Next, you need to run a few commands to start interacting with the cluster.
We execute the command:
mkdir -p $HOME/.kube
We execute the command:
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
We execute the command:
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Next, you can see the addresses of the master and services using the command:
kubectl cluster-info
Now you can see a list of all nodes in the cluster and the status of each node using the command:
kubectl get nodes
We connect to the server on which we plan to install the Kubernetes Worker role.
Assign a name to the server using the command:
sudo hostnamectl set-hostname kubernetes-worker-1.heyvaldemar.net
This tutorial uses kubernetes-worker-1.heyvaldemar.net
as the name of the server with the Worker role.
The server with the Worker role must resolve the name of the server with the Master role, and also the server with the Master role must resolve the name of the server with the Worker role.
Next, add the IP address and name of the server with the Master role to the “/etc/hosts” file using the command:
echo "10.0.6.19 kubernetes-worker-1.heyvaldemar.net kubernetes-worker-1" | sudo tee -a /etc/hosts
Having this entry will allow the server with the agent installed to resolve the Kubernetes server name even without a DNS entry.
NOTEIn this guide, the Master server name is
kubernetes-worker-1.heyvaldemar.net
and the IP address is 10.0.6.19.
Make sure that the name of the server with the Worker role has the correct DNS entry, and also update the “/etc/hosts” file on the server with the command:
echo "10.0.5.140 kubernetes-master-1.heyvaldemar.net kubernetes-master-1" | sudo tee -a /etc/hosts
Having this entry will allow the server with the agent installed to resolve the Kubernetes server name even without a DNS entry.
NOTEIn this guide, the server name with the Master role is
kubernetes-master-1.heyvaldemar.net
, and the IP address is 10.0.5.140.
Restart the hostamed service for the server name changes to take effect using the command:
sudo systemctl restart systemd-hostnamed
Check the correctness of the server name using the command:
hostname
Now let’s replace the current shell process with the new one using the command:
exec bash
Next, you need to disable the paging file using the command:
sudo swapoff -a
The command above disables the swap file until the system is rebooted. We have to make sure that it stays off even after a reboot. To do this, edit the “fstab” file by commenting out the “/swapfile” line with the ”#” symbol.
We execute the command:
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
Load the kernel modules with the command:
sudo tee /etc/modules-load.d/containerd.conf <<EOFoverlaybr_netfilterEOF
Load the “overlay” module with the command:
sudo modprobe overlay
Load the “br_netfilter” module with the command:
sudo modprobe br_netfilter
Set the kernel options for Kubernetes with the command:
sudo tee /etc/sysctl.d/kubernetes.conf <<EOFnet.bridge.bridge-nf-call-ip6tables = 1net.bridge.bridge-nf-call-iptables = 1net.ipv4.ip_forward = 1EOF
Apply the changes made using the command:
sudo sysctl --system
Now let’s add the official Docker key with the command:
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/docker.gpg
Next, we connect the Docker repository using the command:
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
We press the “Enter” button.
Update the local package index to the latest changes in the repositories using the command:
sudo apt update
Now let’s install the packages required for Kubernetes to work using the command:
sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates containerd.io
Now you need to configure containerd.
containerd - an industry-standard container runtime with an emphasis on simplicity, robustness and portability
We execute the command:
containerd config default | sudo tee /etc/containerd/config.toml >/dev/null 2>&1
We execute the command:
sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml
Restart containerd to apply the changes, using the command:
sudo systemctl restart containerd
We enable autostart of the containerd service at the start of the operating system using the command:
sudo systemctl enable containerd
Now let’s add the official Kubernetes key using the command:
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
Next, we connect the Kubernetes repository using the command:
sudo apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main"
NOTEAt the time of writing this guide, Xenial is the current Kubernetes repository, but when the repository is available for Ubuntu 22.04 (Jammy Jellyfish), you will need to change the word in the command above from “xenial” to “jammy”.
We press the “Enter” button.
Update the local package index to the latest changes in the repositories using the command:
sudo apt update
Now install the kubelet, kubeadm and kubectl packages using the command:
sudo apt install -y kubelet kubeadm kubectl
The next step is to disable automatic updates and removal of installed packages using the command:
sudo apt-mark hold kubelet kubeadm kubectl
Next, you need to add a server with the Worker role to the Kubernetes cluster using the command:
sudo kubeadm join kubernetes-master-1.heyvaldemar.net:6443 --token 5xuqag.tefxcfleieexwbos \ --discovery-token-ca-cert-hash sha256:8c3e8eb9d95cd16496db9f65956e2ce1c2164fa64d17a487374bd906dbc0dcb3
The server with the Worker role has successfully joined the Kubernetes cluster.
We return to the server with the Kubernetes Master role.
Now you can see a list of all nodes in the cluster and the status of each node using the command:
kubectl get nodes
The nodes are in the “NotReady” status. To fix this, you need to install CNI (Container Network Interface) or network add-ons such as Calico, Flannel and Weave-net.
Download the Calico manifest with the command:
curl https://projectcalico.docs.tigera.io/manifests/calico.yaml -O
Install Calico with the command:
kubectl apply -f calico.yaml
Check the status of the pods in the kube-system namespace with the command:
kubectl get pods -n kube-system
Now you can see a list of all nodes in the cluster and the status of each node using the command:
kubectl get nodes
The nodes are in the “Ready” status and the Kubernetes cluster is ready to go.
Patreon Exclusives
🏆 Join my Patreon and dive deep into the world of Docker and DevOps with exclusive content tailored for IT enthusiasts and professionals. As your experienced guide, I offer a range of membership tiers designed to suit everyone from newbies to IT experts.
Tools I Personally Trust
If you’re building things, breaking things, and trying to keep your digital life a little saner (like every good DevOps engineer), these are two tools that I trust and use daily:
🛸 Proton VPN - My shield on the internet. It keeps your Wi-Fi secure, hides your IP, and blocks those creepy trackers. Even if I’m hacking away on free café Wi-Fi, I know I’m safe.
🔑 Proton Pass - My password vault. Proper on-device encryption, 2FA codes, logins, secrets - all mine and only mine. No compromises.
These are partner links - you won’t pay a cent more, but you’ll be supporting DevOps Compass. Thanks a ton - it helps me keep this compass pointing the right way 💜
Gear & Books I Trust
📕 Essential DevOps books
🖥️ Studio streaming & recording kit
📡 Streaming starter kit
Social Channels
🎬 YouTube
🐦 X (Twitter)
🎨 Instagram
🐘 Mastodon
🧵 Threads
🎸 Facebook
🦋 Bluesky
🎥 TikTok
💻 LinkedIn
📣 daily.dev Squad
✈️ Telegram
🐈 GitHub
Community of IT Experts
👾 Discord
Refill My Coffee Supplies
💖 PayPal
🏆 Patreon
🥤 BuyMeaCoffee
🍪 Ko-fi
💎 GitHub
⚡ Telegram Boost
🌟 Bitcoin (BTC): bc1q2fq0k2lvdythdrj4ep20metjwnjuf7wccpckxc
🔹 Ethereum (ETH): 0x76C936F9366Fad39769CA5285b0Af1d975adacB8
🪙 Binance Coin (BNB): bnb1xnn6gg63lr2dgufngfr0lkq39kz8qltjt2v2g6
💠 Litecoin (LTC): LMGrhx8Jsx73h1pWY9FE8GB46nBytjvz8g
Is this content AI-generated?
No. Every article on this blog is written by me personally, drawing on decades of hands-on IT experience and a genuine passion for technology.
I use AI tools exclusively to help polish grammar and ensure my technical guidance is as clear as possible. However, the core ideas, strategic insights, and step-by-step solutions are entirely my own, born from real-world work.
Because of this human-and-AI partnership, some detection tools might flag this content. You can be confident, though, that the expertise is authentic. My goal is to share road-tested knowledge you can trust.