Infraestructura¶
KanjiIQ se ejecuta en un clúster de Kubernetes autoalojado en Hetzner, usando Traefik para ingress y cert-manager para TLS automático.
Alojamiento: Servidor dedicado Hetzner¶
Todo el entorno de producción se ejecuta en un único servidor dedicado de Hetzner:
- Distribución de Kubernetes: k3s (Kubernetes ligero, binario único)
- SO: Linux
- Red: IPv4 pública con Cloudflare DNS
¿Por qué Hetzner?¶
- Precios mensuales predecibles (sin cargos por solicitud o por hora)
- Centros de datos en Europa (compatible con GDPR)
- Excelente relación precio-rendimiento
- Acceso root completo para la instalación de k3s
Kubernetes: k3s¶
k3s es una distribución de Kubernetes ligera y certificada por CNCF que incluye:
- Runtime de contenedores: containerd
- Controlador de ingress: Traefik (preinstalado)
- Balanceador de carga de servicios: Klipper
- Almacenamiento: Local path provisioner
- DNS: CoreDNS
k3s ejecuta Kubernetes con un solo binario (~100MB) en lugar de la configuración multi-componente de kubeadm. Es totalmente compatible con las APIs estándar de Kubernetes — todos los comandos de kubectl y los manifiestos funcionan de forma idéntica.
Ingress: Traefik¶
Traefik sirve como el controlador de ingress del clúster, gestionando:
- Terminación TLS: HTTPS automático para todos los dominios
- Enrutamiento: Enrutamiento basado en host hacia servicios (kanjiiq.com -> frontend, api.kanjiiq.com -> backend)
- Limitación de velocidad: Throttling de solicitudes por IP mediante CRD middlewares
- Cabeceras de seguridad: HSTS, X-Frame-Options, CSP mediante cadena de middleware
Configuración de middleware¶
# Public traffic: rate limit + security headers
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: public-security-chain
spec:
chain:
middlewares:
- name: rate-limit # 100 req/min, burst 50
- name: security-headers # HSTS, X-Frame-Options, etc.
# Admin traffic: stricter rate limit + auth
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: admin-security-chain
spec:
chain:
middlewares:
- name: api-rate-limit # 50 req/min, burst 25
- name: security-headers
- name: admin-auth
TLS: cert-manager + Let's Encrypt¶
Gestión automática de certificados TLS:
graph LR
I[Ingress with<br/>cert-manager annotation] --> CM[cert-manager]
CM --> LE[Let's Encrypt<br/>ACME challenge]
LE --> C[TLS Certificate]
C --> S[Kubernetes Secret]
S --> T[Traefik uses cert<br/>for HTTPS]
- ClusterIssuer:
letsencrypt-prod(autoridad de certificación a nivel de clúster) - Tipo de desafío: HTTP-01 vía Traefik
- Renovación: Automática antes del vencimiento
- Almacenamiento: Certificados almacenados como Kubernetes Secrets
Los recursos Ingress solicitan certificados con una sola anotación:
DNS: Cloudflare¶
El DNS del dominio se gestiona a través de Cloudflare:
- Registros A: Apuntan a la IP del servidor Hetzner
- Proxied: Capa opcional de CDN/WAF de Cloudflare
- Cabecera CF-IPCountry: Utilizada por el backend para geolocalización sin bases de datos de IP
Registro de contenedores: Forgejo¶
Las imágenes Docker se almacenan en el Forgejo Container Registry en <registry>:
- Co-ubicado con el código fuente (plataforma única)
- Secretos de pull de imágenes configurados en Kubernetes (
forgejo-registry) - Etiquetas:
:latest+:COMMIT_SHApara cada compilación - Sin dependencias de registros externos (Docker Hub, GHCR, etc.)
Asignación de recursos¶
| Componente | CPU solicitada | Límite CPU | Memoria solicitada | Límite memoria |
|---|---|---|---|---|
| Backend | 250m | 500m | 256Mi | 512Mi |
| Frontend | 100m | 200m | 128Mi | 256Mi |
| PostgreSQL | 250m | 500m | 256Mi | 512Mi |
| Docs | 10m | 100m | 32Mi | 64Mi |