Logo

Cluster Kubernetes (k8s) con Control Plane e Nodi Worker

1. Prerequisiti

I requisiti di Kubernetes sono i seguenti:

2. Disabilita swap

È necessario disabilitare la swap:

   Copia
swapoff -a

Inoltre, modifica /etc/fstab, e commenta la riga che contiene swap. Ad esempio:

   Copia
# COMMENT THE LINE THAT CONTAINS 'swap'
#                 vvvv
#/dev/sda3  none  swap  sw  0 0

3. Configura Kernel

È necessario modificare alcune impostazioni del Kernel.

   Copia
# 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 --system

4. Configura firewall

Assicurati di aprire le seguenti porte:

  • Control Plane:
    • 6443 (TCP):  Kubernetes API Server
    • 2379-2380 (TCP):  etc server client API
    • 10250 (TCP):  Kubelet API
    • 10257 (TCP):  kube-controller-manager
    • 10259 (TCP):  kube-scheduler
  • Nodi Worker:
    • 10250 (TCP):  Kubelet API
    • 10256 (TCP):  kube-proxy
    • 30000-32767 (TCP/UDP):  NodePort Services

CentOS/Fedora/RHEL (firewalld):

   Copia
# 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 --reload

Debian (ufw):

   Copia
# Control Plane
ufw allow 6443,2379:2380,10250,10257,10259/tcp

# Worker Nodes
ufw allow 10250,10256,30000:32767/tcp
ufw allow 30000:32767/udp
Attenzione

Questa è 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

   Copia
# 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
EOF

7. Avvia servizi

   Copia
# 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 start

8. Crea cluster

Crea un cluster con indirizzi IP nel range 10.88.0.0/16:

   Copia
sudo kubeadm init --pod-network-cidr 10.88.0.0/16
Info

Qualora dovessero presentarsi problemi, per resettare ed eliminare il cluster, e tutti i dati relativi a Kubernetes, esegui i comandi seguenti:

   Copia
sudo systemctl stop kubelet
sudo kubeadm reset
sudo rm -rf /etc/kubernetes /var/lib/etc $HOME/.kube
sudo pkill -9 "kube*"
Avvia kubelet:
   Copia
sudo systemctl start kubelet

Una volta creato il cluster, verrà mostrato un comando come il seguente:

   Copia
sudo kubeadm join CONTROL-PLANE-IP:6443 \
--token TOKEN \
--discovery-token-ca-cert-hash sha256:HASH

Questo 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:

   Copia
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Verifica il numero di nodi nel cluster:

   Copia
kubectl get nodes

Esempio di output:

NAMESTATUSROLESAGEVERSION
ControlPlaneReadycontrol-plane1mv1.33.1
Worker1Ready<none>1mv1.33.1
Worker2Ready<none>1mv1.33.1
Worker3Ready<none>1mv1.33.1
Info

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:

   Copia
# 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.yaml

10. Esegui test

Verifichiamo ora che il cluster, il Control Plane, e i Nodi Worker funzionino correttamente.

Crea un namespace di test:

   Copia
kubectl create namespace test

Crea il file nginx.yaml, modificalo, ed inserisci il seguente:

   Copia
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: NodePort

Applica il file:

   Copia
kubectl apply -f nginx.yaml

Controlla che i pod siano stati avviati:

   Copia
watch kubectl get pods -n test

Esegui lo script sottostante per controllare che la funzionalità di load balancing funzioni:

   Copia
#!/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"
done

Ad esempio, se nel cluster vi sono 2 nodi worker, dovresti vedere il seguente output:

   Copia
100.0.10.11 seen 5 times
100.0.10.12 seen 5 times
Info

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:

   Copia
100.0.10.11 seen 4 times
100.0.10.12 seen 6 times

...e subito dopo:

   Copia
100.0.10.11 seen 6 times
100.0.10.12 seen 4 times

Rimuovi l'ambiente di test:

   Copia
kubectl delete -n test configmap/nginx daemonset.apps/nginx service/nginx
kubectl delete namespace test
← Torna alla pagina principale