Post

Guía de Instalación de kubeadm

Guía de Instalación de kubeadm

Guía paso a paso para instalar kubeadm en Linux sin gestor de paquetes.


¿Qué es kubeadm?

kubeadm es una herramienta oficial de Kubernetes que permite crear clústeres de forma sencilla mediante dos comandos principales:

  • kubeadm init → Inicializa el nodo maestro (control plane)
  • kubeadm join → Une nodos trabajadores al clúster

Componentes que instalaremos

Componente Función
kubeadm Herramienta para crear y gestionar el clúster
kubelet Agente que corre en cada nodo y gestiona los pods/contenedores
kubectl Cliente de línea de comandos para interactuar con el clúster

Paso 1: Configurar Swap

¿Por qué? → El kubelet por defecto no arranca si detecta swap activo, ya que puede afectar al rendimiento y la predicción de recursos de los contenedores.

1
2
3
4
5
# Desactivar swap temporalmente
sudo swapoff -a

# Desactivar swap permanentemente (comentar línea de swap en fstab)
sudo sed -i '/ swap / s/^/#/' /etc/fstab

Paso 2: Instalar un Container Runtime

¿Por qué? → Kubernetes necesita un runtime de contenedores para ejecutar los pods. Kubernetes usa la interfaz CRI (Container Runtime Interface) para comunicarse con el runtime.

Instalar containerd (recomendado)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# En Debian/Ubuntu
sudo apt-get update
sudo apt-get install -y containerd

# Crear configuración por defecto
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml

# Habilitar SystemdCgroup (importante para kubelet)
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml

# Reiniciar containerd
sudo systemctl restart containerd
sudo systemctl enable containerd

Paso 3: Cargar módulos del kernel necesarios

¿Por qué? → Kubernetes necesita ciertos módulos del kernel para el networking entre contenedores.

1
2
3
4
5
6
7
8
9
# Crear archivo de configuración para cargar módulos al arranque
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

# Cargar módulos ahora
sudo modprobe overlay
sudo modprobe br_netfilter

Explicación de los módulos:

  • overlay → Sistema de archivos usado por los contenedores
  • br_netfilter → Permite que el tráfico de red de bridges pase por iptables

Paso 4: Configurar parámetros de red del kernel

¿Por qué? → Permite que los paquetes de red sean procesados correctamente entre pods.

1
2
3
4
5
6
7
8
9
# Configurar parámetros sysctl
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

# Aplicar parámetros sin reiniciar
sudo sysctl --system

Explicación:

  • bridge-nf-call-iptables → El tráfico del bridge pasa por iptables (necesario para Network Policies)
  • ip_forward → Permite que el nodo actúe como router (necesario para routing entre pods)

Paso 5: Instalar kubeadm, kubelet y kubectl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 1. Instalar plugins CNI (necesarios para la red de pods)
CNI_PLUGINS_VERSION="v1.3.0"
ARCH="amd64"
DEST="/opt/cni/bin"
sudo mkdir -p "$DEST"
curl -L "https://github.com/containernetworking/plugins/releases/download/${CNI_PLUGINS_VERSION}/cni-plugins-linux-${ARCH}-${CNI_PLUGINS_VERSION}.tgz" | sudo tar -C "$DEST" -xz

# 2. Definir directorio de descarga
DOWNLOAD_DIR="/usr/local/bin"
sudo mkdir -p "$DOWNLOAD_DIR"

# 3. Instalar kubeadm y kubelet
RELEASE="$(curl -sSL https://dl.k8s.io/release/stable.txt)"
ARCH="amd64"
cd $DOWNLOAD_DIR
sudo curl -L --remote-name-all https://dl.k8s.io/release/${RELEASE}/bin/linux/${ARCH}/{kubeadm,kubelet}
sudo chmod +x {kubeadm,kubelet}

# 4. Configurar servicio systemd para kubelet
RELEASE_VERSION="v0.16.2"
curl -sSL "https://raw.githubusercontent.com/kubernetes/release/${RELEASE_VERSION}/cmd/krel/templates/latest/kubelet/kubelet.service" | \
    sed "s:/usr/bin:${DOWNLOAD_DIR}:g" | sudo tee /usr/lib/systemd/system/kubelet.service

