Nodos
Seis equipos físicos en la LAN 192.0.2.0/24. Todos tienen Tailscale instalado como acceso de administración remota.
| Nodo | Rol | IP | CPU | RAM | Disco principal | Red del clúster |
|---|---|---|---|---|---|---|
master-1 |
master (etcd) | 192.0.2.112 | 8 × Intel i7-7700 | 30 GiB | SSD Samsung 860 EVO 1 TB | Cable enp4s0f0 1 Gb/s, IP fija en NetworkManager (desde el 2026-10-27; la WiFi wlp3s0 queda sin conectarse sola) |
master-2 |
master (etcd) + cargas | 192.0.2.139 | 4 × Intel N97 | 14 GiB | SSD 512 GB | cable enp1s0 |
master-3 |
master (etcd) + cargas | 192.0.2.129 | 4 × Intel N150 | 10 GiB | SSD 512 GB (gama baja) | cable enp2s0 |
worker-2 |
worker | 192.0.2.164 | 12 × AMD Ryzen 5 6600H | 13 GiB | NVMe Lexar NQ790 1 TB | cable enp3s0 |
worker-1 |
worker | 192.0.2.128 | 4 vCPU | 15 GiB | HDD mecánico Seagate 500 GB | cable (*) |
worker-3 |
worker (arm64) | 192.0.2.197 | Raspberry Pi 4 B | 4 GiB | microSD 128 GB + HDD USB 1 TB en /mnt/hdd |
cable eth0 |
(*) Sin acceso SSH desde el master-1. Datos tomados de Kubernetes, pendientes de verificar en el propio nodo.
Versiones: k3s v1.34.6+k3s1 y containerd 2.2.2 en todos los nodos. Sistema operativo: Ubuntu 26.04.1 LTS, salvo la Raspberry, que usa Debian 13 (trixie).
Masters (control-plane)
Los tres corren k3s server con etcd embebido (3 miembros, tolera la caída de 1).
Los flags están en ExecStart de /etc/systemd/system/k3s.service:
| Nodo | Flags |
|---|---|
master-1 |
--cluster-init --tls-san 192.0.2.250 --etcd-arg=max-request-bytes=52428800 --etcd-arg=quota-backend-bytes=2147483648 --disable=servicelb --node-ip=192.0.2.112 --flannel-iface=enp4s0f0 |
master-2 |
--server https://192.0.2.250:6443 --disable=servicelb --node-ip=192.0.2.139 --flannel-iface=enp1s0 |
master-3 |
--server https://192.0.2.250:6443 --disable=servicelb --node-ip=192.0.2.129 --flannel-iface=enp2s0 |
--cluster-initen master-1 es histórico: fue el primer nodo, al migrar de SQLite a etcd. Los otros dos se unieron a través de la VIP.- Los
--etcd-arghicieron falta para migrar unstate.dbgrande de SQLite a etcd (ver docs/incidentes.md). --disable=servicelb: losLoadBalancerlos sirve MetalLB, no Klipper.--node-ipy--flannel-ifaceexplícitos para que flannel no elija la VIP como IP del nodo.
API de Kubernetes en alta disponibilidad: VIP 192.0.2.250
Cada master tiene, además de k3s:
| Fichero en el nodo | En este repo | Función |
|---|---|---|
/etc/systemd/system/vip-dummy0.service |
masters/vip-dummy0.service | Crea la interfaz dummy0 antes de keepalived |
/etc/keepalived/keepalived.conf |
masters/keepalived.conf.example | VRRP: el master con más prioridad tiene la VIP |
/etc/haproxy/haproxy.cfg |
masters/haproxy-k3s.cfg | 192.0.2.250:6443 → los 3 apiservers en round-robin con health check |
/etc/sysctl.d/60-haproxy-nonlocal.conf |
masters/60-haproxy-nonlocal.conf | Deja a haproxy escuchar en la VIP aunque el nodo no la tenga |
| Nodo | keepalived state |
priority |
interface (VRRP) |
|---|---|---|---|
master-1 |
MASTER | 150 | enp4s0f0 (cable, desde el 2026-10-27) |
master-2 |
BACKUP | 140 | enp1s0 (cable, desde el 2026-10-27) |
master-3 |
BACKUP | 130 | enp2s0 (cable, desde el 2026-10-27) |
✅ La VIP tiene relevo desde el 2026-10-27. Del 2026-10-18 al 27, keepalived estuvo en FAULT en master-2 y master-3 porque anunciaba VRRP por la WiFi, desconectada desde que esos nodos se pasaron a cable: si caía master-1, la VIP desaparecía. Tras cambiar el cable entre el router y el switch (0 % de pérdida en 90 s, también desde master-1 por WiFi), se cambió interface al cable con scripts/keepalived_cable.sh. Ahora master-1 es MASTER y master-2 y master-3 están en BACKUP. El mismo día, master-1 también pasó a cable (scripts/master1_a_cable.sh): los 3 masters anuncian VRRP por cable. Procedimiento: docs/operacion.md.
Workers
Ejecutan k3s agent y se registraron contra la VIP (K3S_URL=https://192.0.2.250:6443, en /etc/systemd/system/k3s-agent.service.env). Una vez arrancados, el balanceador interno de k3s se conecta directamente a los tres masters, así que no dependen de la VIP para seguir funcionando.
| Nodo | Particularidades |
|---|---|
worker-2 |
El nodo más potente. Aquí está fijado MinIO (nodeSelector). |
worker-1 |
El HDD mecánico no aguanta I/O intensivo (réplicas de Longhorn, imágenes). Ha causado crash-loops por I/O. Evitar cargas pesadas. |
worker-3 |
Tiene el taint app=n8n:NoSchedule, que quedó de cuando n8n corría aquí. Hoy solo corre el node-exporter, así que el nodo está infrautilizado. |
Servicios del sistema fuera de Kubernetes
| Servicio | Dónde | Notas |
|---|---|---|
cloudflared (Cloudflare Tunnel) |
master-3 |
Túnel por token, --protocol http2 (QUIC se caía con la red inestable; ver incidentes). Publica *.example.com; las rutas se configuran en el panel de Cloudflare Zero Trust. Solo existe en un nodo. |
tailscaled |
todos | Acceso remoto de administración. master-2 y worker-2 además son subnet routers de 192.0.2.240/29 y 192.0.2.250/32 (/etc/sysctl.d/99-tailscale.conf con ip_forward=1). Ver docs/red.md. |
haproxy, keepalived |
masters | VIP de la API |
Añadir un nodo
# Fija SIEMPRE la versión del clúster: sin ella se instala la última "stable"
curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.34.6+k3s1 \
K3S_URL=https://192.0.2.250:6443 K3S_TOKEN=<token> sh -s - agent \
--node-ip=<ip-del-nodo> --flannel-iface=<interfaz-cableada>
El token está en /var/lib/rancher/k3s/server/node-token de cualquier master. Para añadir un master, lee primero el procedimiento de docs/operacion.md.