Ottimizzazione dei Costi Cloud: Smetti di Pagare Troppo per il Tuo MVP
La maggior parte delle startup spreca il 40-60% del proprio budget cloud. Ecco una guida pratica per dimensionare correttamente la tua infrastruttura senza sacrificare l'affidabilità.

L'ultimo trimestre ho esaminato la fattura AWS di una startup e ho scoperto che spendevano 2.800 $/mese per un'infrastruttura che avrebbe potuto funzionare comodamente per 900 $. Avevano un'istanza t3.2xlarge che eseguiva un'API Node.js con un picco di utilizzo della CPU del 12%. Tre Elastic IP inutilizzati inattivi a 3,65 $/mese ciascuno. Un deployment RDS Multi-AZ per un database con 200 righe. Un NAT gateway che instradava traffico che avrebbe potuto passare attraverso un endpoint VPC gratuitamente. Nulla di tutto ciò era intenzionale o particolarmente negligente — era l'accumulo di decisioni del tipo "basta provisionare qualcosa che funzioni" prese durante uno sprint per rilasciare il prodotto.
Questa è la norma, non l'eccezione. La maggior parte delle startup in fase iniziale spreca il 40-60% della propria spesa cloud perché nessuno nel team ha il tempo o l'incentivo per ottimizzare i costi quando ci sono funzionalità da rilasciare. Il problema si aggrava: una volta che l'infrastruttura è stata provisionata e funziona, nessuno la tocca più.
Le Più Grandi Trappole di Costo Che Continuo a Vedere
Prima di immergerci nelle soluzioni, è utile capire dove vanno effettivamente i soldi. Queste sono le trappole che incontro più frequentemente quando esamino l'infrastruttura delle startup.
Istanze di Calcolo Sovra-Provisionate
Questa è la più grande fonte di spreco. I team scelgono una dimensione di istanza durante la configurazione iniziale — di solito basandosi su un post di blog o una mentalità "tanto per essere sicuri" — e non la rivedono mai più. Ho visto istanze m5.xlarge eseguire cron job che si attivano per 30 secondi ogni ora. L'istanza rimane inattiva per 59,5 minuti, bruciando 0,192 $/ora (140 $/mese) per non fare essenzialmente nulla.
La causa principale è psicologica: nessuno vuole essere la persona che ha sotto-provisionato il server e causato un'interruzione. Quindi tutti arrotondano per eccesso. Due volte.
# Check your EC2 instance CPU utilization over the past 2 weeks
aws cloudwatch get-metric-statistics \
--namespace AWS/EC2 \
--metric-name CPUUtilization \
--dimensions Name=InstanceId,Value=i-0abcdef1234567890 \
--start-time $(date -u -d '14 days ago' +%Y-%m-%dT%H:%M:%S) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
--period 3600 \
--statistics Average Maximum
Se l'utilizzo medio della CPU è inferiore al 20% e il picco è inferiore al 50%, sei quasi certamente sovra-provisionato. Riduci di una o due dimensioni l'istanza, monitora per una settimana e poi aggiusta.
Volumi e Snapshot EBS Dimenticati
Quando termini un'istanza EC2, i volumi EBS allegati non vengono eliminati automaticamente a meno che tu non l'abbia configurato al momento del lancio. Ciò significa che le istanze terminate lasciano dietro di sé volumi orfani che continuano a generare costi. Ho visto account con decine di volumi gp3 non collegati, ognuno dei quali costa 0,08 $/GB/mese, per un totale di centinaia di dollari per uno storage che nessuno sta utilizzando.
Gli snapshot sono ancora più insidiosi. Gli script di backup automatizzati creano snapshot giornalieri senza una policy di ciclo di vita, quindi si accumulano indefinitamente. Un volume da 500 GB di cui viene fatto uno snapshot ogni giorno per un anno genera 365 snapshot, e sebbene gli snapshot EBS siano incrementali, i costi si sommano a cifre considerevoli.
# Find all unattached EBS volumes
aws ec2 describe-volumes \
--filters Name=status,Values=available \
--query 'Volumes[*].{ID:VolumeId,Size:Size,Created:CreateTime}' \
--output table
# Find snapshots older than 90 days
aws ec2 describe-snapshots \
--owner-ids self \
--query 'Snapshots[?StartTime<=`2025-12-01`].{ID:SnapshotId,Size:VolumeSize,Date:StartTime}' \
--output table
NAT Gateway: L'Assassino Silenzioso del Budget
I NAT gateway costano 0,045 $/ora (32,40 $/mese) solo per esistere, più 0,045 $ per GB di dati elaborati. Per una startup che effettua frequenti chiamate API a servizi esterni da subnet private, i soli costi di elaborazione dati possono superare i 100 $/mese. Ho visto i costi del NAT gateway rappresentare il 15-20% della fattura AWS totale di una piccola startup.
La soluzione dipende dal tipo di traffico che passa attraverso il NAT:
- Traffico verso i servizi AWS (S3, DynamoDB, SQS): Utilizza VPC Gateway Endpoints (gratuiti per S3 e DynamoDB) o Interface Endpoints (7,20 $/mese ciascuno, ma comunque più economici del NAT per traffico ad alto volume).
- Traffico verso internet da funzioni Lambda: Valuta se queste funzioni debbano effettivamente trovarsi in una VPC. Molte funzioni Lambda vengono collocate in una VPC "per sicurezza" quando non accedono a nessuna risorsa VPC.
- Traffico in uscita a basso volume: Un'istanza NAT su un t4g.nano (3,02 $/mese) gestisce un traffico modesto a una frazione del costo del NAT gateway.
Costi di Trasferimento Dati
AWS addebita 0,09 $/GB per i dati che escono da una regione, e il traffico cross-AZ costa 0,01 $/GB in ogni direzione. Questi costi sono invisibili finché non lo diventano. Un'architettura a microservizi "chiacchierona" distribuita su tre zone di disponibilità, con servizi che si chiamano a vicenda centinaia di volte al secondo, può generare fatture di trasferimento dati sorprendenti.
La soluzione architetturale: co-locare i servizi che comunicano frequentemente nella stessa AZ per carichi di lavoro non critici, oppure utilizzare load balancer interni con affinità di AZ.
Dimensionamento Corretto (Right-Sizing): Un Approccio Sistematico
Il dimensionamento corretto non è un esercizio una tantum. È qualcosa che dovresti rivedere trimestralmente. Ecco il processo che seguo.
Fase 1: Raccogliere Dati di Utilizzo
AWS Compute Optimizer è gratuito e fornisce raccomandazioni per il dimensionamento corretto di EC2, EBS, Lambda ed ECS. Abilitalo e lascialo raccogliere almeno 14 giorni di dati prima di agire sulle sue raccomandazioni.
Per un'analisi più granulare, le metriche di CloudWatch sono la tua fonte di dati principale. Le metriche chiave da monitorare:
- EC2: CPUUtilization, NetworkIn/Out, MemoryUtilization (richiede l'agente CloudWatch)
- RDS: CPUUtilization, DatabaseConnections, FreeableMemory, ReadIOPS, WriteIOPS
- ElastiCache: CPUUtilization, CurrConnections, BytesUsedForCache
Fase 2: Categorizzare i Carichi di Lavoro
Non tutti i carichi di lavoro dovrebbero essere dimensionati allo stesso modo. Li categorizzo in tre gruppi:
Carichi di lavoro a stato stazionario (server API, database): Questi necessitano di capacità costante. Dimensiona correttamente trovando l'istanza più piccola che gestisce il carico di picco con un margine del 30%. Utilizza Reserved Instances o Savings Plans per la base.
Carichi di lavoro variabili (elaborazione batch, build server): Questi dovrebbero utilizzare Auto Scaling Groups con policy di scaling appropriate, o Spot Instances per job batch tolleranti ai guasti.
Carichi di lavoro periodici (cron job, report programmati): Questi non dovrebbero affatto essere eseguiti su istanze dedicate. Spostali su Lambda, Fargate Spot o Step Functions.
Fase 3: Agire in Modo Incrementale
Non dimensionare mai tutto in una volta. Riduci di una dimensione di istanza alla volta, monitora per una settimana, quindi decidi se procedere ulteriormente. Il costo di un breve periodo di sovra-provisioning è di gran lunga inferiore al costo di un'interruzione di produzione causata da un ridimensionamento aggressivo.
Reserved Instances vs Savings Plans vs Spot
È qui che avvengono i veri risparmi — dal 30 al 72% di sconto sui prezzi on-demand — ma i meccanismi di impegno sono abbastanza confusi da far sì che molte startup li evitino del tutto.
Reserved Instances (RIs)
Ti impegni per un tipo di istanza specifico in una regione specifica per 1 o 3 anni. In cambio, ottieni dal 30-40% di sconto (nessun pagamento anticipato, 1 anno) al 60% di sconto (tutto anticipato, 3 anni). L'inghippo: se devi cambiare tipo di istanza, le RI Standard non sono flessibili. Le RI Convertibili offrono maggiore flessibilità con uno sconto leggermente inferiore (circa il 45% per 3 anni con pagamento tutto anticipato).
Quando usare le RI: Database e altri carichi di lavoro in cui il tipo e la dimensione dell'istanza sono realmente stabili. Le RDS Reserved Instances valgono quasi sempre la pena — i database raramente cambiano dimensione.
Savings Plans
I Savings Plans sono l'alternativa moderna alle RI per il calcolo. Ti impegni per un importo in dollari di calcolo all'ora (ad esempio, 0,10 $/ora) per 1 o 3 anni. L'impegno si applica automaticamente all'utilizzo di EC2, Fargate e Lambda, ed è flessibile tra famiglie di istanze, dimensioni, sistemi operativi e regioni.
Quando usare i Savings Plans: Quasi sempre preferibili alle RI EC2 per i carichi di lavoro di calcolo. I Compute Savings Plans offrono il miglior rapporto flessibilità-sconto. Inizia con un impegno che copra la tua spesa minima di base.
# Example: Calculating Savings Plan commitment
# Current on-demand spend: $500/month on EC2
# Minimum baseline (never drops below): $350/month
# Recommended Savings Plan commitment: $350/month = ~$0.48/hour
# Expected savings: ~30% on the committed amount = ~$105/month
# Remaining $150/month stays on-demand for flexibility
Spot Instances
Le Spot Instances offrono sconti del 60-90% ma possono essere interrotte con un preavviso di 2 minuti. Sono ideali per:
- Agenti di build CI/CD (usa Spot Fleet con più tipi di istanza)
- Job di elaborazione batch che possono fare checkpoint e riprendere
- Ambienti di sviluppo e staging
- Test di carico
Non sono adatte per server API di produzione, database o qualsiasi cosa che non possa gestire terminazioni improvvise.
# Example: GitHub Actions self-hosted runner on Spot
# This saves roughly 70% compared to GitHub-hosted runners
# for compute-heavy builds
Resources:
SpotFleet:
Type: AWS::EC2::SpotFleet
Properties:
SpotFleetRequestConfigData:
IamFleetRole: !GetAtt SpotFleetRole.Arn
TargetCapacity: 2
AllocationStrategy: lowestPrice
LaunchSpecifications:
- InstanceType: c5.xlarge
SpotPrice: "0.06"
- InstanceType: c5a.xlarge
SpotPrice: "0.06"
- InstanceType: c6i.xlarge
SpotPrice: "0.06"
Modelli di Costo Serverless: Non Sempre Più Economici
Esiste un mito persistente secondo cui il serverless è sempre più economico per le startup. Spesso è più economico a bassa scala, ma l'economia cambia man mano che il traffico cresce.
La Realtà dei Prezzi Lambda
Lambda addebita per richiesta (0,20 $ per milione) e per GB-secondo di calcolo (0,0000166667 $). Per un tipico endpoint API che viene eseguito per 200 ms con 256 MB di memoria:
- 1.000 richieste/giorno: ~$0,03/mese. Praticamente gratuito.
- 100.000 richieste/giorno: ~$3,00/mese. Ancora molto economico.
- 1.000.000 richieste/giorno: ~$30/mese. Inizia a confrontarsi con una piccola istanza EC2.
- 10.000.000 richieste/giorno: ~$300/mese. Un t3.medium (30 $/mese) con una cache adeguata gestisce facilmente questo carico.
Il punto di pareggio dipende fortemente dalla durata dell'esecuzione e dall'allocazione della memoria, ma per la maggior parte dei carichi di lavoro API, Lambda smette di essere conveniente tra 1 e 5 milioni di richieste al giorno. Al di sotto di tale soglia, è quasi sempre l'opzione più economica.
I Costi di API Gateway si Sommano
Le persone dimenticano che le funzioni Lambda dietro API Gateway comportano costi aggiuntivi. API Gateway costa 3,50 $ per milione di richieste (REST API) o 1,00 $ per milione (HTTP API). Su larga scala, il costo di API Gateway supera il costo di Lambda. Se stai gestendo abbastanza traffico da preoccuparti dei costi di Lambda, dovresti usare Application Load Balancer (0,008 $ per LCU-ora) invece di API Gateway.
Fargate: La Via di Mezzo
AWS Fargate si colloca tra Lambda ed EC2 sia in termini di costi che di complessità operativa. Paghi per vCPU e memoria al secondo, senza gestione delle istanze. Per carichi di lavoro che devono essere eseguiti continuamente ma non vuoi gestire server, Fargate con i provider di capacità Spot offre un buon equilibrio.
Un task Fargate con 0,25 vCPU e 0,5 GB di memoria costa circa 9 $/mese se eseguito continuamente. Questo è competitivo con un t4g.nano e ottieni posizionamento automatico, controlli di integrità e scaling senza gestire l'host sottostante.
Monitoraggio e Avvisi sui Costi
Non puoi ottimizzare ciò che non misuri. Ecco lo stack di monitoraggio che imposto per ogni progetto.
AWS Cost Explorer
Abilita Cost Explorer e imposta un budget mensile con avvisi alle soglie del 50%, 80% e 100%. Questo è il minimo indispensabile. La vista "Costo per Servizio" di Cost Explorer mostra immediatamente dove stanno andando i soldi.
# Create a budget with email alerts
aws budgets create-budget \
--account-id 123456789012 \
--budget '{
"BudgetName": "Monthly-Total",
"BudgetLimit": {"Amount": "500", "Unit": "USD"},
"TimeUnit": "MONTHLY",
"BudgetType": "COST"
}' \
--notifications-with-subscribers '[{
"Notification": {
"NotificationType": "ACTUAL",
"ComparisonOperator": "GREATER_THAN",
"Threshold": 80,
"ThresholdType": "PERCENTAGE"
},
"Subscribers": [{
"SubscriptionType": "EMAIL",
"Address": "team@startup.com"
}]
}]'
Infracost per Infrastructure as Code
Se utilizzi Terraform, Infracost si integra nella tua pipeline CI e mostra le stime dei costi per ogni modifica dell'infrastruttura prima che venga applicata. Questo è trasformativo — sposta la consapevolezza dei costi da una sorpresa mensile a una conversazione sulla pull request.
# .github/workflows/infracost.yml
name: Infracost
on: pull_request
jobs:
infracost:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Infracost
uses: infracost/actions/setup@v3
with:
api-key: ${{ secrets.INFRACOST_API_KEY }}
- name: Generate cost estimate
run: |
infracost breakdown --path=. \
--format=json --out-file=/tmp/infracost.json
infracost comment github \
--path=/tmp/infracost.json \
--repo=$GITHUB_REPOSITORY \
--pull-request=${{ github.event.pull_request.number }} \
--github-token=${{ secrets.GITHUB_TOKEN }}
Rilevamento Anomalie di Costo
AWS Cost Anomaly Detection utilizza il machine learning per identificare modelli di spesa insoliti. È gratuito e invia avvisi quando la spesa devia dai modelli storici. Abilitalo per ogni servizio e configura le notifiche SNS su Slack.
Pattern Architetturali Che Fanno Risparmiare Denaro
Oltre al dimensionamento corretto delle singole risorse, alcune decisioni architetturali cambiano fondamentalmente la tua struttura dei costi.
Caching Aggressivo
Una distribuzione CloudFront davanti alla tua API per risposte cacheabili costa 0,085 $/10.000 richieste HTTPS e 0,085 $/GB di trasferimento — ma elimina quelle richieste dal raggiungere il tuo backend. Per API con molte letture (la maggior parte lo sono), un tasso di successo della cache del 90% significa che il tuo backend gestisce 10 volte meno traffico.
Ancora più semplice: una cache in memoria come Redis o semplicemente una cache LRU locale nella tua applicazione può eliminare query di database ridondanti. Ho visto i costi dei database diminuire del 60% dopo aver aggiunto una cache di 15 minuti sui 5 endpoint più frequentemente acceduti.
Usare S3 in Modo Intelligente
S3 ha diverse classi di storage, e usare quella giusta è importante:
| Storage Class | Cost/GB/month | Use Case |
|---|---|---|
| S3 Standard | $0.023 | Dati attivi, accesso frequente |
| S3 Infrequent Access | $0.0125 | Backup, log più vecchi di 30 giorni |
| S3 Glacier Instant | $0.004 | Archivi che necessitano di accesso immediato |
| S3 Glacier Deep Archive | $0.00099 | Archivi a lungo termine, accesso raro |
Configura le S3 Lifecycle Policies per transizionare automaticamente gli oggetti tra le classi di storage:
{
"Rules": [
{
"ID": "TransitionToIA",
"Status": "Enabled",
"Transitions": [
{
"Days": 30,
"StorageClass": "STANDARD_IA"
},
{
"Days": 90,
"StorageClass": "GLACIER_INSTANT_RETRIEVAL"
}
]
}
]
}
Servizi Gestiti vs Self-Hosted
Questo compromesso è sfumato. I servizi gestiti (RDS, ElastiCache, OpenSearch Service) costano di più per unità di calcolo rispetto all'auto-hosting su EC2, ma includono patching, backup, failover e monitoraggio. Per una startup senza una persona dedicata alle operazioni, il tempo di ingegneria risparmiato giustifica quasi sempre il costo aggiuntivo.
L'eccezione: i servizi gestiti ai livelli più alti. Un'istanza RDS db.r6g.2xlarge costa significativamente di più rispetto all'istanza EC2 equivalente che esegue PostgreSQL. Una volta che hai un team con capacità operative e stai spendendo oltre 1.000 $/mese per un singolo servizio gestito, vale la pena valutare l'auto-hosting.
Consolidare Dove Possibile
Eseguire istanze RDS separate per ambienti di staging, QA e sviluppo è costoso. Opzioni:
- Utilizza una singola istanza RDS con database separati per gli ambienti non di produzione.
- Utilizza Aurora Serverless v2 per dev/staging — si ridimensiona a zero quando inattivo.
- Esegui database di sviluppo su una singola istanza EC2 Spot con Docker.
Un Vero Playbook di Ottimizzazione dei Costi
Ecco il processo passo-passo che seguo quando intraprendo un progetto di ottimizzazione dei costi. Questo di solito consente di ottenere risparmi del 30-50% entro il primo mese.
Settimana 1: Audit
- Abilita AWS Cost Explorer se non è già attivo.
- Ottieni una ripartizione dei costi per servizio degli ultimi 3 mesi.
- Identifica i 5 servizi principali per spesa.
- Esegui AWS Compute Optimizer e Trusted Advisor.
- Elenca tutti i volumi EBS non collegati, gli Elastic IP inutilizzati e i load balancer inattivi.
Settimana 2: Guadagni Rapidi (Quick Wins)
- Elimina le risorse inutilizzate identificate nell'audit.
- Dimensiona correttamente le istanze più sovra-provisionate (riduci di 1 dimensione, monitora).
- Configura gli endpoint VPC per il traffico S3 e DynamoDB.
- Abilita le S3 Lifecycle Policies su tutti i bucket.
- Configura gli avvisi di budget.
Settimana 3: Impegni
- Analizza