sudo mkdir -p /usr/lib/systemd/system/kubelet.service.d
curl -sSL "https://raw.githubusercontent.com/kubernetes/release/${RELEASE_VERSION}/cmd/krel/templates/latest/kubeadm/10-kubeadm.conf" | \
    sed "s:/usr/bin:${DOWNLOAD_DIR}:g" | sudo tee /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf

# 5. Instalar kubectl
cd ~
curl -LO "https://dl.k8s.io/release/${RELEASE}/bin/linux/${ARCH}/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
rm kubectl

Paso 6: Habilitar el servicio kubelet

¿Por qué? → El kubelet debe estar activo para que kubeadm pueda configurarlo durante la inicialización del clúster.

1
sudo systemctl enable --now kubelet

Nota: En este punto el kubelet estará en un bucle de reinicio (crashloop). Esto es normal porque está esperando instrucciones de kubeadm.


Paso 7: Crear enlace simbólico para plugins CNI

¿Por qué? → Algunos componentes (como CoreDNS) buscan los plugins CNI en /usr/lib/cni, pero la instalación estándar los coloca en /opt/cni/bin. Sin este enlace, los pods de sistema como CoreDNS pueden quedarse en estado ContainerCreating o CrashLoopBackOff.

Ejecutar en todos los nodos (control-plane y workers):

1
2
3
4
5
# Crear directorio si no existe
sudo mkdir -p /usr/lib/cni

