Capitulo 16: Cluster Multi-Nodo

Por: Artiko
k3skubernetesclustermulti-nodoescalamiento

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:

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    │
                 │ 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

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:

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:

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 —>