Problema

Muchas startups y equipos de DevOps empiezan su stack en un hyperscaler (Azure, AWS, GCP) porque el crédito inicial y la facilidad de aprovisionamiento son atractivos. Con el tiempo, la factura crece: nodos de Kubernetes, balanceadores, CDN, funciones serverless y bases de datos gestionadas. La arquitectura suele estar diseñada para evitar el lock‑in a nivel de API, pero el modelo de precios de los proveedores sigue siendo exponencial. El patrón recurrente es alto gasto operativo con poca diferenciación funcional. Cuando el presupuesto se vuelve crítico, el equipo necesita una alternativa que mantenga la disponibilidad y la capacidad de escalar, pero con un modelo de costos lineal y sin dependencias propietarias.

Causa

  1. Modelo de precios basado en consumo de recursos gestionados
    Los servicios como AKS, Azure Load Balancer o Azure Functions cobran por hora, por request o por GB almacenado. Cada capa adicional (monitoring, logging, autoscaling) añade cargos ocultos.

  2. Vendor lock‑in implícito
    Aunque la aplicación use solo Kubernetes, la infraestructura de red, DNS y almacenamiento está atada a APIs propietarias. Cambiar de proveedor implica re‑escribir pipelines y scripts.

  3. Escalado automático sin control de límites
    Los clusters gestionados escalan sin intervención humana, lo que puede disparar la facturación si la carga inesperada no se controla.

  4. Falta de visibilidad granular de costos
    Las facturas consolidadas ocultan el consumo real de cada componente, dificultando la identificación de cuellos de botella financieros.

Solución

Una estrategia genérica para reducir costos sin sacrificar fiabilidad consta de tres pilares:

1. Re‑evaluar la arquitectura y separar “capa de datos” de “capa de ejecución”

  • Capa de ejecución: workloads sin estado (APIs, microservicios, jobs). Se pueden ejecutar en clusters ligeros como k3s sobre servidores bare‑metal o VPS de bajo coste.
  • Capa de datos: bases de datos que requieren alta disponibilidad y replicación. Mantenerlas en servicios gestionados (por ejemplo, Azure PostgreSQL) solo si el SLA justifica el gasto; de lo contrario, considerar alternativas self‑hosted con Patroni o Galera.

2. Migrar a un proveedor de bare‑metal o VPS de bajo coste (p.ej. Hetzner)

  1. Provisionar servidores: elige servidores con suficiente RAM/CPU para el total de pods previstos. Un nodo de 64 GB RAM puede reemplazar varios nodos pequeños de Azure.
  2. Instalar k3s: es rápido, consume pocos recursos y soporta Helm, CRDs y addons comunes.
  3. Externalizar servicios de red y CDN: Cloudflare ofrece DNS, CDN y Workers a precios predecibles. R2 reemplaza Azure Blob Storage con una API S3‑compatible.

3. Automatizar despliegues con CI/CD independiente del proveedor

  • GitHub Actions o GitLab CI pueden ejecutar pipelines que construyan imágenes, las publiquen en Docker Hub o GitHub Packages y desplieguen a k3s vía kubectl o helm.
  • Mantener los manifiestos de Kubernetes en Git (GitOps) permite revertir cambios sin tocar la infraestructura subyacente.

Paso a paso resumido

  1. Inventario de recursos
    Exporta la lista de recursos de Azure (az resource list --output json) y clasifícalos por tipo y coste mensual.

  2. Mapeo a equivalentes

    • AKS → k3s en Hetzner
    • Azure Load Balancer → MetalLB + Cloudflare DNS
    • Azure CDN → Cloudflare CDN
    • Azure Functions → Cloudflare Workers o scripts en GitHub Actions
  3. Crear playbooks de Ansible para aprovisionar servidores Hetzner, instalar k3s y configurar MetalLB. Un ejemplo mínimo está al final.

  4. Actualizar pipelines: reemplaza los pasos que usan az por hcloud (CLI de Hetzner) y kubectl contra el nuevo cluster.

  5. Validar datos: migra bases de datos con pg_dump/pg_restore o replicación en tiempo real.

  6. Desactivar recursos en Azure: una vez verificado el tráfico, elimina los recursos para evitar cargos residuales.

Cuándo aplicar esta solución

  • Facturación > $5 000/mes en un hyperscaler sin un ROI claro de los servicios gestionados.
  • Arquitectura basada en contenedores y sin dependencias exclusivas de APIs propietarias.
  • Equipo con experiencia en Linux, Ansible/Terraform y Kubernetes que pueda asumir la operación de servidores bare‑metal.
  • Necesidad de control granular de costos (por nodo, por GB, por request).

No aplicar si:

  • El SLA de los servicios gestionados es crítico (p.ej., cumplimiento regulatorio que exige certificaciones específicas).
  • El equipo no tiene capacidad para monitorizar y parchear infraestructuras propias.
  • La carga es altamente variable y requiere escalado automático instantáneo que solo un hyperscaler garantiza.

Código

# 1. Crear servidor Hetzner (requiere hcloud CLI y token configurado)
hcloud server create \
  --name k3s-node-01 \
  --type cx41 \
  --image ubuntu-22.04 \
  --ssh-key my-key \
  --location nbg1

# 2. Instalar k3s (ejecutado vía Ansible o manualmente)
curl -sfL https://get.k3s.io | sh -s - --disable-agent

# 3. Instalar MetalLB en modo layer‑2 (solo necesita una IP del rango de la red)
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.10/config/manifests/metallb-native.yaml
cat <<EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: hetzner-pool
  namespace: metallb-system
spec:
  addresses:
  - 185.65.134.100-185.65.134.110
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: hetzner-adv
  namespace: metallb-system
EOF

Verificación

  1. Comprobar que los nodos aparecen en kubectl get nodes y que el estado es Ready.
  2. Desplegar un pod de prueba (nginx) y exponerlo con un Service type: LoadBalancer. Verifica que la IP asignada pertenece al rango de MetalLB.
  3. Ejecutar un request a través de Cloudflare y medir latencia; debe ser comparable o mejor que la anterior.
  4. Revisar facturación: en el portal de Hetzner, confirma que el coste mensual está dentro del presupuesto estimado (p.ej., < $350).
  5. Simular caída de un nodo: apaga k3s-node-01 y verifica que los pods se re‑programan en los nodos restantes sin interrupción perceptible.

Notas adicionales

  • Backup de etcd: aunque k3s usa SQLite por defecto, para entornos productivos habilita un backend externo (MySQL o PostgreSQL) y programa backups diarios.
  • Monitoreo ligero: Prometheus + Grafana pueden ejecutarse como pods en el mismo cluster; evita servicios gestionados si el coste es un factor.
  • Seguridad de red: Hetzner no ofrece firewall por nodo gratuito; usa iptables o nftables y habilita el firewall de Cloudflare para el tráfico externo.
  • Escalado manual: define un script que añada nodos con hcloud server create y los una al cluster con k3s agent join. Automatízalo con GitHub Actions para que el proceso sea reproducible.
  • Licencias de software: al migrar fuera de Azure, revisa que no dependas de licencias vinculadas al proveedor (p.ej., Windows Server, SQL Server).

Con una planificación estructurada y una automatización mínima, la migración a un stack basado en Hetzner + Cloudflare permite reducir la factura a una fracción del coste original, manteniendo la flexibilidad y el control que los equipos de DevOps necesitan para iterar rápidamente.