Complete step-by-step guide for setting up a production-ready Kubernetes cluster on bare metal
π Documentation β’ π Visit SupportPC.org β’ π¬ Get Support
- Overview
- Prerequisites
- Architecture
- Installation Steps
- Step 1: Disable Swap
- Step 2: Update /etc/fstab
- Step 3: Update /etc/hosts
- Step 4: Enable Bridged Traffic in IPTABLES
- Step 5: Install Container Runtime (containerd)
- Step 6: Installing runc
- Step 7: Installing CNI Plugin
- Step 8: Configure containerd
- Step 9: Install Kubernetes Components
- Creating Control Panel
- Adding Calico 3.25 CNI
- Install cri-dockerd (Optional)
- Join Worker Nodes
- Verification
- Troubleshooting
- Additional Resources
- Contributing
This guide provides a comprehensive walkthrough for deploying a production-ready Kubernetes cluster on bare metal infrastructure. Perfect for DevOps engineers, system administrators, and anyone looking to build their own Kubernetes environment from scratch.
- π§ Complete bare metal Kubernetes setup
- π³ Container runtime (containerd) configuration
- π CNI plugin deployment (Calico AND Flannel options)
- π Docker support with cri-dockerd
- π Security best practices
- π Cluster management basics
Before starting, ensure you have:
- π₯οΈ Ubuntu/Debian-based system (tested on Ubuntu 20.04+)
- πΎ Minimum 2GB RAM per node (4GB+ recommended)
- π 2 CPU cores per node minimum
- π Network connectivity between all nodes
- π€ Root or sudo access
- π‘ Static IP addresses for all nodes
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Kubernetes Cluster Architecture β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β β Master Node β β Worker Nodes β β
β β (k8s-control) βββββββΊβ β β
β β β β - Node 1 β β
β β - API Server β β - Node 2 β β
β β - Scheduler β β - Node N β β
β β - Controller β β β β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββ β
β β Container Runtime: containerd v1.6.16 β β
β ββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββ β
β β CNI Plugin (Choose one): β β
β β β’ Calico v3.25 β β
β β β’ Flannel (Recommended) β β
β ββββββββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Kubernetes requires swap to be disabled for optimal performance.
sudo swapoff -aWhy? Kubernetes scheduler needs to manage memory allocation precisely. Swap can interfere with this process.
Prevent swap from being re-enabled after system reboot.
sudo sed -i '/\sswap\s/s/^/#/' /etc/fstabExplanation: This comments out any swap entries in /etc/fstab
Configure hostname resolution for your cluster nodes.
sudo sed -i '/<IP_address>/d; $a\<IP_address>\t<hostname>' /etc/hostsExample:
# For master node
sudo sed -i '/192.168.1.100/d; $a\192.168.1.100\tk8s-master' /etc/hosts
# For worker nodes
sudo sed -i '/192.168.1.101/d; $a\192.168.1.101\tk8s-worker1' /etc/hosts
sudo sed -i '/192.168.1.102/d; $a\192.168.1.102\tk8s-worker2' /etc/hostsEnable necessary kernel modules and network settings for Kubernetes networking.
echo -e "overlay\nbr_netfilter" | sudo tee /etc/modules-load.d/containerd.conf >/dev/null && cat /etc/modules-load.d/containerd.conf
sudo modprobe overlay
sudo modprobe br_netfilter
echo -e "net.bridge.bridge-nf-call-iptables = 1\nnet.bridge.bridge-nf-call-ip6tables = 1\nnet.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/k8s.conf >/dev/null && cat /etc/sysctl.d/k8s.confVerify the configuration:
# Check if modules are loaded
lsmod | grep br_netfilter
lsmod | grep overlay
# Apply sysctl parameters
sudo sysctl --systemInstall containerd as the container runtime for Kubernetes.
wget https://github.com/containerd/containerd/releases/download/v1.6.16/containerd-1.6.16-linux-amd64.tar.gz -P /tmp/
tar Cxzvf /usr/local /tmp/containerd-1.6.16-linux-amd64.tar.gz
wget https://raw.githubusercontent.com/containerd/containerd/main/containerd.service -P /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now containerdVerify installation:
systemctl status containerd
containerd --versionrunc is the container runtime that containerd uses to run containers.
wget https://github.com/opencontainers/runc/releases/download/v1.1.4/runc.amd64 -P /tmp/
install -m 755 /tmp/runc.amd64 /usr/local/sbin/runcVerify installation:
runc --versionContainer Network Interface (CNI) plugins for network configuration.
wget https://github.com/containernetworking/plugins/releases/download/v1.2.0/cni-plugins-linux-amd64-v1.2.0.tgz -P /tmp/
mkdir -p /opt/cni/bin
tar Cxzvf /opt/cni/bin /tmp/cni-plugins-linux-amd64-v1.2.0.tgzVerify installation:
ls -la /opt/cni/bin/Generate and customize containerd configuration.
mkdir -p /etc/containerd
containerd config default | tee /etc/containerd/config.toml/etc/containerd/config.toml and change SystemdCgroup to true
# Edit the config file
sudo nano /etc/containerd/config.toml
# Find this line (around line 125):
# SystemdCgroup = false
# Change it to:
# SystemdCgroup = trueRestart containerd:
systemctl restart containerdInstall Kubernetes components from official repository.
apt-get update
apt-get install -y apt-transport-https ca-certificates curl
curl -fsSLo /etc/apt/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | tee /etc/apt/sources.list.d/kubernetes.list
apt-get update
sudo -s
apt-get install -y kubelet=1.26.1-00 kubeadm=1.26.1-00 kubectl=1.26.1-00
apt-mark hold kubelet kubeadm kubectlVerify installation:
kubectl version --client
kubeadm version
kubelet --versionInitialize the Kubernetes cluster on the master node.
kubeadm init --pod-network-cidr 10.10.0.0/16 --kubernetes-version 1.26.1 --node-name k8s-controlNote: Change
10.10.0.0/16to your network CIDR if needed
kubeadm init --config=kubeadm-config.yaml --upload-certskubeadm join command from the output! You'll need it for worker nodes.
Configure kubectl access:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/configVerify cluster:
kubectl cluster-info
kubectl get nodesChoose one CNI plugin for your cluster networking.
# Install Tigera Operator
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/tigera-operator.yaml
# Download and customize resources
wget https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/custom-resources.yaml
# Edit the CIDR for pods if it's custom
vi custom-resources.yaml
# Apply configuration
kubectl apply -f custom-resources.yamlWatch Calico pods deployment:
watch kubectl get pods -n calico-system# Apply Flannel manifest
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.ymlAlternative deployment: Check Flannel Manual Deployment
Restart services if needed:
sudo systemctl restart containerd
systemctl daemon-reloadIf you need Docker support alongside containerd.
systemctl status docker# Update and install prerequisites
sudo apt update
sudo apt install git wget curl
# Get latest version
VER=$(curl -s https://api.github.com/repos/Mirantis/cri-dockerd/releases/latest|grep tag_name | cut -d '"' -f 4|sed 's/v//g')
echo $VER# Download cri-dockerd
wget https://github.com/Mirantis/cri-dockerd/releases/download/v${VER}/cri-dockerd-${VER}.amd64.tgz
# Extract and install
tar xvf cri-dockerd-${VER}.amd64.tgz
sudo mv cri-dockerd/cri-dockerd /usr/local/bin/
# Verify installation
cri-dockerd --version# Download service files
wget https://raw.githubusercontent.com/Mirantis/cri-dockerd/master/packaging/systemd/cri-docker.service
wget https://raw.githubusercontent.com/Mirantis/cri-dockerd/master/packaging/systemd/cri-docker.socket
# Move to systemd directory
sudo mv cri-docker.socket cri-docker.service /etc/systemd/system/
# Update service path
sudo sed -i -e 's,/usr/bin/cri-dockerd,/usr/local/bin/cri-dockerd,' /etc/systemd/system/cri-docker.service
# Reload systemd
sudo systemctl daemon-reload
# Enable services
sudo systemctl enable cri-docker.service
sudo systemctl enable --now cri-docker.socket
sudo systemctl enable cri-docker.service
sudo systemctl enable cri-docker.socket
# Start services
sudo systemctl start cri-docker.service
sudo systemctl start cri-docker.socketCheck service status:
journalctl -u cri-docker.service
sudo systemctl status cri-docker.serviceAdd worker nodes to your Kubernetes cluster.
On each worker node:
# Use the join command from kubeadm init output
sudo kubeadm join <MASTER_IP>:6443 \
--token <YOUR_TOKEN> \
--discovery-token-ca-cert-hash sha256:<YOUR_HASH>If you lost the join command, generate a new one on master:
kubeadm token create --print-join-commandkubectl get nodesExpected output:
NAME STATUS ROLES AGE VERSION
k8s-control Ready control-plane 15m v1.26.1
k8s-worker1 Ready <none> 10m v1.26.1
k8s-worker2 Ready <none> 10m v1.26.1
# Check all pods across all namespaces
kubectl get pods -A
# Check node details
kubectl get nodes -o wide
# Check cluster info
kubectl cluster-info
# Check component status
kubectl get componentstatuses
# Check namespaces
kubectl get namespaces
# Verify CNI plugin (for Calico)
kubectl get pods -n calico-system
# Verify CNI plugin (for Flannel)
kubectl get pods -n kube-flannelβ οΈ Nodes showing NotReady status
# Check kubelet status
sudo systemctl status kubelet
# View kubelet logs
sudo journalctl -u kubelet -n 100 --no-pager
# Check CNI installation
kubectl get pods -n kube-system
# Restart kubelet
sudo systemctl restart kubeletβ οΈ containerd not starting
# Check containerd status
sudo systemctl status containerd
# View containerd logs
sudo journalctl -u containerd -n 100 --no-pager
# Verify configuration
sudo containerd config dump
# Restart containerd
sudo systemctl restart containerdβ οΈ Pod network not working
# Verify network modules
lsmod | grep br_netfilter
lsmod | grep overlay
# Check sysctl settings
sysctl net.bridge.bridge-nf-call-iptables
sysctl net.bridge.bridge-nf-call-ip6tables
sysctl net.ipv4.ip_forward
# Reload network configuration
sudo sysctl --systemβ οΈ CoreDNS pods pending
# Check CoreDNS status
kubectl get pods -n kube-system | grep coredns
# Describe CoreDNS pod
kubectl describe pod -n kube-system <coredns-pod-name>
# Restart CoreDNS
kubectl rollout restart deployment coredns -n kube-systemβ οΈ Worker node join fails
# On worker node - reset kubeadm
sudo kubeadm reset
# Clean up
sudo rm -rf /etc/cni/net.d
sudo rm -rf $HOME/.kube/config
# Generate new token on master
kubeadm token create --print-join-command
# Try joining again- Kubernetes: https://kubernetes.io/docs/
- containerd: https://containerd.io/docs/
- Calico: https://docs.tigera.io/calico/latest/about/
- Flannel: https://github.com/flannel-io/flannel#deploying-flannel-manually
# Cluster Management
kubectl cluster-info # Display cluster info
kubectl get nodes # List all nodes
kubectl get pods -A # List all pods in all namespaces
kubectl get services -A # List all services
# Pod Management
kubectl get pods -n <namespace> # List pods in namespace
kubectl describe pod <pod-name> # Detailed pod info
kubectl logs <pod-name> # View pod logs
kubectl exec -it <pod-name> -- /bin/bash # Access pod shell
# Node Management
kubectl describe node <node-name> # Detailed node info
kubectl cordon <node-name> # Mark node unschedulable
kubectl uncordon <node-name> # Mark node schedulable
kubectl drain <node-name> # Drain node for maintenance
# Troubleshooting
kubectl get events -A # View cluster events
journalctl -u kubelet -f # Follow kubelet logs
journalctl -u containerd -f # Follow containerd logs
kubectl top nodes # Node resource usage
kubectl top pods -A # Pod resource usageVisit SupportPC.org for:
- π¬ Community Support - Get help from experienced users
- π Additional Guides - More tutorials and documentation
- π― Professional Services - Expert consulting and training
- π§ Troubleshooting - Dedicated assistance for your issues
- π§ Contact Us - Direct support channels
We welcome contributions! Here's how you can help:
- π΄ Fork the repository
- π§ Create a feature branch (
git checkout -b feature/AmazingFeature) - π‘ Commit your changes (
git commit -m 'Add some AmazingFeature') - π€ Push to the branch (
git push origin feature/AmazingFeature) - π Open a Pull Request
- Ensure all commands are tested
- Update documentation for any changes
- Follow existing formatting style
- Add comments for complex configurations
- v1.26.1 - Current stable release
- containerd v1.6.16
- Calico v3.25.0
- Support for both Calico and Flannel CNI
- Optional cri-dockerd support
This guide is available under the MIT License.
If this guide helped you set up your Kubernetes cluster, please:
- β Star this repository
- π Share it with your colleagues and friends
- π’ Follow us on SupportPC.org
- π¬ Leave feedback and suggestions
- π Write about your experience
Made with β€οΈ by the SupportPC.org Team
For professional support and consulting services, visit our website:
π SupportPC.org