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-releaseNow 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 -acheck that swap if off with:
sudo swaponif 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/fstabVerify if /etc/fstab row with swap type is commented
Debian needs to disable swap also in systemd:
sudo systemctl mask --now swap.targetNow you could reboot your system and launch
swaponto 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.ascecho \
"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 updatesudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginsudo docker run hello-worldsudo systemctl enable docker
sudo systemctl start dockerDefault 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.tomlsearch 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.tomlNow, restart containerd service with:
sudo systemctl restart containerd5.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 gnupg5.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.gpg5.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.listsudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectlsudo systemctl enable --now kubeletsudo kubeadm initmkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/configkubectl apply -f https://docs.projectcalico.org/manifests/calico.yamlBy 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 TaintIf 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.yamlThen prepare the IPAddressPool config:
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: cheap
namespace: metallb-system
spec:
addresses:
- 192.168.1.18/32where 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: 80kubectl apply -f nginx-deployment.yamlWrite 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: 80In 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: 80kubectl apply -f nginx2-deployment.yamlWrite 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: 80In 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.