Ekim 26 2026

Ghost Infrastructure: Cloud Maliyetlerinizi Gizlice Artıran Kullanılmayan Resource’ları Tespit Etme

Modern bir devops mühendisinin kabusları genellikle gece yarısı gelen PagerDuty alarmlarıyla sınırlı değildir. Asıl soğuk terler, ay sonunda FinOps ekibinin Slack’ten attığı “Bu ayki cloud faturası neden %40 arttı?” mesajıyla başlar. Şirketler büyüdükçe, microservice mimarileri genişledikçe ve CI/CD pipeline’ları günde yüzlerce kez ephemeral ortamlar ayağa kaldırıp indirdikçe, arkada sessizce biriken “ghost infrastructure” (hayalet altyapı) kaçınılmaz hale gelir. Cost optimization sadece instance type küçültmekten ibaret değildir; asıl mesele, varlığından bile haberdar olmadığınız ama her saniye faturalandırılan zombi kaynakları yönetebilmektir. Bu rehberde, proaktif resource management ve finops pratikleriyle bu sızıntıları nasıl tespit edip kökünden temizleyeceğimizi inceliyoruz.

Zombi Altyapının Anatomisi: Bu Kaynaklar Nereden Çıkıyor?

Kıdemli bir mühendis olarak “Biz her şeyi Terraform ile yönetiyoruz, drift olmaz” yanılgısına düşmüş olabilirsiniz. Ne yazık ki gerçek dünya production ortamları ideal koşullarda çalışmaz. Zombi kaynakların arkasında genellikle üç ana faktör yatar:

1. Pipeline Race Condition ve Timeout’lar: CI runner’da koşan bir terraform destroy komutunun ağ kesintisi veya SIGKILL ile sonlanması, state dosyasının güncellenememesine ama cloud provider tarafında bazı resource’ların (örneğin provision edilmiş bir ALB veya NAT Gateway) yetim (orphaned) kalmasına yol açar.

2. Kubernetes CSI Driver Sızıntıları: K8s cluster’ında bir PersistentVolumeClaim silindiğinde, underlying cloud diskini (AWS EBS, GCP Persistent Disk) temizlemesi beklenen CSI driver zaman zaman API rate limit’e takılır veya reclaim policy’si yanlış yapılandırıldığı için diski available durumunda serbest bırakır. Pod ölür, PVC silinir ama disk sonsuza kadar faturaya yazmaya devam eder.

3. Manuel Acil Müdahaleler: Production incident sırasında debug amaçlı açılan read-replica’lar, detach edilen root volume’lar veya snapshot’lar post-mortem sonrasında ticket’lar kapandığında unutulur.

En Büyük Sessiz Katiller ve CLI ile Avlanma Taktikleri

Şimdi lafı uzatmadan, ay sonunda faturayı kabartan majör zombi kaynakları tespit etmek için terminale geçelim. AWS ekosistemini baz alacağız ancak mantık GCP ve Azure için de birebir aynıdır.

1. Unattached EBS Volume’lar

Bir EC2 instance termine edildiğinde, varsayılan olarak root volume silinir; fakat secondary volume’lar (özellikle DeleteOnTermination=false flag’i ile attach edilmiş olanlar) veya dinamik PVC diskleri arkada kalır. Üstelik bunlar io2 veya gp3 gibi yüksek IOPS provision edilmiş pahalı disklerse maliyet çarpanı devasa olur.

Aşağıdaki AWS CLI + JMESPath query’si ile sadece boşa çıkmış (available) diskleri, tipleri ve boyutlarıyla filtreleyebilirsiniz:

aws ec2 describe-volumes \
    --filters Name=status,Values=available \
    --query "Volumes[*].{ID:VolumeId,Size:Size,Type:VolumeType,AZ:AvailabilityZone,Created:CreateTime}" \
    --output table

Eğer 30 günden eski ve unattached olan diskleri doğrudan bulup silinebilir listesine atmak isterseniz, küçük bir bash one-liner işinizi görür:

aws ec2 describe-volumes \
    --filters Name=status,Values=available \
    --query "Volumes[?CreateTime<='$(date -v-30d -u +%Y-%m-%d)'].VolumeId" \
    --output text | tr '\t' '\n'

2. Unassociated Elastic IP (EIP) Sızıntıları

Cloud provider’ların en sevdiği para kazanma yöntemi: Bir IP’yi kullanırsanız ücretsizdir (veya çok ucuzdur), ama tahsis edip hiçbir instance veya Network Interface’e bağlamazsanız saatlik ceza faturası kesilir. IPv4 kıtlığı nedeniyle AWS, 1 Şubat 2024’ten itibaren tüm public IPv4 adreslerini (kullanılsın veya kullanılmasın) saatlik $0.005 ile ücretlendirmeye başladı. 100 adet boşta EIP, ayda yaklaşık $360 doğrudan çöp demektir.

aws ec2 describe-addresses \
    --query "Addresses[?AssociationId==null].{AllocationId:AllocationId,PublicIp:PublicIp}" \
    --output table

Çıkan listedeki adresleri serbest bırakmak için:

for alloc_id in $(aws ec2 describe-addresses --query "Addresses[?AssociationId==null].AllocationId" --output text); do
    echo "Releasing: $alloc_id"
    aws ec2 release-address --allocation-id "$alloc_id"
done

