Problema
Muchos entusiastas de homelab quieren practicar Kubernetes sin invertir en hardware dedicado. La configuración típica consiste en un host Proxmox que ejecuta varias VMs Ubuntu: una para el control‑plane y una o más para workers. El reto no es solo lanzar las VMs; es asegurarse de que la red interna, los requisitos de kubeadm y la persistencia de los componentes funcionen sin sorpresas. Cuando la red de Proxmox está configurada con puentes Linux y NAT, es fácil encontrarse con errores de “connection refused”, “node not ready” o problemas de sincronización de tiempo que hacen que el clúster nunca alcance estado “Ready”.
Causa
- Puente de red mal configurado – Proxmox permite varios tipos de interfaces (Linux Bridge, Open vSwitch, VLAN). Si el bridge no pasa tráfico entre las VMs o no está conectado a la red física, los nodos no pueden comunicarse con el API server.
- Direcciones IP estáticas vs DHCP – kubeadm genera certificados basados en la IP del control‑plane. Cambiar la IP después de
kubeadm initinvalida los certificados y los workers no pueden unirse. - Desfase de tiempo – Los nodos sin NTP pueden presentar diferencias de varios segundos; los certificados TLS fallan y el kubelet se queda en
NotReady. - Swap activado – kubeadm aborta si el swap está activo; en entornos de prueba a veces se olvida desactivarlo.
- Módulos del kernel ausentes – Algunas configuraciones de Proxmox usan kernels personalizados que no incluyen
br_netfilterooverlay, obligatorios para la red de pods.
Solución
1. Preparar la infraestructura en Proxmox
- Crea un Linux Bridge (por ejemplo
vmbr10) conectado a la NIC física que usarás para el tráfico del clúster. - Asigna a cada VM una IP estática dentro del mismo rango (p.ej. 192.168.100.10‑12) y habilita la opción “bridge firewall” solo si ya tienes reglas definidas.
- Desactiva el swap en la plantilla Ubuntu antes de clonarla:
swapoff -a && sed -i '/ swap / s/^/#/' /etc/fstab.
2. Configurar los nodos Ubuntu
En cada VM:
apt-get update && apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
apt-get update && apt-get install -y docker-ce docker-ce-cli containerd.io
systemctl enable docker && systemctl start docker
cat <<EOF > /etc/modules-load.d/k8s.conf
br_netfilter
overlay
EOF
modprobe br_netfilter
modprobe overlay
cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
sysctl --system
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl
- Habilita NTP:
apt-get install -y chrony && systemctl enable --now chrony.
3. Inicializar el control‑plane
En la VM designada como master, ejecuta:
kubeadm init --apiserver-advertise-address=192.168.100.10 --pod-network-cidr=10.244.0.0/16 --control-plane-endpoint=192.168.100.10
- Copia el
kubeconfigal usuario regular:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
- Despliega una red de pods ligera (Flannel funciona sin requisitos extra):
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
4. Añadir los workers
En cada worker, usa la línea kubeadm join que kubeadm init imprimió, por ejemplo:
kubeadm join 192.168.100.10:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>
Si la línea se perdió, recupérala en el master con kubeadm token create --print-join-command.
5. Ajustes post‑instalación
- Persistencia de la IP: bloquea la interfaz con
netplanpara evitar que DHCP cambie la dirección. - Firewall: abre puertos 6443 (API), 10250 (kubelet), 10255 (read‑only) y los rangos de la red de pods. En Proxmox, desactiva el firewall del bridge o crea reglas específicas.
- Snapshots: toma un snapshot de cada VM después de que el nodo esté
Ready. Facilita volver a un estado limpio si pruebas algo arriesgado.
Cuándo aplicar esta solución
- Entornos de aprendizaje donde se dispone de un único host físico y se quiere simular un clúster multi‑node.
- Pruebas de CI/CD que requieren un clúster real pero no justifican hardware dedicado.
- Validación de add‑ons (Ingress, CSI, observabilidad) antes de migrar a producción.
No es adecuada cuando:
- Se necesita alta disponibilidad del control‑plane; un solo master no tolera fallos.
- El tráfico del clúster debe cruzar subredes distintas a la del bridge de Proxmox sin configuración adicional de routing.
- Se busca rendimiento de producción; la sobrecarga de virtualización y la red NAT pueden ser cuellos de botella.
Código
# En el master
kubeadm init --apiserver-advertise-address=192.168.100.10 \
--pod-network-cidr=10.244.0.0/16 \
--control-plane-endpoint=192.168.100.10
# Copiar kubeconfig
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# Instalar Flannel
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# En cada worker
kubeadm join 192.168.100.10:6443 --token <token> \
--discovery-token-ca-cert-hash sha256:<hash>
Verificación
- En el master,
kubectl get nodesdebe listar 3 nodos con estadoReady. kubectl get pods -n kube-systemdebe mostrar todos los pods de Flannel y CoreDNS enRunning.- Desde cualquier worker, prueba la conectividad al API:
curl -k https://192.168.100.10:6443/healthz. - Verifica que los pods pueden comunicarse entre sí creando un deployment de prueba y ejecutando
kubectl execpara ping a otro pod.
Notas adicionales
- Tiempo de arranque: la primera vez que inicias los workers pueden tardar varios minutos en pasar de
NotReadyaReadymientras el kubelet descarga imágenes del repositorio. - Versión de Docker vs containerd: kubeadm soporta ambos, pero si prefieres containerd, reemplaza la instalación de Docker por
apt-get install -y containerd. Ajusta el archivo/etc/containerd/config.tomlpara usar el driversystemd. - Actualizaciones: cuando actualices Kubernetes, repite solo
apt-get upgrade -y kubeadm kubelet kubectly sigue el proceso dekubeadm upgrade. Los nodos VM pueden ser recreados desde snapshots para evitar problemas de versión. - Persistencia de datos: para practicar StatefulSets, crea discos virtuales adicionales y móntalos dentro de los workers; recuerda añadir la etiqueta
node.kubernetes.io/disksi usas un provisionador dinámico.
Con esta guía puedes levantar rápidamente un clúster funcional en Proxmox, experimentar con recursos de Kubernetes y, lo más importante, evitar los errores típicos que aparecen cuando la red o el tiempo no están alineados. ¡A jugar con pods, servicios y operadores!