Capitulo 16: Cluster Multi-Nodo
Capitulo 16: Cluster Multi-Nodo
< Volver al Indice del Tutorial
Single Node vs Multi-Nodo
Hasta ahora hemos trabajado con un solo nodo que cumple los roles de server (control plane) y worker. Esto funciona para desarrollo y aplicaciones pequenas, pero tiene limitaciones:
- Sin alta disponibilidad: si el nodo cae, todo cae
- Recursos limitados: estas atado a la CPU y RAM de una sola maquina
- Sin aislamiento: los workloads compiten por los mismos recursos
Escalar a multiples nodos te da redundancia, mas capacidad y la posibilidad de distribuir workloads estrategicamente.
Arquitectura Multi-Nodo
Un cluster K3s multi-nodo tiene dos tipos de nodos:
- Server: ejecuta el control plane (API server, scheduler, controller manager) y etcd/SQLite. Puede tambien ejecutar workloads
- Agent: solo ejecuta workloads (pods). Se conecta al server para recibir instrucciones
┌──────────────┐
│ Server │
│ Control Plane│
│ + Workloads │
└──────┬───────┘
│
┌───────────┼───────────┐
│ │ │
┌──────┴──────┐ ┌──┴───────┐ ┌┴──────────┐
│ Agent 1 │ │ Agent 2 │ │ Agent 3 │
│ Workloads │ │ Workloads│ │ Workloads │
└─────────────┘ └──────────┘ └────────────┘
Obtener el Token
El server genera un token que los agents necesitan para unirse al cluster. Este token se crea automaticamente durante la instalacion de K3s:
# En el nodo server
cat /var/lib/rancher/k3s/server/node-token
Guarda este token. Lo necesitaras en cada agent que agregues.
Tambien necesitas la IP del server:
# IP del server
hostname -I | awk '{print $1}'
Agregar Agent Nodes
En cada maquina que quieras agregar como agent, ejecuta:
curl -sfL https://get.k3s.io | \
K3S_URL=https://IP_DEL_SERVER:6443 \
K3S_TOKEN=TOKEN_DEL_SERVER \
sh -
Reemplaza IP_DEL_SERVER con la IP de tu nodo server y TOKEN_DEL_SERVER con el token obtenido.
Requisitos de los Agents
- Conectividad de red al puerto 6443 del server
- Puertos 10250 (kubelet) y 8472/UDP (VXLAN para Flannel) abiertos
- Al menos 512MB de RAM y 1 vCPU
Verificar
Desde el nodo server:
kubectl get nodes
Deberias ver todos los nodos con status Ready:
NAME STATUS ROLES AGE VERSION
server-1 Ready control-plane,master 10d v1.31.4+k3s1
agent-1 Ready <none> 1m v1.31.4+k3s1
agent-2 Ready <none> 30s v1.31.4+k3s1
Labels
Los labels son pares clave-valor que etiquetan nodos para organizar y seleccionar donde corren los workloads.
Etiquetar nodos
# Asignar un label
kubectl label node agent-1 tipo=compute
# Asignar multiples labels
kubectl label node agent-2 tipo=storage zona=us-east
# Ver labels de un nodo
kubectl get node agent-1 --show-labels
# Eliminar un label
kubectl label node agent-1 tipo-
Usar labels en pods
Con nodeSelector indicas en que nodos puede correr un pod:
apiVersion: v1
kind: Pod
metadata:
name: mi-app
spec:
nodeSelector:
tipo: compute
containers:
- name: app
image: mi-app:latest
Este pod solo se programara en nodos con el label tipo=compute.
Taints y Tolerations
Los taints son lo opuesto a los labels: en lugar de atraer pods, los repelen. Solo los pods con la toleration correspondiente pueden ejecutarse en un nodo con taint.
Agregar un taint
# Sintaxis: kubectl taint nodes NODO clave=valor:efecto
kubectl taint nodes server-1 rol=control-plane:NoSchedule
Los efectos disponibles son:
- NoSchedule: no programar pods nuevos (los existentes se quedan)
- PreferNoSchedule: evitar si es posible, pero no es estricto
- NoExecute: no programar y ademas desalojar los pods existentes
Tolerar un taint
apiVersion: v1
kind: Pod
metadata:
name: pod-en-server
spec:
tolerations:
- key: "rol"
operator: "Equal"
value: "control-plane"
effect: "NoSchedule"
containers:
- name: app
image: mi-app:latest
Eliminar un taint
kubectl taint nodes server-1 rol=control-plane:NoSchedule-
Node Affinity
Node affinity es una version mas expresiva de nodeSelector. Permite reglas complejas con operadores logicos.
Required (obligatorio)
El pod solo se programa si se cumple la condicion:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: tipo
operator: In
values:
- compute
- general
Preferred (preferido)
El scheduler intenta cumplir la condicion pero no es obligatorio:
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: zona
operator: In
values:
- us-east
El weight (1-100) indica que tan fuerte es la preferencia. Se pueden combinar multiples preferencias.
Cordon y Drain
Cuando necesitas dar mantenimiento a un nodo (actualizar el OS, agregar RAM, etc.), usa cordon y drain para sacarlo de rotacion de forma segura.
Cordon
Marca el nodo como no-programable. Los pods existentes siguen corriendo pero no se programan pods nuevos:
kubectl cordon agent-1
# Verificar (STATUS muestra SchedulingDisabled)
kubectl get nodes
Drain
Desaloja todos los pods del nodo de forma controlada. Kubernetes los reprograma en otros nodos:
kubectl drain agent-1 \
--ignore-daemonsets \
--delete-emptydir-data
Los flags comunes:
--ignore-daemonsets: ignora los DaemonSets (no se pueden mover)--delete-emptydir-data: acepta perder datos de volumenes emptyDir--grace-period=60: tiempo de gracia para terminar pods
Volver a poner el nodo en rotacion
Despues del mantenimiento:
kubectl uncordon agent-1
Ejemplo: Cluster de 3 Nodos
Supongamos que tienes 3 nodos con diferentes capacidades:
# Etiquetar nodos segun su rol
kubectl label node server-1 rol=infra
kubectl label node agent-1 rol=app
kubectl label node agent-2 rol=app
# Taint al server para que solo corra infra
kubectl taint nodes server-1 rol=infra:PreferNoSchedule
Deployment que corre solo en nodos de aplicacion:
apiVersion: apps/v1
kind: Deployment
metadata:
name: mi-api
spec:
replicas: 4
selector:
matchLabels:
app: mi-api
template:
metadata:
labels:
app: mi-api
spec:
nodeSelector:
rol: app
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: mi-api
containers:
- name: api
image: mi-api:latest
resources:
requests:
cpu: 100m
memory: 128Mi
El topologySpreadConstraints distribuye las 4 replicas equitativamente entre los nodos disponibles (2 en cada agent).
Verifica la distribucion:
kubectl get pods -o wide
La columna NODE muestra en que nodo esta cada pod.
Resumen
Un cluster multi-nodo te da redundancia y capacidad de escalar. Usa labels para organizar nodos, taints para restringir acceso, affinity para reglas de programacion avanzadas y drain para mantenimiento seguro. La clave es disenar una estrategia de distribucion que se ajuste a las necesidades de tus workloads.
Siguiente: Capitulo 17: Alta Disponibilidad —>