The goal of this tutorial is to install a kubernetes cluster using Debian 11 or above.
This tutorial covers also as creating a single node cluster (step 7).
Before starting the installation process, ensure you have:
- Debian 12 or 11 machines (one master and one worker node or a single master node).
- Root or sudo access on all machines.
- At least 2 GB of RAM and 2 CPUs per machine.
- A stable internet connection for downloading packages.
sudo apt update
sudo apt upgrade
sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release
Now you must disable swap to allow kubernetes installation.
If you can't or don't want to reboot the machine, temporarely disable the swap with this command:
sudo swapoff -a
check that swap if off with:
sudo swapon
if the command does not return anything, the swap is off.
But you need to disable permanently the swap to ensure that it is disable also after a reboot.
Find the line in /etc/fstab
referring to swap, and comment it. This command should be enough:
sudo sed -i '/\s\+none\s\+swap\s\+/s/^/#/' /etc/fstab
Verify if /etc/fstab row with swap
type is commented
Debian needs to disable swap also in systemd:
sudo systemctl mask --now swap.target
Now you could reboot your system and launch
swapon
to see if the swap if off after a reboot.
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo docker run hello-world
sudo systemctl enable docker
sudo systemctl start docker
Default package containerd configuration is minimal and does not set cfgroup value to true
for systemd.
So, to apply full containerd configuration launch this command as root user:
containerd config default > /etc/containerd/config.toml
search the key SystemdCgroup=false
under [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
section, and set the value to true.
sudo sed -i 's/SystemdCgroup\s*=\s*false/SystemdCgroup = true/' /etc/containerd/config.toml
Now, restart containerd service with:
sudo systemctl restart containerd
5.1 - Update the apt package index and install packages needed to use the Kubernetes apt repository:
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
5.2 - Download the public signing key for the Kubernetes package repositories. The same signing key is used for all repositories so you can disregard the version in the URL:
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
5.3 - Add the appropriate Kubernetes apt repository. If you want to use Kubernetes version different than v1.30, replace v1.30 with the desired minor version in the command below:
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
sudo systemctl enable --now kubelet
sudo kubeadm init
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
By default, your cluster will not schedule Pods on the control plane nodes for security reasons. If you want to be able to schedule Pods on the control plane nodes, for example for a single machine Kubernetes cluster, run:
kubectl taint nodes --all node-role.kubernetes.io/control-plane:NoSchedule-
Check if taint is removed with
kubectl describe node | grep Taint
If you are installing the load balancer inside the master node, you must apply previous point to remove NoSchedule pods from master node.
Apply the manifest:
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.8/config/manifests/metallb-native.yaml
Then prepare the IPAddressPool config:
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: cheap
namespace: metallb-system
spec:
addresses:
- 192.168.1.18/32
where address can be a single ip (this example) or a subnet (ex. 192.168.10.0/24, 42.176.25.64/30) or multiple rows.
Source: https://metallb.universe.tf/configuration/_advanced_ipaddresspool_configuration/
Write the content to nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
kubectl apply -f nginx-deployment.yaml
Write the content to nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: default
annotations:
metallb.universe.tf/allow-shared-ip: "publicip-192.168.1.18"
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
In this example, I have just one available ip 192.168.1.18
, otherwise the section annotations
can be removed:
annotations:
metallb.universe.tf/allow-shared-ip: "publicip-192.168.1.18"
Go to http://192.168.1.18 to show nginx welcome page.
Write the content to nginx2-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx2-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx2
template:
metadata:
labels:
app: nginx2
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
kubectl apply -f nginx2-deployment.yaml
Write the content to nginx2-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx2-service
namespace: default
annotations:
metallb.universe.tf/allow-shared-ip: "publicip-192.168.1.18"
spec:
type: LoadBalancer
selector:
app: nginx2
ports:
- protocol: TCP
port: 81
targetPort: 80
In this example, I have just one available ip 192.168.1.18
, otherwise the section annotations
can be removed:
annotations:
metallb.universe.tf/allow-shared-ip: "publicip-192.168.1.18"
Go to http://192.168.1.18:81 (port 81) to show nginx welcome page.