# Crear enlaces simbólicos a los plugins CNI
sudo ln -s /opt/cni/bin/* /usr/lib/cni/

Si ya habías inicializado el clúster y tienes pods en estado fallido:

1
2
3
4
5
6
7
8
# En el nodo control-plane, reiniciar kubelet
sudo systemctl restart kubelet

# Eliminar pods del sistema para que se regeneren
kubectl delete pod -n kube-system --all

# Si tienes ingress-nginx instalado
kubectl delete pod -n ingress-nginx --all

Verificación final

Antes de ejecutar kubeadm init, verifica que todo esté listo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Verificar que los módulos están cargados
lsmod | grep br_netfilter
lsmod | grep overlay

# Verificar parámetros de red
sysctl net.bridge.bridge-nf-call-iptables
sysctl net.ipv4.ip_forward

# Verificar que swap está desactivado
free -h

# Verificar que el runtime está funcionando
sudo systemctl status containerd

# Verificar que los enlaces CNI existen
ls -la /usr/lib/cni/

# Verificar versiones instaladas
kubeadm version
kubelet --version
kubectl version --client

Siguientes pasos

Una vez completada la instalación, puedes:

  1. Inicializar el nodo maestro:
    1
    
    sudo kubeadm init --pod-network-cidr=10.244.0.0/16
    
  2. Configurar kubectl para tu usuario:
    1
    2
    3
    
    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config
    
  3. Instalar un plugin de red (CNI):
    1
    2
    
    # Flannel
    kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
    
  4. Instalar NGINX Ingress Controller:
    1
    2
    3
    4
    
    kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/baremetal/deploy.yaml
       
    # Verificar que está corriendo
    kubectl get pods -n ingress-nginx
    
  5. Unir nodos worker al clúster:
    1
    2
    
    # Usar el comando que devuelve kubeadm init
    kubeadm join <master-ip>:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>
    

Comandos útiles de kubeadm

Comando Descripción
kubeadm init Inicializa el control plane
kubeadm join Une un nodo al clúster
kubeadm reset Deshace cambios de init/join
kubeadm token Gestiona tokens de bootstrap
kubeadm upgrade Actualiza el clúster
kubeadm certs Gestiona certificados
kubeadm version Muestra la versión

Balanceador de carga con HAProxy

Para distribuir el tráfico entre los nodos worker, puedes usar HAProxy en una máquina separada.

1. Instalar HAProxy

1
2
sudo apt-get update
sudo apt-get install -y haproxy

2. Obtener el NodePort del ingress

Desde el master:

1
kubectl get svc -n ingress-nginx ingress-nginx-controller

Verás algo como:

1
2
NAME                       TYPE       CLUSTER-IP     PORT(S)                      
ingress-nginx-controller   NodePort   10.96.x.x      80:31080/TCP,443:31443/TCP

Anota los puertos (en el ejemplo: 31080 para HTTP, 31443 para HTTPS).

3. Configurar HAProxy

Edita /etc/haproxy/haproxy.cfg:

1
sudo nano /etc/haproxy/haproxy.cfg

Añade al final (cambia los NodePorts e IPs por los tuyos):

#---------------------------------------------------------------------
# Frontend HTTP
#---------------------------------------------------------------------
frontend http_front
    bind *:80
    default_backend http_back

#---------------------------------------------------------------------
# Frontend HTTPS
#---------------------------------------------------------------------
frontend https_front
    bind *:443
    mode tcp
    default_backend https_back

#---------------------------------------------------------------------
# Backend HTTP - Workers de Kubernetes
#---------------------------------------------------------------------
backend http_back
    balance roundrobin
    server k8s-worker1 <IP_WORKER1>:31080 check
    server k8s-worker2 <IP_WORKER2>:31080 check

#---------------------------------------------------------------------
# Backend HTTPS - Workers de Kubernetes
#---------------------------------------------------------------------
backend https_back
    mode tcp
    balance roundrobin
    server k8s-worker1 <IP_WORKER1>:31443 check
    server k8s-worker2 <IP_WORKER2>:31443 check

#---------------------------------------------------------------------
# Estadísticas (opcional)
#---------------------------------------------------------------------
listen stats
    bind *:8404
    stats enable
    stats uri /stats
    stats refresh 10s

Reemplaza:

  • <IP_WORKER1> → IP de k8s-worker1
  • <IP_WORKER2> → IP de k8s-worker2
  • 31080 y 31443 → Los NodePorts que obtuviste

4. Reiniciar HAProxy

1
2
3
4
5
6
# Verificar sintaxis
sudo haproxy -c -f /etc/haproxy/haproxy.cfg

# Reiniciar y habilitar
sudo systemctl restart haproxy
sudo systemctl enable haproxy

5. Configurar acceso

Añade en el /etc/hosts de tu máquina cliente:

1
<IP_HAPROXY>  django-tutorial.local

Luego accede a http://django-tutorial.local.

6. Verificar el balanceo

Panel de estadísticas:

Accede a http://<IP_HAPROXY>:8404/stats para ver el estado de los backends.

Probar con curl:

1
curl -H "Host: django-tutorial.local" http://<IP_HAPROXY>

Ver logs de los pods:

1
kubectl logs -f -l app=django-tutorial -n django-tutorial

Troubleshooting común

CoreDNS o pods del sistema no arrancan (ContainerCreating)

Problema típico: los plugins CNI están en /opt/cni/bin pero se buscan en /usr/lib/cni.

1
2
3
4
5
# Ver el estado de los pods del sistema
kubectl get pods -n kube-system

# Si CoreDNS está en ContainerCreating, verificar logs
kubectl describe pod -n kube-system -l k8s-app=kube-dns

Solución (ejecutar en todos los nodos):

1
2
3
4
5
6
sudo mkdir -p /usr/lib/cni
sudo ln -s /opt/cni/bin/* /usr/lib/cni/

# En el control-plane
sudo systemctl restart kubelet
kubectl delete pod -n kube-system --all

El kubelet no arranca

1
2
# Ver logs del kubelet
journalctl -xeu kubelet

Problemas de red

1
2
3
4
5
# Verificar que los módulos están cargados
lsmod | grep br_netfilter

# Si no están, cargarlos manualmente
sudo modprobe br_netfilter

Swap activo

1
2
3
4
5
# Verificar swap
swapon --show

# Desactivar
sudo swapoff -a

Referencias

This post is licensed under CC BY 4.0 by the author.