Zašto neiskorišteni cloud resursi koštaju milijarde
Zamislite da svaki mjesec plaćate najam za pet uredskih prostora, a zapravo koristite samo tri. Zvuči apsurdno, zar ne? Pa, upravo to rade organizacije diljem svijeta sa svojim cloud resursima — plaćaju za virtualke koje ne rade ništa, diskove koji nisu spojeni ni na što, i snapshotove koje je netko napravio prije dvije godine "za svaki slučaj".
Brojke su, iskreno, zastrašujuće. Prema industrijskim analizama, 28-35% ukupne cloud potrošnje otpada na neiskorištene ili nedovoljno iskorištene resurse. Na globalnoj razini to ispada otprilike 187 milijardi dolara godišnje bačenog novca. VMwareovo izvješće iz 2025. pokazuje da 49% IT voditelja priznaje kako je više od 25% njihove cloud potrošnje bačeno. A čak 31% smatra da im rasipanje premašuje 50%.
Kad raščlanimo gdje točno nestaje novac, slika postaje jasnija:
- Neaktivni (idle) resursi čine 10-15% mjesečnog računa — EC2 instance, Azure VM-ovi ili GCP VM-ovi koji rade, ali praktički ništa ne procesiraju
- Predimenzionirana računalna snaga (over-provisioned compute) odnosi dodatnih 10-12% — instance koje koriste tek djelić svojih kapaciteta
- Napuštena pohrana (orphaned storage) dodaje 3-6% — EBS volumeni bez instance, nepovezani diskovi, zastarjeli snapshotovi
- Kontejnersko rasipanje je posebno alarmantno: prema Datadogu, više od 80% potrošnje na kontejnere otpada na neiskorištene resurse
A tipični "zombie" resursi? Pronaći ćete ih u gotovo svakom cloud okruženju:
- Zaustavljene EC2 instance ili VM-ove koji još uvijek imaju priključene EBS volumene s naplatom
- Nepovezane EBS volumene (status:
available) — ostaju nakon brisanja instance - Zastarjele snapshotove koji referenciraju izbrisane volumene
- Nekorištene Elastic IP adrese (AWS naplaćuje za svaku neiskorištenu EIP — da, svaku)
- Idle load balancere bez aktivnih ciljnih grupa ili s nula aktivnih veza
- Zombie NAT gatewaye koji služe prazne podmreže
- Stare AMI slike i registrirane kontejnerske slike koje nitko ne koristi
Dobra vijest? Organizacije koje implementiraju FinOps prakse i automatsko čišćenje neiskorištenih resursa štede 25-30% na mjesečnoj cloud potrošnji. U nastavku ćemo vam pokazati konkretne skripte, CLI naredbe i alate kojima možete identificirati i ukloniti te resurse na sve tri velike cloud platforme.
Identifikacija neiskorištenih resursa na AWS-u
AWS je najzrelija cloud platforma po pitanju alata za analizu troškova, ali to ne znači da je lako držati sve pod kontrolom. Sa stotinama servisa i tisućama mogućih konfiguracija, zombie resursi se nakupljaju brže nego što mislite.
Ajmo redom.
Neaktivne EC2 instance
Prva stvar koju trebate provjeriti su EC2 instance koje rade, ali zapravo ne rade ništa korisno. Ključni pokazatelji neaktivnosti:
- CPU iskorištenost ispod 3% tijekom 14 uzastopnih dana
- Mrežni promet (Network I/O) manji od 5 MB u istom razdoblju
- Nema aktivnih SSH ili RDP sesija
- Nema planiranih zadataka (cron jobs) koji bi opravdali rad instance
Za početak, pronađimo sve zaustavljene instance koje i dalje generiraju troškove (priključeni EBS volumeni, Elastic IP adrese):
# Pronalaženje svih zaustavljenih EC2 instanci u regiji
aws ec2 describe-instances \
--filters "Name=instance-state-name,Values=stopped" \
--query "Reservations[].Instances[].{
ID:InstanceId,
Tip:InstanceType,
Ime:Tags[?Key=='Name']|[0].Value,
ZaustavljenoOd:StateTransitionReason
}" \
--output table
# Pronalaženje instanci s niskom CPU iskorištenošću (ispod 3%) u zadnjih 14 dana
aws cloudwatch get-metric-statistics \
--namespace AWS/EC2 \
--metric-name CPUUtilization \
--dimensions Name=InstanceId,Value=i-0abc123def456789 \
--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 86400 \
--statistics Average \
--output table
Za sustavniji pregled, tu su AWS Trusted Advisor (automatski označava instance s niskom iskorištenošću) i AWS Compute Optimizer koji na temelju strojnog učenja predlaže odgovarajuće veličine instanci. Compute Optimizer analizira posljednjih 14 dana CloudWatch metrika i daje konkretne preporuke — no budući da smo right-sizing pokrili u zasebnom članku, ovdje se fokusiramo na potpuno neiskorištene resurse koje treba ugasiti ili izbrisati.
Nepovezani EBS volumeni i zastarjeli snapshotovi
EBS volumeni su jedan od najčešćih izvora nepotrebnih troškova. I to je nešto što mnogi timovi uopće ne primjećuju mjesecima.
Kad izbrišete EC2 instancu, priključeni EBS volumeni ne moraju biti automatski izbrisani — ovisi o postavci DeleteOnTermination. Rezultat? Volumeni u statusu available koji lebde u vašem računu i generiraju troškove.
# Pronalaženje svih nepovezanih EBS volumena (status: available)
aws ec2 describe-volumes \
--filters "Name=status,Values=available" \
--query "Volumes[].{
ID:VolumeId,
Velicina:Size,
Tip:VolumeType,
Kreirano:CreateTime,
Zona:AvailabilityZone
}" \
--output table
# Izračun ukupne veličine nepovezanih volumena u GB
aws ec2 describe-volumes \
--filters "Name=status,Values=available" \
--query "sum(Volumes[].Size)" \
--output text
Kod snapshotova je situacija malo složenija. Prije brisanja morate provjeriti:
- Je li snapshot registriran kao AMI (Amazon Machine Image) — ako jest, prvo morate deregistrirati AMI
- Koristi li se snapshot kao izvor za neki drugi volumen
- Postoji li retention politika ili compliance zahtjev koji nalaže čuvanje
# Pronalaženje snapshotova koji nisu povezani s nijednim aktivnim volumenom
# Korak 1: Dohvatite sve vaše snapshotove
aws ec2 describe-snapshots \
--owner-ids self \
--query "Snapshots[].{
ID:SnapshotId,
VolumenID:VolumeId,
Velicina:VolumeSize,
Kreirano:StartTime,
Opis:Description
}" \
--output table
# Korak 2: Pronađite snapshotove starije od 90 dana
aws ec2 describe-snapshots \
--owner-ids self \
--query "Snapshots[?StartTime<='$(date -u -d '90 days ago' +%Y-%m-%dT%H:%M:%S)'].{
ID:SnapshotId,
Starost:StartTime,
Velicina:VolumeSize
}" \
--output table
Nekorištene Elastic IP adrese i load balanceri
AWS naplaćuje $0,005 po satu za svaku Elastic IP adresu koja nije povezana s aktivnom instancom. To je oko $3,60 mjesečno po adresi — zvuči malo, ali ako imate 50 neiskorištenih EIP-ova (a vidjeli smo i takve slučajeve), to je $180 mjesečno bez ikakvog razloga.
# Pronalaženje Elastic IP adresa koje nisu pridružene instancama
aws ec2 describe-addresses \
--query "Addresses[?AssociationId==null].{
IP:PublicIp,
AlokacijaID:AllocationId,
Domena:Domain
}" \
--output table
# Pronalaženje Application Load Balancera bez aktivnih veza
# Provjeravamo metriku ActiveConnectionCount za zadnjih 7 dana
aws cloudwatch get-metric-statistics \
--namespace AWS/ApplicationELB \
--metric-name ActiveConnectionCount \
--dimensions Name=LoadBalancer,Value=app/moj-alb/1234567890abcdef \
--start-time $(date -u -d '7 days ago' +%Y-%m-%dT%H:%M:%S) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
--period 3600 \
--statistics Sum \
--output table
Load balanceri su posebno podmukli jer imaju fiksnu satnicu bez obzira na promet. Application Load Balancer košta minimalno oko $16 mjesečno čak i bez ijedne aktivne veze. Potražite ALB-ove i NLB-ove kod kojih je ActiveConnectionCount jednak nuli tijekom dužeg razdoblja, te one koji nemaju registrirane ciljne grupe ili imaju samo nezdrave (unhealthy) ciljeve.
Identifikacija neiskorištenih resursa na Azureu
Azure ima iznimno dobru ugrađenu podršku za identifikaciju neiskorištenih resursa kroz Azure Advisor. Ali trebate znati i kako samostalno postavljati upite — za potpunu kontrolu nema prečaca.
Neaktivni virtualni strojevi
Azure Advisor automatski generira preporuke za virtualne strojeve s niskom iskorištenošću. Pristupite mu kroz portal (Advisor → Cost) ili putem CLI-ja. Za detaljniji uvid, Azure Resource Graph omogućuje upite koji obuhvaćaju sve pretplate odjednom:
# Azure Resource Graph upit za pronalaženje dealociranih VM-ova
az graph query -q "
Resources
| where type == 'microsoft.compute/virtualmachines'
| where properties.extended.instanceView.powerState.code == 'PowerState/deallocated'
| project name, resourceGroup, location, subscriptionId,
vmSize=properties.hardwareProfile.vmSize,
tags
| order by name asc
"
# Pronalaženje svih VM-ova koji su dealocirani više od 30 dana
# (koristimo Activity Log za provjeru posljednje akcije)
az monitor activity-log list \
--resource-group moja-grupa \
--offset 30d \
--query "[?operationName.value=='Microsoft.Compute/virtualMachines/deallocate/action'].{
Resurs:resourceId,
Vrijeme:eventTimestamp,
Status:status.value
}" \
--output table
Jedna bitna razlika u odnosu na AWS: Azure ne naplaćuje računalnu snagu za dealocirane VM-ove. Međutim, diskovi priključeni na te VM-ove i dalje se naplaćuju. Zato je ključno identificirati VM-ove koji su dealocirani dulje vrijeme i obrisati ih zajedno s pripadajućim diskovima.
Nepovezani diskovi i javne IP adrese
PowerShell je najmoćniji alat za upravljanje Azure resursima (barem po mom iskustvu). Evo kako pronaći nepovezane managed diskove i javne IP adrese:
# PowerShell: Pronalaženje nepovezanih managed diskova
Get-AzDisk | Where-Object {
$_.ManagedBy -eq $null -and
$_.DiskState -eq 'Unattached'
} | Select-Object Name, ResourceGroupName, DiskSizeGB, Location, TimeCreated |
Format-Table -AutoSize
# Izračun ukupnog troška nepovezanih diskova
$nepovezaniDiskovi = Get-AzDisk | Where-Object { $_.ManagedBy -eq $null }
$ukupnoGB = ($nepovezaniDiskovi | Measure-Object -Property DiskSizeGB -Sum).Sum
Write-Host "Ukupno nepovezanih diskova: $($nepovezaniDiskovi.Count)"
Write-Host "Ukupna velicina: $ukupnoGB GB"
# Pronalaženje neiskorištenih javnih IP adresa
Get-AzPublicIpAddress | Where-Object {
$_.IpConfiguration -eq $null
} | Select-Object Name, ResourceGroupName, IpAddress, Location |
Format-Table -AutoSize
# Az CLI alternativa za nepovezane diskove
az disk list \
--query "[?managedBy==null].{
Ime:name,
Grupa:resourceGroup,
Velicina:diskSizeGb,
Stanje:diskState,
Lokacija:location
}" \
--output table
Sustav isteka temeljen na oznakama (tag-based expiry)
Ovo je, po mom mišljenju, jedna od najelegantnijih praksi za Azure. Ideja je jednostavna: kad kreirate resurs (osobito u dev/test okruženju), dodate mu oznaku expireOn s datumom isteka.
# Kreiranje resursa s oznakom isteka
az vm create \
--name test-vm-01 \
--resource-group dev-resursi \
--image Ubuntu2204 \
--size Standard_B2s \
--tags expireOn=2026-04-14 vlasnik=ivan.horvat okolina=dev
# Pronalaženje resursa kojima je istekao rok trajanja
az resource list \
--query "[?tags.expireOn != null && tags.expireOn < '$(date +%Y-%m-%d)'].{
Ime:name,
Tip:type,
Grupa:resourceGroup,
Istice:tags.expireOn,
Vlasnik:tags.vlasnik
}" \
--output table
Ovaj pristup je koristan jer stavlja odgovornost na kreatore resursa. Ako netko kreira resurs bez oznake expireOn, automatski mu se može dodijeliti zadani rok od, primjerice, 30 dana. Uskoro ćemo pokazati kako automatizirati brisanje resursa s isteklim rokovima.
Identifikacija neiskorištenih resursa na GCP-u
Google Cloud Platform ima vjerojatno najnapredniji ugrađeni sustav preporuka od svih triju platformi. Recommender API analizira metrike i automatski generira prijedloge za uštedu — i to radi prilično dobro.
Neaktivne VM instance
GCP Idle VM Recommender automatski identificira VM instance s niskom iskorištenošću. Preporuke možete pregledati u konzoli ili putem gcloud CLI-ja:
# Pregled preporuka za neaktivne VM-ove
gcloud recommender recommendations list \
--recommender=google.compute.instance.IdleResourceRecommender \
--project=moj-projekt \
--location=europe-west3-a \
--format="table(
name.basename(),
description,
primaryImpact.costProjection.cost.units,
stateInfo.state
)"
# Ručno pronalaženje VM-ova koji nisu aktivni — provjeravamo status
gcloud compute instances list \
--project=moj-projekt \
--filter="status=TERMINATED OR status=SUSPENDED" \
--format="table(name, zone, status, machineType.basename(),
creationTimestamp.date('%Y-%m-%d'))"
# Provjera CPU iskorištenosti instance u zadnjih 14 dana
gcloud monitoring time-series list \
--project=moj-projekt \
--filter='metric.type="compute.googleapis.com/instance/cpu/utilization" AND
resource.labels.instance_id="1234567890"' \
--interval-start-time=$(date -u -d '14 days ago' +%Y-%m-%dT%H:%M:%SZ) \
--interval-end-time=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
--format="table(points.interval.startTime, points.value.doubleValue)"
Nepovezani persistentni diskovi
Slično kao na AWS-u i Azureu — GCP persistentni diskovi nastavljaju generirati troškove i nakon brisanja VM instance kojoj su bili priključeni. Evo kako ih pronaći:
# Pronalaženje diskova koji nisu priključeni ni na jednu instancu
gcloud compute disks list \
--project=moj-projekt \
--filter="NOT users:*" \
--format="table(name, zone.basename(), sizeGb, type.basename(),
status, creationTimestamp.date('%Y-%m-%d'))"
# Izračun ukupne veličine nepovezanih diskova po projektu
gcloud compute disks list \
--project=moj-projekt \
--filter="NOT users:*" \
--format="value(sizeGb)" | \
awk '{s+=$1} END {print "Ukupno nepovezanih diskova: " s " GB"}'
# Pronalaženje nepovezanih diskova starijih od 30 dana
gcloud compute disks list \
--project=moj-projekt \
--filter="NOT users:* AND creationTimestamp<$(date -u -d '30 days ago' +%Y-%m-%dT%H:%M:%SZ)" \
--format="table(name, zone.basename(), sizeGb, creationTimestamp.date('%Y-%m-%d'))"
# Pronalaženje neiskorištenih statičkih IP adresa
gcloud compute addresses list \
--project=moj-projekt \
--filter="status=RESERVED" \
--format="table(name, address, region.basename(), status)"
GCP Recommender je tu stvarno koristan jer ne samo da identificira neiskorištene resurse, već i procjenjuje koliko ćete uštedjeti brisanjem svakog pojedinog resursa. Preporuke se ažuriraju svakodnevno na temelju metrika iz Cloud Monitoringa.
Automatizacija čišćenja pomoću skripti
Ručna provjera je dobar početak, ali pravo smanjenje troškova postiže se automatizacijom. Hajde da pogledamo kompletne, funkcionalne skripte za sve tri platforme koje možete odmah prilagoditi i pokrenuti.
AWS Lambda + Boto3 skripta za čišćenje EBS volumena
Ova Python skripta koristi Boto3 za pronalaženje i brisanje nepovezanih EBS volumena. Uključuje dry-run mod za sigurno testiranje i SNS obavijesti za praćenje — jer nikad ne želite brisati resurse bez traga o tome što se dogodilo.
import boto3
import os
from datetime import datetime, timezone
def lambda_handler(event, context):
"""
Lambda funkcija za automatsko čišćenje nepovezanih EBS volumena.
Pokreće se putem EventBridge pravila (npr. svaki ponedjeljak u 8:00).
Varijable okruženja:
DRY_RUN - "true" za simulaciju, "false" za stvarno brisanje
SNS_TOPIC_ARN - ARN SNS teme za obavijesti
MIN_AGE_DAYS - Minimalna starost volumena u danima (zadano: 7)
"""
ec2 = boto3.client('ec2')
sns = boto3.client('sns')
dry_run = os.environ.get('DRY_RUN', 'true').lower() == 'true'
sns_topic = os.environ.get('SNS_TOPIC_ARN', '')
min_age_days = int(os.environ.get('MIN_AGE_DAYS', '7'))
# Pronalaženje svih nepovezanih volumena
response = ec2.describe_volumes(
Filters=[{'Name': 'status', 'Values': ['available']}]
)
sada = datetime.now(timezone.utc)
obrisani = []
preskoceni = []
for volumen in response['Volumes']:
volumen_id = volumen['VolumeId']
kreiran = volumen['CreateTime']
starost_dana = (sada - kreiran).days
velicina_gb = volumen['Size']
# Provjera zaštitne oznake
oznake = {t['Key']: t['Value'] for t in volumen.get('Tags', [])}
if oznake.get('DoNotDelete', '').lower() == 'true':
preskoceni.append(f"{volumen_id} (zaštićen oznakom)")
continue
# Preskačemo volumene mlađe od MIN_AGE_DAYS
if starost_dana < min_age_days:
preskoceni.append(f"{volumen_id} (star samo {starost_dana} dana)")
continue
if dry_run:
obrisani.append(
f"[DRY-RUN] {volumen_id}: {velicina_gb} GB, "
f"star {starost_dana} dana"
)
else:
try:
ec2.create_snapshot(
VolumeId=volumen_id,
Description=f"Sigurnosna kopija prije brisanja - {volumen_id}",
TagSpecifications=[{
'ResourceType': 'snapshot',
'Tags': [
{'Key': 'AutoCleanup', 'Value': 'true'},
{'Key': 'IzvorVolumen', 'Value': volumen_id}
]
}]
)
ec2.delete_volume(VolumeId=volumen_id)
obrisani.append(
f"OBRISANO: {volumen_id}: {velicina_gb} GB, "
f"star {starost_dana} dana"
)
except Exception as e:
preskoceni.append(f"{volumen_id} (greška: {str(e)})")
# Priprema izvješća
izvjesce = (
f"=== Izvješće o čišćenju EBS volumena ===\n"
f"Datum: {sada.strftime('%Y-%m-%d %H:%M UTC')}\n"
f"Način rada: {'DRY-RUN' if dry_run else 'AKTIVNO BRISANJE'}\n"
f"Obrisano: {len(obrisani)} | Preskočeno: {len(preskoceni)}\n\n"
)
for stavka in obrisani:
izvjesce += stavka + "\n"
if sns_topic:
sns.publish(
TopicArn=sns_topic,
Subject=f"EBS čišćenje: {len(obrisani)} volumena",
Message=izvjesce
)
return {'statusCode': 200, 'obrisano': len(obrisani)}
Za zakazivanje ove Lambda funkcije, kreirajte EventBridge pravilo s cron izrazom. Primjerice, za pokretanje svakog ponedjeljka u 8:00 UTC:
# Kreiranje EventBridge pravila za tjedno pokretanje
aws events put-rule \
--name "tjedno-ciscenje-ebs" \
--schedule-expression "cron(0 8 ? * MON *)" \
--description "Tjedno čišćenje nepovezanih EBS volumena"
# Povezivanje Lambda funkcije s pravilom
aws events put-targets \
--rule "tjedno-ciscenje-ebs" \
--targets "Id"="1","Arn"="arn:aws:lambda:eu-central-1:123456789:function:ebs-cleanup"
Azure Functions + PowerShell skripta za čišćenje resursa
Sljedeća PowerShell skripta koristi sustav oznaka expireOn za automatsko brisanje isteklih resursa. Dizajnirana je za pokretanje kao Azure Function s Timer triggerom:
# Azure Function: PowerShell skripta za čišćenje isteklih resursa
# Timer trigger: 0 0 6 * * 1 (svaki ponedjeljak u 06:00 UTC)
param($Timer)
$dryRun = $env:DRY_RUN -eq "true"
$graceperiodDana = [int]($env:GRACE_PERIOD_DAYS ?? 3)
$danas = Get-Date -Format "yyyy-MM-dd"
Write-Host "=== Azure čišćenje resursa ==="
Write-Host "Način rada: $(if ($dryRun) {'DRY-RUN'} else {'AKTIVNO BRISANJE'})"
# Pronalaženje resursa s isteklom expireOn oznakom
$istekliResursi = Search-AzGraph -Query @"
Resources
| where tags contains 'expireOn'
| where tags.expireOn < '$danas'
| where tags.DoNotDelete != 'true'
| project id, name, type, resourceGroup,
expireOn=tags.expireOn, vlasnik=tags.vlasnik
| order by expireOn asc
"@
Write-Host "Pronađeno isteklih resursa: $($istekliResursi.Count)"
$obrisani = @()
$greske = @()
foreach ($resurs in $istekliResursi) {
$istekao = [DateTime]::Parse($resurs.expireOn)
$danaIsteklo = (New-TimeSpan -Start $istekao -End (Get-Date)).Days
if ($danaIsteklo -lt $graceperiodDana) {
Write-Host "GRACE PERIOD: $($resurs.name) — čekamo $graceperiodDana dana"
continue
}
if ($dryRun) {
$obrisani += [PSCustomObject]@{
Ime = $resurs.name; Tip = $resurs.type; Status = "DRY-RUN"
}
} else {
try {
Remove-AzResource -ResourceId $resurs.id -Force
$obrisani += [PSCustomObject]@{
Ime = $resurs.name; Tip = $resurs.type; Status = "OBRISANO"
}
} catch {
$greske += "GREŠKA: $($resurs.name) — $($_.Exception.Message)"
}
}
}
Write-Host "Obrađeno: $($obrisani.Count) | Grešaka: $($greske.Count)"
$obrisani | Format-Table -AutoSize
GCP Cloud Functions + Python skripta za zaustavljanje neaktivnih VM-ova
Ova Python skripta koristi Cloud Monitoring API za identifikaciju VM-ova s niskom CPU iskorištenošću i automatski ih zaustavlja. Pokreće se putem Cloud Schedulera:
import os
from datetime import datetime, timezone, timedelta
from google.cloud import compute_v1
from google.cloud import monitoring_v3
def zaustavi_neaktivne_vmove(event, context):
"""
Cloud Function za zaustavljanje neaktivnih VM-ova.
Pokreće se putem Cloud Scheduler pub/sub poruke.
"""
project = os.environ.get('GCP_PROJECT')
cpu_prag = float(os.environ.get('CPU_PRAG', '0.03'))
period_dana = int(os.environ.get('PERIOD_DANA', '14'))
dry_run = os.environ.get('DRY_RUN', 'true').lower() == 'true'
zasticene_labele = os.environ.get(
'ISKLJUCI_LABELE', 'production,critical'
).split(',')
compute_client = compute_v1.InstancesClient()
monitoring_client = monitoring_v3.MetricServiceClient()
sada = datetime.now(timezone.utc)
pocetak = sada - timedelta(days=period_dana)
rezultati = {'zaustavljeno': [], 'preskoceno': [], 'greske': []}
zones_client = compute_v1.ZonesClient()
for zona in zones_client.list(project=project):
try:
instance_list = compute_client.list(
project=project, zone=zona.name
)
except Exception:
continue
for instanca in instance_list:
if instanca.status != 'RUNNING':
continue
labele = dict(instanca.labels) if instanca.labels else {}
if any(l in labele for l in zasticene_labele):
rezultati['preskoceno'].append(
f"{instanca.name} — zaštićena labelom"
)
continue
# Provjera CPU iskorištenosti putem Cloud Monitoringa
filtar = (
f'metric.type="compute.googleapis.com/instance/cpu/utilization"'
f' AND resource.labels.instance_id="{instanca.id}"'
)
interval = monitoring_v3.TimeInterval({
'start_time': {'seconds': int(pocetak.timestamp())},
'end_time': {'seconds': int(sada.timestamp())}
})
try:
metrike = monitoring_client.list_time_series(
request={
'name': f'projects/{project}',
'filter': filtar,
'interval': interval,
'view': monitoring_v3.ListTimeSeriesRequest
.TimeSeriesView.FULL,
}
)
tocke = []
for serija in metrike:
for tocka in serija.points:
tocke.append(tocka.value.double_value)
if not tocke:
continue
prosjek_cpu = sum(tocke) / len(tocke)
if prosjek_cpu < cpu_prag:
if dry_run:
rezultati['zaustavljeno'].append(
f"[DRY-RUN] {instanca.name} — "
f"CPU: {prosjek_cpu:.2%}"
)
else:
compute_client.stop(
project=project,
zone=zona.name,
instance=instanca.name
)
rezultati['zaustavljeno'].append(
f"ZAUSTAVLJENO: {instanca.name} — "
f"CPU: {prosjek_cpu:.2%}"
)
except Exception as e:
rezultati['greske'].append(f"{instanca.name}: {str(e)}")
print(f"Zaustavljeno: {len(rezultati['zaustavljeno'])}")
print(f"Preskočeno: {len(rezultati['preskoceno'])}")
return rezultati
Za zakazivanje, koristite Cloud Scheduler s Pub/Sub triggerom:
# Kreiranje Pub/Sub teme za trigger
gcloud pubsub topics create ciscenje-neaktivnih-vmova
# Kreiranje Cloud Scheduler zadatka — svaki ponedjeljak u 07:00 CET
gcloud scheduler jobs create pubsub zaustavi-idle-vmove \
--schedule="0 7 * * 1" \
--topic=ciscenje-neaktivnih-vmova \
--message-body='{"akcija": "zaustavi_idle"}' \
--time-zone="Europe/Zagreb" \
--description="Tjedno zaustavljanje neaktivnih VM-ova"
# Deploy Cloud Function
gcloud functions deploy zaustavi-neaktivne-vmove \
--runtime=python312 \
--trigger-topic=ciscenje-neaktivnih-vmova \
--set-env-vars="GCP_PROJECT=moj-projekt,DRY_RUN=true,CPU_PRAG=0.03" \
--memory=256MB \
--timeout=300s \
--region=europe-west3
Alati otvorenog koda za automatsko čišćenje
Osim vlastitih skripti, postoji i solidni ekosustav alata otvorenog koda koji mogu značajno pojednostaviti proces. Evo onih koji su se dokazali u praksi:
- cloud-nuke (Gruntwork) — Vjerojatno najpoznatiji alat za automatsko brisanje resursa na AWS-u. Podržava gotovo sve AWS servise, omogućuje filtriranje po regijama, starosti resursa i oznakama. Gruntwork je ovim alatom smanjio vlastiti AWS račun za 85% — s $2.000 na oko $300 mjesečno. Idealan za čišćenje dev/test okruženja.
- Azure Subscription Cleaner — Specijalizirani alat za čišćenje Azure pretplata. Pronalazi i briše nepovezane diskove, neiskorištene javne IP adrese, prazne resurse grupe i istekle resurse na temelju oznaka.
- GCP Recommender CLI — Ugrađeni GCP alat koji agregira preporuke iz više Recommender servisa (Idle VM, Idle Disk, Idle IP) i prikazuje procijenjenu uštedu za svaki resurs.
- Datadog Cloud Cost Recommendations — Multi-cloud alat koji agregira podatke s AWS-a, Azurea i GCP-a, identificira neiskorištene resurse i daje konkretne preporuke s procijenjenom uštedom.
# cloud-nuke: Suho pokretanje — prikazuje što bi bilo obrisano
cloud-nuke aws --dry-run
# Brisanje resursa starijih od 24 sata u specifičnim regijama
cloud-nuke aws --older-than 24h --region eu-central-1 --region eu-west-1
# GCP Recommender: Pregled preporuka za uštedu
gcloud recommender recommendations list \
--recommender=google.compute.instance.IdleResourceRecommender \
--project=moj-projekt \
--location=europe-west3-a
Pri odabiru alata razmislite o sljedećem: koliko platforma pokrivate, trebate li automatsko brisanje ili samo izvješćivanje, te koliko granularnu kontrolu želite. Za organizacije s jednom platformom, nativni alati su često sasvim dovoljni. Za multi-cloud okruženja, alati poput Datadoga ili vlastite skripte s centraliziranim upravljanjem su bolji izbor.
Najbolje prakse za sigurno automatsko čišćenje
Automatsko brisanje cloud resursa može biti iznimno korisno, ali i opasno ako se ne provodi ispravno. Jedan pogrešan filtar u skripti i mogli biste obrisati produkcijsku bazu podataka. Nije pretjerivanje — vidjeli smo to u praksi.
Zato je ključno slijediti strukturirani proces.
1. Discover → Report → Confirm → Delete radni tijek
Nikada ne idite izravno na brisanje. Strukturirani radni tijek trebao bi izgledati ovako:
- Discover (Otkrij) — Skripte skeniraju okruženje i identificiraju kandidate za brisanje
- Report (Izvijesti) — Generira se izvješće s popisom resursa, vlasnicima i procijenjenim uštedama
- Confirm (Potvrdi) — Vlasnici resursa dobivaju obavijest i imaju vrijeme za prigovor
- Delete (Obriši) — Tek nakon isteka roka za prigovor resursi se brišu
2. Dry-run način uvijek prvi
Svaka skripta za čišćenje mora imati dry-run način rada koji je uključen prema zadanim postavkama. Prve 2-4 tjedna pokretanja nove skripte pokrenite isključivo u dry-run modu i detaljno pregledajte izvješća. Tek kad ste sigurni da skripta ispravno identificira resurse, prebacite na aktivno brisanje.
3. Grace period (razdoblje počeka)
Umjesto trenutnog brisanja, koristite dvostupanjski proces:
- Dan 1: Označite resurs oznakom
cleanup_candidate: 2026-03-14 - Dan 1-7: Svakodnevno šaljite obavijesti vlasniku resursa
- Dan 8: Ako vlasnik nije uklonio oznaku ili odgovorio, obrišite resurs
4. Zaštitne oznake za produkcijske resurse
Uvedite obvezne zaštitne oznake koje će vaše skripte poštovati:
# Primjeri zaštitnih oznaka koje skripte moraju provjeriti
DoNotDelete: "true" # Nikada ne brisati
Environment: "production" # Preskočiti produkcijske resurse
ManagedBy: "terraform" # Resursima upravlja IaC
CriticalService: "true" # Kritični servis
# AWS primjer: dodavanje zaštitne oznake
aws ec2 create-tags \
--resources i-0abc123def456789 vol-0abc123def456789 \
--tags Key=DoNotDelete,Value=true Key=Environment,Value=production
5. Odvojeni računi za dev/test okruženja
Najbolja praksa je korištenje potpuno odvojenih AWS računa, Azure pretplata ili GCP projekata za razvojna i testna okruženja. Na tim računima možete agresivnije provoditi čišćenje — primjerice, brisati sve resurse starije od 48 sati ili automatski gasiti sve instance vikendom. Produkcija je druga priča.
6. Mjesečni raspored revizije
Čak i s potpuno automatiziranim čišćenjem, provodite mjesečnu reviziju:
- Pregled izvješća o obrisanim resursima — je li nešto obrisano što nije trebalo biti?
- Analiza novih tipova zombie resursa koji su se pojavili
- Ažuriranje filtera i pragova u skriptama
- Provjera funkcioniraju li obavijesti i eskalacije ispravno
- Usporedba troškova s prethodnim mjesecom — koliko ste zaista uštedjeli?
Organizacije koje dosljedno primjenjuju ove prakse tipično postižu 25-30% smanjenje mjesečne cloud potrošnje u prvih 3-6 mjeseci, s održivim uštedama od 15-20% dugoročno. To nisu mali iznosi.
Često postavljana pitanja (FAQ)
1. Koliko novca mogu uštedjeti čišćenjem neiskorištenih cloud resursa?
Uštede variraju ovisno o veličini organizacije i razini postojećeg upravljanja troškovima, ali brojke su dosljedne: neiskorišteni resursi čine 10-15% prosječnog mjesečnog cloud računa. Za organizaciju koja troši $50.000 mjesečno na cloud, to je $5.000-7.500 mjesečne uštede samo od brisanja resursa koji ne rade ništa. Ako dodate i optimizaciju predimenzioniranih resursa (dodatnih 10-12%), uštede mogu doseći 25-30%. Gruntwork je, primjerice, korištenjem cloud-nuke smanjio račun za dev/test okruženja za 85% — s $2.000 na oko $300 mjesečno.
2. Kako spriječiti slučajno brisanje proizvodnih resursa?
Preporučujemo višeslojni pristup. Prvo, uvedite obvezne zaštitne oznake poput DoNotDelete: true i Environment: production na sve produkcijske resurse, a zatim osigurajte da vaše skripte uvijek provjeravaju te oznake. Koristite odvojene AWS račune, Azure pretplate ili GCP projekte za produkciju i razvoj. Uvedite grace period od minimalno 7 dana između označavanja resursa za brisanje i stvarnog brisanja, uz automatske obavijesti vlasnicima. I uvijek — uvijek — pokrenite svaku novu skriptu u dry-run modu nekoliko tjedana prije aktiviranja. Koristite AWS Resource Protection, Azure Resource Locks ili GCP Liens za dodatnu zaštitu kritičnih resursa.
3. Koji su najčešći tipovi zombie resursa u oblaku?
Na prvom mjestu su nepovezani diskovi (EBS volumeni, Azure Managed Diskovi, GCP Persistent Diskovi) — nastaju kad obrišete instancu, ali disk ostane. Slijede zastarjeli snapshotovi koji referenciraju resurse koji više ne postoje. Neiskorištene Elastic IP adrese i statičke IP adrese generiraju troškove bez isporuke vrijednosti. Idle load balanceri bez registriranih ciljeva koštaju fiksnu satnicu. Tu su i stare AMI slike i kontejnerske slike u registrima, napuštene Lambda funkcije koje se nikada ne pozivaju, prazne resurse grupe na Azureu, te neiskorišteni NAT gatewayji.
4. Koliko često treba pokretati skripte za čišćenje?
Ovisi o tipu okruženja. Za razvojna i testna okruženja, preporučujemo dnevno ili svaka 4 sata — resursi se tu najbrže nakupljaju, a rizik od pogrešnog brisanja je najmanji. Za staging okruženja, jednom tjedno je dobar kompromis. Za produkcijska okruženja, jednom tjedno za identifikaciju i jednom mjesečno za stvarno brisanje uz obveznu ručnu potvrdu. Mnoge organizacije koriste hibridni model: automatsko brisanje u dev/test okruženjima i poluautomatski pristup u produkciji gdje skripte identificiraju resurse, ali čovjek odobrava brisanje.
5. Mogu li koristiti jedan alat za čišćenje resursa na svim cloud platformama?
Da, postoje multi-cloud rješenja. Datadog Cloud Cost Recommendations pokriva AWS, Azure i GCP s jednog sučelja. Spot.io (NetApp) i CloudHealth by VMware također nude multi-cloud upravljanje. Za alate otvorenog koda, možete kombinirati cloud-nuke za AWS, Azure Subscription Cleaner za Azure i GCP Recommender za GCP, te ih orkestrirati centralnom skriptom ili CI/CD pipelineom. Vlastite skripte nude najveću fleksibilnost — objedinite ih u jedan repozitorij i pokretajte putem zajedničkog CI/CD sustava. Za većinu organizacija, kombinacija nativnih alata s centralnim izvješćivanjem pruža najbolji omjer kontrole i jednostavnosti.