Zombie cloudové zdroje: Jak najít a eliminovat nečinné EBS, snapshoty a NAT Gateway v roce 2026
Zombie cloudové zdroje (nepřipojené EBS, staré snapshoty, idle NAT Gateway) tvoří 15 až 30 % útraty. Ukážeme detekci přes Trusted Advisor, Azure Advisor a GCP Recommender, hotové Boto3 skripty pro bezpečné mazání i case study s úsporou 23 800 USD/měsíc.
Zombie cloudové zdroje jsou aktivní, ale nepoužívané komponenty infrastruktury (typicky nepřipojené EBS svazky, staré snapshoty, nečinné NAT Gateway, nevázané Elastic IP a osiřelé Load Balancery), které dál generují faktury, přestože je nikdo nepoužívá. Ve firmách, kterým jsem pomáhal snížit náklady, tvořily průměrně 15 až 30 % celkové cloudové útraty. Odstranění zombie zdrojů je nejrychlejší cesta k okamžité úspoře: žádná refaktorizace, žádný přepis kódu, žádné vyjednávání s dodavatelem. Stačí je najít a smazat.
Nepřipojený EBS svazek typu gp3 velikosti 500 GB stojí v AWS us-east-1 přibližně 40 USD měsíčně a v pravidelně auditovaných účtech tvoří 5 až 12 % útraty za blokové úložiště.
Jedna nečinná NAT Gateway v AWS stojí 32,40 USD měsíčně za samotnou dostupnost, i když skrz ni neteče žádný provoz.
Nevázaná Elastic IP adresa je v AWS účtována 3,60 USD měsíčně. Velké účty jich mají desítky až stovky.
Nástroje AWS Trusted Advisor, Azure Advisor a GCP Recommender najdou 60 až 70 % zombie zdrojů zdarma, zbytek odhalí vlastní skripty nad CloudWatch/Cost Explorer daty.
Automatizovaný úklid pomocí Boto3, Azure CLI nebo gcloud lze provozovat v režimu "detekce dnes, mazání za 30 dní" a odstraní 90 % rizika smazání aktivně používaného zdroje.
Prevencí je povinné tagování na CI/CD úrovni s owner, ttl a environment. Bez toho se zombie zdroje vrátí do tří měsíců.
Co jsou zombie cloudové zdroje a proč se hromadí?
Zombie zdroj je infrastrukturní komponenta, která je alokovaná (a proto účtovaná), ale neposkytuje žádnou hodnotu. Žádný workload ji nečte ani nezapisuje. V praxi to jsou:
EBS svazek odpojený od EC2 instance, která byla terminována
Snapshot pocházející z AMI, které už neexistuje nebo bylo deprecated
NAT Gateway v subnetu, který nemá žádné běžící privátní instance
Elastic IP alokovaná, ale nepřiřazená k žádnému síťovému rozhraní
Load Balancer s 0 healthy targets déle než 30 dní
RDS instance ve stavu available, u které CloudWatch metrika DatabaseConnections zůstává 30 dní na nule
CloudWatch log group bez retention policy, který roste do desítek GB
Proč vznikají? Vidím tři opakující se příčiny. Za prvé, Terraform state drift. Někdo smaže EC2 instanci manuálně přes konzoli, Terraform o tom neví a EBS svazek zůstane osiřelý. Za druhé, experimentální práce vývojářů: proof-of-concept environment, který nikdo nezruší, protože "možná se ještě vrátíme". Za třetí, selhání blueprintů. CloudFormation nebo Terraform vytvoří stack, který spadne v polovině, ale některé zdroje už jsou vytvořené a nikdo je neuklidí. Bez pravidelného auditu se za rok nasčítají do významné částky.
Kolik peněz vás zombie zdroje reálně stojí?
Podle veřejně dostupných studií (Flexera 2026 State of the Cloud a interní data ze čtyř auditů, které jsem v posledních 18 měsících vedl) tvoří zombie zdroje mezi 12 a 32 % cloudového rozpočtu. Mediánová hodnota v mém vzorku byla 21 %. Konkrétní ceny za nejčastější zombie kategorie v AWS us-east-1 (červenec 2026):
Zdroj
Jednotková cena
Typický počet ve středně velkém účtu
Měsíční ztráta
Nepřipojený EBS gp3 (500 GB)
40,00 USD / měsíc
15
600 USD
Staré snapshoty (100 GB agregátně)
5,00 USD / měsíc
200
1 000 USD
Nečinná NAT Gateway
32,40 USD / měsíc
4
129,60 USD
Nevázaná Elastic IP
3,60 USD / měsíc
25
90,00 USD
Idle ALB (0 targets)
16,20 USD / měsíc
6
97,20 USD
Idle RDS db.t3.medium
50,00 USD / měsíc
3
150,00 USD
Nepoužívané EIP na Global Accelerator
18,00 USD / měsíc
2
36,00 USD
Celkem
2 102,80 USD / měsíc
To je 25 234 USD ročně u účtu, který si podle mě většina lidí představí jako "středně velký", tedy útrata 40 až 80 tisíc USD měsíčně. Pokud pracujete s multi-cloudem, čísla znásobte přibližně 1,4×, protože Azure a GCP mají obdobné zombie kategorie (unattached managed disks, idle Cloud NAT, nezrušené static IP). Honestně, když poprvé projdete Cost Explorer po roce provozu, ta čísla vás překvapí. Pokud vás zajímá širší téma závazkových slev a jak je zombie zdroje "žerou zbytečně", podívejte se na srovnání Reserved Instances vs Savings Plans vs CUD. Reserved Instance nasazená na terminovanou instanci je učebnicový příklad ztráty peněz.
8 nejčastějších typů zombie zdrojů, které vidím v každém auditu
1. Unattached EBS volumes
Zdaleka nejčastější kategorie. Vzniká pokaždé, když někdo terminuje EC2 instanci a její datový svazek má DeleteOnTermination = false. Původní záměr byl zachovat data pro pozdější migraci; realita je, že se na svazek zapomene. Nákladově dominuje gp3 (0,08 USD/GB/měsíc) a io2 (0,125 USD/GB/měsíc + IOPS). Detekce: filtr --filters Name=status,Values=available.
2. Orphaned EBS snapshots
Snapshot je "orphaned", když AMI, ze kterého vznikl, už neexistuje nebo bylo označeno jako deprecated. Účtování probíhá inkrementálně (platíte jen za unikátní bloky), ale u dlouho běžících účtů to jsou snadno terabajty. Nejhorší patternu se dopouštějí týmy, které nastaví denní snapshoty s Data Lifecycle Manager a zapomenou nastavit Retention count.
3. Idle NAT Gateway
NAT Gateway má fixní hodinovou cenu 0,045 USD/hodinu (v us-east-1) plus 0,045 USD za GB zpracovaných dat. Fixní část znamená 32,40 USD měsíčně bez ohledu na provoz. Vidím ji nasazenou v subnetech, kde už dávno neběží žádná privátní instance. Typicky pozůstatek stagingu, který byl vypnutý. Detekce: CloudWatch metrika BytesOutToDestination na nule po 30 dní. Tuhle konkrétní diagnostiku detailně probírám v článku o skrytých nákladech na síťový provoz.
4. Unassigned Elastic IPs
AWS vás účtuje za Elastic IP jen tehdy, když není asociovaná s běžící instancí. 0,005 USD/hodinu, tedy 3,60 USD měsíčně. Zdá se to málo, ale u účtu s desítkami sub-account (multi-account setup přes AWS Organizations) jich najdu klidně 100+.
5. Zombie Load Balancery
Application Load Balancer stojí 16,20 USD/měsíc jen za dostupnost + LCU. Když má 0 healthy targets déle než 30 dní, je to zombie. Nejčastější zdroj: staré target groups z blue/green deploymentu, na které nikdo nezrušil DNS záznam.
6. Idle RDS instance
RDS instance ve stavu available, u které je DatabaseConnections = 0 po 30+ dní. Typicky staging environment, který někdo vypnul jen na aplikační vrstvě.
7. Zapomenutá dev/test prostředí
Celý stack (EC2, RDS, ALB, EBS) vytvořený jako "test XY" před šesti měsíci. Nejlépe se detekuje tagem Environment=dev kombinovaným s LastActivityTimestamp starším než 60 dní.
8. CloudWatch log groups bez retence
Log group založený SDK/CloudFormation šablonou má výchozí retention never expire. Po roce běhu produkční aplikace vidím logy o velikosti 400 GB, které nikdo nikdy nečetl. Cena 0,03 USD/GB/měsíc znamená 144 USD ročně za jednu log group. Rychlá oprava: nastavit PutRetentionPolicy na 30 dní.
Jak najít zombie zdroje v AWS (Trusted Advisor + CLI)
Nejrychlejší cesta je AWS Trusted Advisor. V placených Support plánech (Business a výše) obsahuje kategorii Cost Optimization s kontrolami "Underutilized EBS Volumes", "Idle Load Balancers", "Unassociated Elastic IP Addresses" a "Underutilized RDS DB Instances". Bez placené podpory dostanete jen 6 základních kontrol. Klienti to většinou nevědí a platí za Basic Support.
Pro účty bez Business Support dělám detekci přes AWS CLI. Následující skript vypíše nepřipojené EBS svazky napříč všemi regiony a spočítá potenciální měsíční úsporu:
#!/bin/bash
# find-unattached-ebs.sh - detekce nepřipojených EBS svazků ve všech regionech
REGIONS=$(aws ec2 describe-regions --query 'Regions[].RegionName' --output text)
TOTAL_GB=0
TOTAL_COST=0
for REGION in $REGIONS; do
RESULT=$(aws ec2 describe-volumes \
--region "$REGION" \
--filters Name=status,Values=available \
--query 'Volumes[].[VolumeId,Size,VolumeType,CreateTime]' \
--output text)
if [ -n "$RESULT" ]; then
echo "=== Region: $REGION ==="
echo "$RESULT"
GB=$(echo "$RESULT" | awk '{sum+=$2} END {print sum+0}')
# gp3 cena: 0,08 USD/GB/měsíc
COST=$(echo "$GB * 0.08" | bc -l)
printf "Region total: %s GB, cca %.2f USD/měsíc\n\n" "$GB" "$COST"
TOTAL_GB=$(echo "$TOTAL_GB + $GB" | bc)
TOTAL_COST=$(echo "$TOTAL_COST + $COST" | bc)
fi
done
printf "\n===== CELKEM: %s GB, cca %.2f USD/měsíc =====\n" "$TOTAL_GB" "$TOTAL_COST"
Pro nečinné NAT Gateway používám CloudWatch dotaz. Následující one-liner najde všechny NAT Gateway s nulovým provozem za posledních 30 dní:
aws ec2 describe-nat-gateways \
--query 'NatGateways[?State==`available`].[NatGatewayId,VpcId]' \
--output text | while read NGW VPC; do
BYTES=$(aws cloudwatch get-metric-statistics \
--namespace AWS/NATGateway \
--metric-name BytesOutToDestination \
--start-time "$(date -u -v-30d '+%Y-%m-%dT%H:%M:%S')" \
--end-time "$(date -u '+%Y-%m-%dT%H:%M:%S')" \
--period 2592000 --statistics Sum \
--dimensions Name=NatGatewayId,Value="$NGW" \
--query 'Datapoints[0].Sum' --output text)
if [ "$BYTES" = "None" ] || [ "$BYTES" = "0.0" ]; then
echo "ZOMBIE: $NGW ve VPC $VPC (0 bytes za 30 dní, 32,40 USD/měsíc)"
fi
done
Jak najít zombie zdroje v Azure (Advisor + PowerShell)
V Azure je základní nástroj Azure Advisor, který je součástí každé subscription bez příplatku. V kategorii Cost najdete doporučení "Delete or reconfigure idle virtual network gateways", "Delete unassociated public IP addresses" a "Unattached disks should be deleted".
Pro programatickou detekci nepřipojených managed disků použijte tento PowerShell:
Pro Public IP addresses platí obdobný pattern: filtr IpConfiguration -eq $null najde všechny nepřiřazené. V Azure jsou účtované jen tehdy, když nejsou asociované s běžícím zdrojem (podobně jako Elastic IP v AWS). Cena standard tier: 3,65 USD měsíčně za adresu.
Jak najít zombie zdroje v GCP (Recommender + gcloud)
GCP Recommender API je Google ekvivalent Advisoru a je součástí Active Assist. Klíčové doporučovací služby pro zombie kategorii: google.compute.disk.IdleResourceRecommender (nepřipojené persistent disky), google.compute.address.IdleResourceRecommender (nevázané statické IP) a google.compute.image.IdleResourceRecommender (staré custom images).
# find-idle-disks-gcp.sh
PROJECT_ID="my-project"
ZONES=$(gcloud compute zones list --format="value(name)")
for ZONE in $ZONES; do
RECS=$(gcloud recommender recommendations list \
--project="$PROJECT_ID" \
--location="$ZONE" \
--recommender=google.compute.disk.IdleResourceRecommender \
--format="value(name,description,primaryImpact.costProjection.cost.units)")
if [ -n "$RECS" ]; then
echo "=== Zone: $ZONE ==="
echo "$RECS"
fi
done
Recommender vrací nejen seznam zdrojů, ale i odhad měsíční úspory v primaryImpact.costProjection. To je největší rozdíl oproti AWS: Google si detekci předžvýkal a zobrazí ji přímo v Recommendations Hub konzole. Nevýhodou je, že Recommender má latenci 24 až 48 hodin od změny stavu zdroje.
Automatizace úklidu pomocí Boto3 a Terraformu
Ruční mazání nefunguje ve firmách s desítkami účtů. V mém posledním projektu jsme nasadili Lambda function v každém AWS účtu, která běží denně a taguje kandidáty na smazání. Skutečné mazání provede druhá Lambda po 30 dnech quarantine, pokud se stav zdroje nezměnil.
Fáze 1, detekce a označení kandidátů (Python 3.12, Boto3):
import boto3
from datetime import datetime, timezone, timedelta
DRY_RUN = True # produkci nastavíme na False až po testech
QUARANTINE_TAG = "zombie-scheduled-delete"
def tag_unattached_volumes(region: str) -> list[str]:
ec2 = boto3.client("ec2", region_name=region)
tagged = []
delete_after = (datetime.now(timezone.utc) + timedelta(days=30)).strftime("%Y-%m-%d")
paginator = ec2.get_paginator("describe_volumes")
for page in paginator.paginate(Filters=[{"Name": "status", "Values": ["available"]}]):
for vol in page["Volumes"]:
existing = {t["Key"] for t in vol.get("Tags", [])}
if QUARANTINE_TAG in existing:
continue # už označený z předchozího běhu
print(f"Tagging {vol['VolumeId']} ({vol['Size']} GB) for deletion after {delete_after}")
if not DRY_RUN:
ec2.create_tags(
Resources=[vol["VolumeId"]],
Tags=[
{"Key": QUARANTINE_TAG, "Value": delete_after},
{"Key": "zombie-reason", "Value": "unattached-30d"},
],
)
tagged.append(vol["VolumeId"])
return tagged
def lambda_handler(event, context):
regions = [r["RegionName"] for r in boto3.client("ec2").describe_regions()["Regions"]]
all_tagged = []
for region in regions:
all_tagged.extend(tag_unattached_volumes(region))
return {"tagged_count": len(all_tagged), "volumes": all_tagged}
Fáze 2, mazání po uplynutí quarantine:
def delete_expired_zombies(region: str) -> int:
ec2 = boto3.client("ec2", region_name=region)
today = datetime.now(timezone.utc).date()
deleted = 0
volumes = ec2.describe_volumes(Filters=[
{"Name": "status", "Values": ["available"]},
{"Name": "tag-key", "Values": [QUARANTINE_TAG]},
])["Volumes"]
for vol in volumes:
tag_val = next(t["Value"] for t in vol["Tags"] if t["Key"] == QUARANTINE_TAG)
scheduled = datetime.strptime(tag_val, "%Y-%m-%d").date()
if scheduled <= today:
print(f"Deleting {vol['VolumeId']} (was scheduled {tag_val})")
if not DRY_RUN:
# bezpečnostní snapshot před smazáním
ec2.create_snapshot(VolumeId=vol["VolumeId"], Description="pre-zombie-delete")
ec2.delete_volume(VolumeId=vol["VolumeId"])
deleted += 1
return deleted
Terraform verze používá provider aws a modul, který automaticky nasadí obě Lambdy plus EventBridge scheduler:
Prevence: Jak zabránit tomu, aby zombie zdroje vznikly znovu
Detekce a mazání je jen hašení. Skutečný cíl je zombie zdroje vůbec nevytvářet. V každém FinOps auditu doporučuju tři vrstvy prevence, které pracují dohromady:
Povinné tagování na CI/CD úrovni: Terraform Sentinel nebo OPA Gatekeeper policy, která odmítne apply bez tagů owner, environment, ttl a cost-center. Tag ttl=2026-12-31 je magický. Automatizovaný proces každý týden zkontroluje, jestli TTL neexpirovala, a stack zruší.
Ephemeral environments defaultně: každý PR dostane vlastní krátkodobý stack, který se automaticky zruší při mergu nebo po 7 dnech nečinnosti. Zabíjí to největší zdroj zombie zdrojů, tedy "dočasné" testovací nasazení.
Weekly cost anomaly review: 30minutový meeting, kde tým prochází Cost Explorer / Azure Cost Management dashboard s filtrem Untagged Resources. Cokoli bez ownera se buď otaguje, nebo smaže do konce týdne.
Kombinace tří vrstev srazila v mém posledním projektu vznik nových zombie zdrojů na méně než 5 % předchozí úrovně. Detailní návod na nastavení cost policies napříč AWS/Azure/GCP najdete v kompletním průvodci FinOps v multi-cloud prostředí.
Případová studie: Jak jsme za jeden sprint uklidili 23 800 USD měsíční útraty
Loni v prosinci jsem dělal audit pro fintech s útratou 220 000 USD měsíčně, převážně AWS + malý GCP kus na BigQuery. Zadání znělo "najít quick wins do dvou týdnů". Postupovali jsme takto.
Týden 1, detekce. Nasadili jsme AWS Trusted Advisor (byl už zaplacený, jen ho nikdo nečetl) a doplnili vlastními CLI skripty pro NAT Gateway a CloudWatch log groups. Výsledek:
Týden 2, bezpečné mazání. Všechny svazky a snapshoty prošly 7denním quarantine s tagem zombie-review. Poslali jsme automatický e-mail vlastníkům podle owner tagu (kde existoval); 6 % zdrojů si někdo vyžádal zpět. Zbytek jsme smazali.
Výsledek: Měsíční úspora 23 807 USD, což je 10,8 % původního rozpočtu. Tři idle MSK clustery samy o sobě tvořily 75 % úspory a byly pozůstatkem interního workshopu z Q3. Nikdo si nevšiml, protože byly ve stavu "active" (Kafka nemá stav "idle"). Bez detekce přes CloudWatch metriky BytesInPerSec = 0 by tam běžely dál.
Investice do vlastní automatizace se vrátila za 4 dny. Trvalá roční úspora: 285 684 USD. Přidejte k tomu compliance benefit (méně dat = menší expozice při breach) a jde o jedno z nejlepších ROI, co ve FinOps existuje.
Často kladené otázky
Co přesně jsou zombie zdroje v AWS?
Zombie zdroje jsou alokované (a účtované) komponenty, které už neposkytují žádnou hodnotu. Typicky nepřipojený EBS svazek, snapshoty ze smazaných AMI, nečinná NAT Gateway s nulovým provozem, nevázaná Elastic IP nebo Load Balancer s 0 healthy targets. Průměrně tvoří 15 až 30 % útraty za AWS.
Jak najdu všechny nepřipojené EBS svazky ve svém AWS účtu?
Nejrychleji přes AWS CLI: aws ec2 describe-volumes --filters Name=status,Values=available. Skript spusťte pro každý region zvlášť. Trusted Advisor (Business Support+) je zobrazí v kategorii Cost Optimization automaticky, včetně odhadu úspory. Pro Azure použijte Get-AzDisk | Where DiskState -eq 'Unattached', pro GCP gcloud compute disks list --filter="-users:*".
Kolik reálně stojí jedna nečinná NAT Gateway měsíčně?
32,40 USD měsíčně jen za dostupnost (v regionu us-east-1, cena 0,045 USD/hodinu). Data processing se účtuje navíc, ale nečinná gateway ho negeneruje. Ve VPC s více NAT Gateway (jedna per AZ) násobte počtem AZ.
Je bezpečné automaticky mazat nepřipojené EBS svazky?
Ne, ne bez opatření. Doporučuji tříkrokový workflow: (1) tagovací Lambda označí kandidáty s datem plánovaného smazání za 30 dní, (2) automatický e-mail vlastníkovi podle owner tagu, (3) mazací Lambda vytvoří pojistný snapshot a smaže svazek až po uplynutí quarantine. Dry-run testování minimálně týden před ostrým nasazením.
Jaké nástroje detekují zombie zdroje zdarma?
V AWS je to Trusted Advisor Basic (6 kontrol) a AWS Cost Explorer s doporučeními Rightsizing. V Azure je Advisor součástí každé subscription bez příplatku a pokrývá disky, IP, VM i SQL. V GCP dostanete Recommender/Active Assist s cost impact odhadem. Open-source alternativy: Komiser, Cloud Custodian, Steampipe.
Jak zabránit tomu, aby zombie zdroje vznikaly znovu?
Kombinací tří vrstev: povinné tagování vynucené v CI/CD (Terraform Sentinel nebo OPA), ephemeral environments s automatickým teardownem po 7 dnech nečinnosti, a týdenní review neotagovaných zdrojů v cost dashboardu. Snižuje to vznik nových zombie o cca 95 %.
Detailní srovnání AWS Reserved Instances, Azure Reservations, Savings Plans a GCP Committed Use Discounts pro rok 2026. Zjistíte, který typ závazku zvolit podle stability zátěže, jaké slevy jsou reálné a jak sestavit vrstvenou strategii pro maximální úsporu.
Síťový provoz tvoří 10–18 % cloudových rozpočtů. Naučte se snížit egress poplatky, NAT Gateway náklady a cross-region přenosy o 40–78 % pomocí VPC Endpoints, CDN, komprese a Cloudflare R2 — s Terraform příklady.
Databáze tvoří 30–40 % cloudového rozpočtu, ale málokdo je systematicky optimalizuje. AWS Database Savings Plans, Graviton4, Aurora I/O-Optimized, Azure Hybrid Benefit a GCP BigQuery CUDs mohou výrazně snížit náklady. Praktický průvodce s příklady kódu pro všechny tři velké poskytovatele.