Un SaaS de salud llegó a nosotros con un problema simple: su factura AWS había crecido de $12K/mes a $38K/mes en 18 meses, pero su base de usuarios solo se había duplicado. Algo estaba escalando de forma lineal cuando tendría que ser sublineal.
Su VP de Ingeniería fue directo: "Tenemos 50.000 usuarios y gastamos $38K/mes. Nuestro competidor tiene 200.000 usuarios y gasta menos que nosotros. ¿Qué estamos haciendo mal?"
Después de 2 semanas de auditoría y 6 semanas de implementación, bajamos su factura a $18.200/mes — una reducción del 52%, ahorrando $237.600/año. Acá está cada cosa que cambiamos.
La Auditoría
Arrancamos categorizando el gasto por servicio AWS:
| Servicio | Costo Mensual | % del Total |
|---|---|---|
| EC2 (nodos EKS) | $16.400 | 43% |
| RDS (PostgreSQL) | $7.200 | 19% |
| ElastiCache (Redis) | $3.100 | 8% |
| S3 + CloudFront | $2.800 | 7% |
| NAT Gateway | $2.600 | 7% |
| Data Transfer | $2.400 | 6% |
| Volúmenes EBS | $1.800 | 5% |
| Otros | $1.700 | 5% |
| Total | $38.000 | 100% |
Cada línea tenía potencial de optimización. Vamos una por una.
1. EC2/EKS: Right-Size + Spot + Karpenter ($16.400 → $6.800)
Este fue el mayor win. El cluster EKS corría en instancias m5.2xlarge On-Demand porque "eso es lo que sugería la guía Quick Start de AWS."
Cambios realizados:
- Reemplazamos Cluster Autoscaler con Karpenter
- Agregamos 15 tipos de instancia a la lista permitida
- Movimos el 75% de los workloads a instancias Spot
- Right-sizing de todos los pods en base a 2 semanas de datos de VPA
- Agregamos HPA a todos los servicios stateless
Escribimos sobre el setup de Karpenter en detalle en nuestro post de Karpenter + Spot + Scale-to-Zero.
Ahorro: $9.600/mes (58%)
2. RDS: Reserved Instances + Read Replicas ($7.200 → $3.600)
Corrían una instancia PostgreSQL RDS db.r6g.2xlarge — On-Demand, Multi-AZ. La base de datos estaba al 15% de utilización de CPU en promedio.
Cambios realizados:
- Bajamos a
db.r6g.xlarge(la CPU solo llegaba al 40% durante el pico con la instancia más chica) - Compramos una Reserved Instance 1 año All Upfront (42% de descuento)
- Agregamos una read replica para las queries de analytics que martillaban el primario
- Movimos los batch jobs nocturnos para que golpearan la replica en vez del primario
-- Antes: queries de analytics en el primario
SELECT date_trunc('day', created_at), count(*)
FROM patient_records
WHERE created_at > now() - interval '90 days'
GROUP BY 1;
-- Después: misma query ruteada a la read replica via connection string
-- analytics_db_url = postgres://replica-endpoint:5432/healthdb
Ahorro: $3.600/mes (50%)
3. ElastiCache: Right-Size + Reserved ($3.100 → $1.400)
Corrían cache.r6g.xlarge con 3% de utilización de memoria. Cacheaban session data para 50K usuarios — eso cabe en un cache.r6g.large con margen de sobra.
Cambios realizados:
- Bajamos a
cache.r6g.large - Compramos Reserved Instance por 1 año
- Implementamos TTL en todas las cache keys (tenían 2M de keys sin expiración)
Ahorro: $1.700/mes (55%)
4. NAT Gateway: El Asesino Silencioso del Presupuesto ($2.600 → $800)
Este sorprendió a todos. NAT Gateway cobra $0.045/GB por data processing — y los pods estaban pulleando imágenes Docker a través de NAT en cada deploy.
Cambios realizados:
- Configuramos VPC endpoints para ECR (se acabó el NAT para los image pulls)
- Agregamos S3 VPC endpoint (los logs y backups pasaban por NAT)
- Configuramos VPC endpoints para STS y CloudWatch
- Movimos el tráfico no esencial a instancias con IPs públicas
# VPC Endpoints que agregamos
aws ec2 create-vpc-endpoint \
--vpc-id vpc-xxx \
--service-name com.amazonaws.us-east-1.ecr.api \
--vpc-endpoint-type Interface
aws ec2 create-vpc-endpoint \
--vpc-id vpc-xxx \
--service-name com.amazonaws.us-east-1.s3 \
--vpc-endpoint-type Gateway
Ahorro: $1.800/mes (69%)
Los costos de NAT Gateway son uno de los ítems más ignorados en las facturas AWS. Cada empresa que auditamos está pagando de más por NAT.
5. S3 + CloudFront: Lifecycle Policies + Compresión ($2.800 → $1.600)
Estaban guardando cada versión de cada archivo para siempre. Los uploads de documentos médicos de hace 3 años seguían en S3 Standard.
Cambios realizados:
- S3 Intelligent-Tiering para todos los buckets (mueve los datos fríos automáticamente a tiers más baratos)
- Lifecycle policy: pasar a Glacier después de 1 año para archivos de compliance
- Habilitamos compresión en CloudFront (Brotli) — redujo el bandwidth un 40%
- Configuramos cache headers correctos — el hit ratio del CDN pasó de 60% a 94%
{
"Rules": [
{
"ID": "ArchiveOldDocuments",
"Status": "Enabled",
"Transitions": [
{
"Days": 90,
"StorageClass": "STANDARD_IA"
},
{
"Days": 365,
"StorageClass": "GLACIER"
}
]
}
]
}
Ahorro: $1.200/mes (43%)
6. Data Transfer: Mantener el Tráfico Dentro del VPC ($2.400 → $1.200)
Los cargos de cross-AZ data transfer los estaban comiendo vivos. Servicios en us-east-1a hablaban con servicios en us-east-1c, pagando $0.01/GB en cada dirección.
Cambios realizados:
- Configuramos topology-aware routing en Kubernetes (preferir misma AZ)
- Movimos los servicios que se hablan mucho a la misma AZ
- Comprimimos los payloads inter-servicios (gRPC con protobuf en vez de JSON)
# Topology-aware routing
apiVersion: v1
kind: Service
metadata:
name: user-service
annotations:
service.kubernetes.io/topology-mode: Auto
Ahorro: $1.200/mes (50%)
7. Volúmenes EBS: Eliminar Huérfanos + Cambiar Tipos ($1.800 → $800)
22 volúmenes EBS sin adjuntar, haciendo nada. PersistentVolumes de pods eliminados que nadie limpió. Clásico.
Cambios realizados:
- Eliminamos 22 volúmenes EBS huérfanos (ahorro inmediato de $400/mes)
- Cambiamos volúmenes GP2 a GP3 (20% más barato, mejor performance)
- Redujimos la frecuencia de snapshots de horaria a diaria para los volúmenes no críticos
# Encontrar volúmenes huérfanos
aws ec2 describe-volumes \
--filters Name=status,Values=available \
--query 'Volumes[*].{ID:VolumeId,Size:Size,Created:CreateTime}' \
--output table
Ahorro: $1.000/mes (56%)
El Resultado Final
| Servicio | Antes | Después | Ahorro | % |
|---|---|---|---|---|
| EC2/EKS | $16.400 | $6.800 | $9.600 | 58% |
| RDS | $7.200 | $3.600 | $3.600 | 50% |
| ElastiCache | $3.100 | $1.400 | $1.700 | 55% |
| NAT Gateway | $2.600 | $800 | $1.800 | 69% |
| S3/CloudFront | $2.800 | $1.600 | $1.200 | 43% |
| Data Transfer | $2.400 | $1.200 | $1.200 | 50% |
| EBS | $1.800 | $800 | $1.000 | 56% |
| Otros | $1.700 | $2.000 | -$300 | -18% |
| Total | $38.000 | $18.200 | $19.800 | 52% |
"Otros" subió levemente porque agregamos herramientas de monitoring (Kubecost, exporters custom) que tienen un pequeño costo de compute. Vale cada centavo.
Ahorro anual: $237.600
El proyecto completo — auditoría, implementación, testing, documentación — tomó 8 semanas y les costó una fracción del ahorro de un solo mes.
El Cambio Más Importante
Las optimizaciones técnicas fueron importantes, pero el cambio cultural importó más. Instalamos nuestro dashboard de FinOps el primer día del proyecto, para que el equipo pudiera ver los costos en tiempo real desde el arranque.
Para la semana 3, los ingenieros ya venían a nosotros con ideas de optimización que nosotros no habíamos visto. Un developer notó que su servicio hacía 10 veces más llamadas a la API de S3 de las necesarias por falta de una capa de cache. Otro encontró un cron job que levantaba una instancia grande 2 minutos cada hora.
Cuando hacés los costos visibles, los ingenieros optimizan naturalmente. Solo necesitan los datos.
Qué Haríamos Diferente
Arrancar con right-sizing antes de Spot. Hicimos Karpenter primero, pero si hubiéramos right-siziado los pods antes, Karpenter hubiera sido aún más eficiente desde el día uno. Los nodos se empaquetan mejor cuando los pods piden lo que realmente necesitan.
Instalar el dashboard de costos antes, no después. Armamos el dashboard de FinOps al comienzo del proyecto en este caso, pero en proyectos anteriores lo dejamos para el final. Es un error: sin visibilidad de costos en tiempo real, los ingenieros no tienen el feedback loop para optimizar durante la implementación. El dashboard debería ser lo primero que se instala, no lo último.
Auditar los snapshots de RDS desde el día uno. Nos tomó hasta la semana 4 notar que tenían snapshots manuales de RDS acumulándose desde 2022 — nadie los borraba nunca. No era una línea enorme, pero era dinero tirado. Los snapshots automatizados tienen políticas de retención; los manuales no expiran solos. Ahora lo chequeamos en la primera semana de toda auditoría.
¿Tu factura AWS crece más rápido que tu base de usuarios? Es normal — y tiene solución. Pedí una evaluación gratuita de infraestructura y te mostramos exactamente dónde está el desperdicio.