Cluster Kubernetes (k8s) con Control Plane e Nodi Worker
1. Prerequisiti
I requisiti di Kubernetes sono i seguenti:
- RAM: >2GB per ogni nodo
- CPU: >2 core (Control plane)
- Hostname univoco per ogni nodo
- Porte aperte nel firewall
2. Disabilita swap
È necessario disabilitare la swap:
swapoff -aInoltre, modifica /etc/fstab, e commenta la riga che contiene swap. Ad esempio:
# COMMENT THE LINE THAT CONTAINS 'swap'
# vvvv
#/dev/sda3 none swap sw 0 03. Configura Kernel
È necessario modificare alcune impostazioni del Kernel.
# Load modules
sudo modprobe overlay
sudo modprobe br_netfilter
# Permanently save changes
cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF
# Tweak sysctl
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
# enables bridged traffic to pass through iptables,
# crucial for routing between nodes and pods
net.bridge.bridge-nf-call-iptables = 1
# allows IP forwarding for pod-to-pod communication across node interfaces
net.ipv4.ip_forward = 1
# manages IPv6 traffic on bridged interfaces through ip6tables, important for IPv6 networking environments
net.bridge.bridge-nf-call-ip6tables = 1
EOF
# Load sysctl tweaks
sudo sysctl --system4. Configura firewall
Assicurati di aprire le seguenti porte:
- Control Plane:
6443(TCP): Kubernetes API Server2379-2380(TCP): etc server client API10250(TCP): Kubelet API10257(TCP): kube-controller-manager10259(TCP): kube-scheduler
- Nodi Worker:
10250(TCP): Kubelet API10256(TCP): kube-proxy30000-32767(TCP/UDP): NodePort Services
CentOS/Fedora/RHEL (firewalld):
# Control Plane
firewall-cmd --zone=public --add-port=6443/tcp --permanent
firewall-cmd --zone=public --add-port=2379-2380/tcp --permanent
firewall-cmd --zone=public --add-port=10250/tcp --permanent
firewall-cmd --zone=public --add-port=10257/tcp --permanent
firewall-cmd --zone=public --add-port=10259/tcp --permanent
firewall-cmd --reload
# Worker Nodes
firewall-cmd --zone=public --add-port=10250/tcp --permanent
firewall-cmd --zone=public --add-port=10256/tcp --permanent
firewall-cmd --zone=public --add-port=30000-32767/tcp --permanent
firewall-cmd --zone=public --add-port=30000-32767/udp --permanent
firewall-cmd --reloadDebian (ufw):
# Control Plane
ufw allow 6443,2379:2380,10250,10257,10259/tcp
# Worker Nodes
ufw allow 10250,10256,30000:32767/tcp
ufw allow 30000:32767/udpQuesta è solo una configurazione di esempio. È vivamente consigliato che tu modifichi questa configurazione in modo tale che solo i tuoi nodi possano comunicare su queste porte.
5. Installa pacchetti
- CentOS/Fedora/RHEL: Copia
# Set SELinux to permissive mode for ease of troubleshooting sudo setenforce 0 sudo sed -i --follow-symlinks 's/SELINUX=enforcing/SELINUX=permissive/g' /etc/sysconfig/selinux # Add containerd repo & install it sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install containerd.io -y # Add kubernetes repo cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://pkgs.k8s.io/core:/stable:/v1.33/rpm/ enabled=1 gpgcheck=1 gpgkey=https://pkgs.k8s.io/core:/stable:/v1.33/rpm/repodata/repomd.xml.key exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni EOF # Install Kubernetes sudo dnf install -y kubelet kubeadm kubectl --disableexcludes=kubernetes - Debian: Copia
# Update repos sudo apt update # Install required packages sudo apt install -y apt-transport-https ca-certificates curl gpg # Copy Kubernetes gpg key for apt curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg # Add Kubernetes repository echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list # Update repos sudo apt update # Install Kubernetes & other packages sudo apt install docker-cli containerd kubectl kubeadm kubelet - Gentoo: Copia
# Control Plane doas emerge -a app-containers/{containerd,cri-o} sys-cluster/kube-{apiserver,controller-manager,proxy,scheduler} sys-cluster/kube{adm,ctl,let,letctl} # Worker Nodes sudo emerge -a app-containers/{containerd,cri-o} sys-cluster/kube{let,-proxy}
6. Configura pacchetti
# Containerd
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
# Gentoo users: do not run if you don't use systemd
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
sudo systemctl restart containerd
# Configure crictl (cri-o)
cat <<EOF | sudo tee /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 3
EOF7. Avvia servizi
# Systemd users (Debian, CentOS, Fedora, RHEL, ...)
sudo systemctl enable --now containerd
sudo systemctl enable --now kubelet
# Gentoo users (OpenRC)
sudo rc-update add containerd default
sudo rc-update add kubelet default
sudo rc-service containerd start
# Note: do not run the line below on the control plane.
# If the control plane also acts as a worker (2-node cluster),
# enable the 'kubelet' service only after creating the cluster.
sudo rc-service kubelet start8. Crea cluster
Crea un cluster con indirizzi IP nel range 10.88.0.0/16:
sudo kubeadm init --pod-network-cidr 10.88.0.0/16Qualora dovessero presentarsi problemi, per resettare ed eliminare il cluster, e tutti i dati relativi a Kubernetes, esegui i comandi seguenti:
sudo systemctl stop kubelet
sudo kubeadm reset
sudo rm -rf /etc/kubernetes /var/lib/etc $HOME/.kube
sudo pkill -9 "kube*"sudo systemctl start kubeletUna volta creato il cluster, verrà mostrato un comando come il seguente:
sudo kubeadm join CONTROL-PLANE-IP:6443 \
--token TOKEN \
--discovery-token-ca-cert-hash sha256:HASHQuesto comando va eseguito su ogni nodo worker da aggiungere al cluster. Sostituisci i parametri in grassetto con quelli ottenuti dal comando.
Dopo aver creato il cluster, copia la configurazione nella tua home directory:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/configVerifica il numero di nodi nel cluster:
kubectl get nodesEsempio di output:
| NAME | STATUS | ROLES | AGE | VERSION |
|---|---|---|---|---|
| ControlPlane | Ready | control-plane | 1m | v1.33.1 |
| Worker1 | Ready | <none> | 1m | v1.33.1 |
| Worker2 | Ready | <none> | 1m | v1.33.1 |
| Worker3 | Ready | <none> | 1m | v1.33.1 |
Ogni nodo tipicamente entra nello status :x quasi immediatamente, o comunque meno di 30 secondi dalla sua data di aggiunta.
9. Installa Calico CNI
Calico CNI (Container Network Interface) fornisce connettività di rete, sicurezza, e osservabilità per applicazioni containerizzate. Installalo con i comandi seguenti:
# Setup tigera operator
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/master/manifests/tigera-operator.yaml
# Download custom resources file
curl https://raw.githubusercontent.com/projectcalico/calico/master/manifests/custom-resources.yaml -O
# Replace default network '192.168.0.0/16' with '10.88.0.0/16'
sed -i "s/192.168.0.0\/16/10.88.0.0\/16/" custom-resources.yaml
# Create custom resources
kubectl create -f custom-resources.yaml10. Esegui test
Verifichiamo ora che il cluster, il Control Plane, e i Nodi Worker funzionino correttamente.
Crea un namespace di test:
kubectl create namespace testCrea il file nginx.yaml, modificalo, ed inserisci il seguente:
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx
namespace: test
data:
nginx.conf: |
worker_processes auto;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
server {
listen 80;
server_name _;
location / {
# Return public IP
resolver 1.1.1.1;
resolver_timeout 5s;
proxy_pass https://ifconfig.me/ip;
}
}
}
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx
namespace: test
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: nginx-config-volume
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: nginx-config-volume
configMap:
name: nginx
---
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: test
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30000
type: NodePortApplica il file:
kubectl apply -f nginx.yamlControlla che i pod siano stati avviati:
watch kubectl get pods -n testEsegui lo script sottostante per controllare che la funzionalità di load balancing funzioni:
#!/bin/bash
IP=controlplane
PORT=30000
declare -A buffer
for i in {1..10}; do
ip=$(curl http://$IP:$PORT 2>/dev/null)
echo "IP: $ip"
if [[ -v buffer["$ip"] ]]; then
buffer["$ip"]=$((buffer["$ip"] + 1))
else
buffer["$ip"]=1
fi
done
for ip in "${!buffer[@]}"; do
seen=${buffer["$ip"]}
echo "$ip seen $seen times"
doneAd esempio, se nel cluster vi sono 2 nodi worker, dovresti vedere il seguente output:
100.0.10.11 seen 5 times
100.0.10.12 seen 5 times
Nota che non sempre ogni nodo sarà presente al 50% (richieste_servite / richieste_totali). Questo è più che normale, in quanto Kubernetes tiene in conto il carico del sistema, oltre ad eseguire uno scheduling round-robin.
Questo significa che, ad esempio, potresti vedere:
100.0.10.11 seen 4 times
100.0.10.12 seen 6 times...e subito dopo:
100.0.10.11 seen 6 times
100.0.10.12 seen 4 timesRimuovi l'ambiente di test:
kubectl delete -n test configmap/nginx daemonset.apps/nginx service/nginx
kubectl delete namespace test
