# ADR 0001 — Por qué k3d (y no k3s directo, minikube, o un cluster cloud) **Estado:** aceptada **Fecha:** 2026-08 (retroactiva — decisión tomada al arrancar el lab, documentada en Fase 2 del portal) ## Contexto El lab corre sobre un NAS ZimaOS doméstico, sin presupuesto para un cluster gestionado y con recursos modestos y compartidos con otras apps del NAS (Gitea, Nginx Proxy Manager, este mismo portal). El propósito del lab es doble: servir de portafolio técnico real y de material de estudio para el hijo del usuario (7mo semestre de Ingeniería de Sistemas) — ver [guía del estudiante](../guia-estudiante/README.md). Para que ambos objetivos tengan sentido, el cluster necesitaba comportarse como un Kubernetes real y multi-nodo, no como una caja de arena de un solo proceso: patrones como afinidad de pods, StatefulSets con almacenamiento persistente por nodo, y tráfico cross-node debían poder reproducirse y depurarse de verdad, no simularse. También pesó la restricción del propio sistema operativo: `/` en ZimaOS es un `squashfs` de solo lectura y `/usr` es un overlay igualmente inmutable — instalar un binario nativo como `k3s` que espera escribir en `/usr/local/bin`, `/etc/rancher`, etc. de forma persistente no encaja bien con ese filesystem sin trabajo extra de por medio. ## Opciones consideradas | Opción | A favor | En contra | |---|---|---| | **k3d** | Multi-nodo real corriendo como contenedores Docker (server + agent), se crea/destruye en segundos, no toca el filesystem inmutable de ZimaOS más allá de `/DATA` | Al ser Docker-in-Docker, hereda las capas de red de Docker — un blackhole de MTU/PMTUD real apareció por esto (ver Consecuencias) | | k3s directo (sin Docker) | Sin la capa extra de red de Docker-in-Docker, más cercano a un nodo "real" | Necesita instalar servicios systemd y escribir en rutas de sistema (`/usr/local/bin`, `/etc/rancher`) que en ZimaOS son de solo lectura o requieren workarounds — solo `/DATA` y `/etc` quedan escribibles | | minikube | Instalación simple, muy documentado, ideal para aprender lo básico | Single-node por defecto — no permite reproducir tráfico cross-node, afinidad de pods, ni el tipo de incidentes de infraestructura real que este lab busca documentar como aprendizaje | | Cluster gestionado (cloud) | Cero mantenimiento de infraestructura, SLA real | Costo recurrente que este lab no tiene presupuestado; además reduce el valor de aprendizaje — gran parte de lo documentado en `playbooks/` (MTU, DNS, límites de recursos) es justamente lo que un proveedor gestionado abstrae | ## Decisión k3d, multi-nodo (hoy: 1 server + 1 agent, `k3d-lab-cluster-server-0` / `k3d-lab-cluster-agent-0`), corriendo como contenedores Docker sobre el propio NAS. ## Consecuencias - **Se ganó** un cluster real y gratuito, reproducible con un solo script (`scripts/deploy-lab.sh`), y suficientemente parecido a un Kubernetes de producción como para que los incidentes documentados en `playbooks/` sean transferibles a un entorno cloud real. - **Se pagó** con un blackhole de red cross-node real: cualquier pod agendado en un nodo distinto al de `commerce-postgres-0` (StatefulSet, fijo a un nodo) fallaba de forma consistente al hablar con Postgres — diagnosticado hasta el bit exacto (payload interno 1420 bytes OK, 1450 bytes blackhole total, sin ICMP "frag needed") y resuelto ajustando el MTU real de la interfaz `flannel.1` a 1400 en cada nodo. Ver [known-issues.md](https://gitea.cruzcloud.net/devops/apps-registry/src/branch/main/docs/known-issues.md) y el [playbook del crashloop de Medusa](../playbooks/incidente-crashloop-medusa.md) para el diagnóstico completo. El fix no persiste solo — está automatizado en `scripts/deploy-lab.sh` (función `fix_flannel_mtu`), se reaplica cada vez que el cluster arranca o se recrea. - **Deuda aceptada a propósito**: el `podAffinity` que fuerza a `medusa-deploy` a compartir nodo con Postgres se dejó como red de contención extra después del fix de fondo — no es estrictamente necesario, pero es barato mantenerlo. - **Para revertir esta decisión** haría falta migrar a un cluster gestionado o a `k3s` nativo, lo que implicaría asumir el costo recurrente (cloud) o resolver las restricciones de filesystem inmutable de ZimaOS (k3s nativo) — ninguna de las dos se justifica hoy con el tamaño real del lab.