3. Hayalet Load Balancer’lar ve Trafiksiz NAT Gateway’ler

Bir ortamı decommission ederken compute katmanını (Auto Scaling Group, ECS Task, EKS Node) kapatıp, önündeki ALB’yi veya VPC içindeki NAT Gateway’i silmeyi unutmak çok yaygındır. NAT Gateway, üzerinden 1 byte bile geçmese bile sırf ayakta kaldığı için her ay yaklaşık $32 taban ücret çeker (bölgeye göre değişir). Çoklu AZ kurulumunda 3 NAT Gateway ayda ~$100 eder.

Son 7 gün içinde üzerinden sıfır request geçmiş ALB’leri CloudWatch metriği sorgulamadan doğrudan tespit edemezsiniz. AWS CLI ile CloudWatch metriklerini tarayarak RequestCount toplamı 0 olan load balancer’ları yakalamak en garanti yoldur:

START_TIME=$(date -u -v-7d +%Y-%m-%dT%H:%M:%SZ)
END_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)

for alb_arn in $(aws elbv2 describe-load-balancers --query "LoadBalancers[*].LoadBalancerArn" --output text); do
    alb_name=$(echo "$alb_arn" | awk -F'/' '{print $2"/"$3"/"$4}')
    sum=$(aws cloudwatch get-metric-data --metric-data-queries '[{
        "Id": "m1",
        "MetricStat": {
            "Metric": {
                "Namespace": "AWS/ApplicationELB",
                "MetricName": "RequestCount",
                "Dimensions": [{"Name": "LoadBalancer", "Value": "'"$alb_name"'"}]
            },
            "Period": 604800,
            "Stat": "Sum"
        }
    }]' --start-time "$START_TIME" --end-time "$END_TIME" --query "MetricDataResults[0].Values[0]" --output text)

    if [ "$sum" == "None" ] || [ -z "$sum" ] || [ "$sum" == "0.0" ]; then
        echo "Zombie ALB Tespit Edildi: $alb_arn (Son 7 günde 0 request)"
    fi
done

Modern Tespit Yöntemi: Steampipe ile SQL Tabanlı Cloud Auditing

Bütün AWS API’lerini bash scriptleriyle gezip JSON parse etmek bir noktadan sonra kırılgan hale gelir. Infrastructure as Code kültürüne SQL sorgulama yeteneğini entegre eden Steampipe, cloud auditing için endüstri standardı araçlardan biri haline geldi. Cloud kaynaklarını bir Postgres veritabanı gibi sorgulamanızı sağlar.

Örneğin, bağlı bir instance’ı olmayan tüm network interface’leri (ENI) bulmak için:

steampipe query "
select
  network_interface_id,
  status,
  interface_type,
  description
from
  aws_ec2_network_interface
where
  status = 'available';
"

Ya da tüm region’lardaki sahipsiz EBS snapshot’larını tek seferde listelemek için:

steampipe query "
select
  snapshot_id,
  volume_size,
  start_time,
  description
from
  aws_ebs_snapshot
where
  volume_id not in (select volume_id from aws_ebs_volume);
"

Zombileri Kalıcı Olarak Engellemek: Preventative FinOps

Manuel olarak veya haftalık cron job’lar ile CLI çalıştırmak geçici bir pansumandır. Asıl amaç, ghost altyapının oluşmasını mühendislik seviyesinde engellemektir.

1. TTL (Time-To-Live) Tabanlı Resource Tagging

Test ve staging ortamlarında ayağa kaldırılan her şey zorunlu bir TTL veya ExpiresAt tag’ine sahip olmalıdır. Bir Open Policy Agent (OPA) kuralı veya AWS SCP (Service Control Policy) ile tag’i olmayan kaynakların provision edilmesini CI seviyesinde engelleyin.

# Örnek: Cloud Custodian policy snippet (custodian.yml)
policies:
  - name: terminate-expired-ephemeral-ec2
    resource: ec2
    filters:
      - "tag:Environment": "development"
      - type: marked-for-op
        op: terminate
    actions:
      - terminate

2. Terraform lifecycle Bloklarını Doğru Kullanmak

Instance oluştururken persistent diskler bağlıyorsanız, instance silindiğinde diskin yetim kalmaması için Terraform konfigürasyonunuzda block device mapping ayarlarını açıkça belirtin:

resource "aws_instance" "app_server" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "c6i.xlarge"

  ebs_block_device {
    device_name           = "/dev/xvdf"
    volume_size           = 100
    volume_type           = "gp3"
    delete_on_termination = true # Asla unattached kalmaz
  }
}

Özet ve Aksiyon Planı

Bulut sağlayıcıları altyapınızı kurmanızı inanılmaz kolaylaştırır; ancak temizlemeyi zorlaştırmak onların iş modelinin doğal bir sonucudur. Boşta duran diskler, rotasız IP’ler ve trafiği kesilmiş load balancer’lar şirketinizin sermayesini günden güne eritir.

Yarın sabah yapacağınız ilk iş, ekibinizle 1 saatlik bir “Zombie Hunting” sprint’i düzenlemek olsun. Yukarıdaki scriptleri read-only modda çalıştırın, çıkan faturayı görün ve silme scriptlerini pipeline’larınıza gömün. FinOps sadece muhasebecilerin işi değildir; production’a saygı duyan her DevOps mühendisinin asli görevidir.

Category: Genel | LEAVE A COMMENT