GCP Billing ile Bulut Maliyetlerini Takip Etme ve Optimize Etme
Bulut maliyetleri kontrolden çıktığında, ay sonu gelen fatura sizi masanıza bağlar ve sorgular başlar: “Bu kaynaklar neden hâlâ çalışıyor?”, “Kim bu bucket’ı oluşturdu?”, “Bu Compute Engine instance’ı ne zaman durduracaktık?” GCP (Google Cloud Platform) güçlü bir altyapı sunuyor ama bu güç, dikkatli yönetilmezse ciddi maliyet sorunlarına dönüşebilir. Bu yazıda GCP Billing araçlarını kullanarak maliyetleri nasıl izleyeceğinizi, alarm kuracağınızı ve optimize edeceğinizi gerçek dünya senaryolarıyla ele alacağız.
GCP Billing Temel Kavramları
GCP’de billing yapısını anlamak, optimizasyon sürecinin ilk adımıdır. Her şey Billing Account etrafında döner. Bir Billing Account birden fazla projeye bağlanabilir ve tüm faturalandırma bu hesap üzerinden akar.
Yapıyı şöyle düşünebilirsiniz:
- Billing Account: Ana ödeme hesabı (kredi kartı veya fatura bilgisi burada)
- Projects: Kaynakların organize edildiği birimler, her proje bir billing account’a bağlanır
- Labels: Kaynaklara atadığınız etiketler, maliyet dağılımını anlamlandırır
- Cost Allocation Tags: Departman, ekip veya ortam bazında maliyetleri ayırmak için kullanılır
- Budgets & Alerts: Harcama eşiklerini belirleyip bildirim almanızı sağlar
Yeni bir ortamda ilk yapmanız gereken şey, tüm kaynaklara tutarlı etiketler eklemektir. Sonradan bu etiketsiz kaynakları analiz etmek gerçekten zordur.
gcloud ile Billing Bilgilerine Erişim
GCP CLI aracı olan gcloud, billing bilgilerine programatik erişim için oldukça kullanışlıdır. Önce mevcut billing account’larınızı listeleyelim:
# Mevcut billing account'ları listele
gcloud billing accounts list
# Belirli bir projenin billing bilgisini görüntüle
gcloud billing projects describe my-project-id
# Bir projeyi billing account'a bağla
gcloud billing projects link my-project-id
--billing-account=XXXXXX-XXXXXX-XXXXXX
Eğer birden fazla projenizi yönetiyorsanız, tüm projelerin billing durumunu toplu olarak kontrol edebilirsiniz:
# Tüm projelerin billing durumunu kontrol et
for project in $(gcloud projects list --format="value(projectId)"); do
echo "Proje: $project"
gcloud billing projects describe $project
--format="value(billingEnabled, billingAccountName)"
echo "---"
done
Bu script özellikle büyük organizasyonlarda, billing’i aktif olmayan veya yanlış hesaba bağlı projeleri tespit etmek için kullanışlıdır. Benim bir müşteride yaşadığım senaryoda, 3 test projesi yanlış billing account’a bağlıydı ve bu durum 6 ay boyunca fark edilmemişti.
BigQuery ile Detaylı Maliyet Analizi
GCP’nin en güçlü maliyet analiz özelliği, billing verilerini BigQuery’e export edebilmesidir. Cloud Console üzerinden Billing > Billing Export > BigQuery Export kısmından bu özelliği aktif edebilirsiniz. Veriler günlük olarak aktarılır ve çok detaylı sorgular çalıştırmanıza olanak tanır.
Export aktif olduktan sonra birkaç saat içinde veriler akmaya başlar. Temel sorgu yapısı şöyledir:
# BigQuery'e billing export ayarla (gcloud ile)
bq mk
--dataset
--description "GCP Billing Export Dataset"
--location=EU
my_project_id:billing_export
# Ardından Console'dan veya aşağıdaki komutu kullanarak export aktifleştir
gcloud beta billing accounts get-iam-policy BILLING_ACCOUNT_ID
BigQuery üzerinde çalıştırabileceğiniz maliyet analiz sorguları gerçekten çok güçlüdür. En çok kullandığım sorgulardan birini paylaşayım:
# Son 30 günün servis bazında maliyet dağılımı
bq query --use_legacy_sql=false
'SELECT
service.description AS service,
ROUND(SUM(cost), 2) AS total_cost,
currency
FROM
`my_project.billing_export.gcp_billing_export_v1_XXXXXX`
WHERE
DATE(_PARTITIONTIME) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
GROUP BY
service, currency
ORDER BY
total_cost DESC
LIMIT 20'
Bu sorgu size hangi GCP servisinin ne kadar harcadığını net bir şekilde gösterir. Genellikle Compute Engine, BigQuery ve Cloud Storage ilk sıralarda yer alır.
Etiket bazında maliyet dağılımını görmek için şu sorguyu kullanabilirsiniz:
# Etiket (label) bazında maliyet analizi
bq query --use_legacy_sql=false
'SELECT
labels.key AS label_key,
labels.value AS label_value,
ROUND(SUM(cost), 2) AS total_cost
FROM
`my_project.billing_export.gcp_billing_export_v1_XXXXXX`,
UNNEST(labels) AS labels
WHERE
DATE(_PARTITIONTIME) >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
GROUP BY
label_key, label_value
ORDER BY
total_cost DESC'
Bu sorgu, etiketleme stratejinizin işe yarayıp yaramadığını anlamanın en hızlı yoludur. Eğer “environment”, “team” veya “cost-center” gibi etiketleriniz yoksa ve yukarıdaki sorgu boş dönüyorsa, etiketleme stratejinizi acilen gözden geçirmeniz gerekiyor.
Budget ve Alert Yapılandırması
Maliyetleri reaktif değil, proaktif yönetmek istiyorsanız budget alertler olmazsa olmazınızdır. Terraform ile budget tanımlamak production ortamları için en sağlıklı yaklaşımdır:
# Önce Terraform provider yapılandırması
# main.tf dosyasına eklenecek budget kaynağı
cat > budget.tf << 'EOF'
resource "google_billing_budget" "production_budget" {
billing_account = var.billing_account_id
display_name = "Production Monthly Budget"
budget_filter {
projects = ["projects/${var.project_number}"]
custom_period {
start_date {
year = 2024
month = 1
day = 1
}
}
}
amount {
specified_amount {
currency_code = "USD"
units = "5000"
}
}
threshold_rules {
threshold_percent = 0.5
spend_basis = "CURRENT_SPEND"
}
threshold_rules {
threshold_percent = 0.8
spend_basis = "CURRENT_SPEND"
}
threshold_rules {
threshold_percent = 1.0
spend_basis = "CURRENT_SPEND"
}
all_updates_rule {
pubsub_topic = google_pubsub_topic.budget_alerts.id
}
}
EOF
echo "Budget Terraform konfigürasyonu oluşturuldu"
gcloud ile de budget oluşturabilirsiniz:
# gcloud ile budget oluşturma
gcloud billing budgets create
--billing-account=XXXXXX-XXXXXX-XXXXXX
--display-name="Monthly Dev Budget"
--budget-amount=1000USD
--threshold-rule=percent=50,basis=current-spend
--threshold-rule=percent=80,basis=current-spend
--threshold-rule=percent=100,basis=current-spend
--filter-projects=projects/my-dev-project
# Mevcut budget'ları listele
gcloud billing budgets list
--billing-account=XXXXXX-XXXXXX-XXXXXX
Budget alert’leri aldığınızda otomatik aksiyonlar almak için Pub/Sub ile Cloud Functions kombinasyonu kullanabilirsiniz. Örneğin bütçe %100’e ulaşınca non-production instance’ları otomatik durdurmak isteyebilirsiniz.
Compute Engine Maliyet Optimizasyonu
Compute Engine genellikle GCP faturasının en büyük kalemini oluşturur. Birkaç kritik optimizasyon yöntemini inceleyelim.
Kullanılmayan Instance’ları Tespit Etme
#!/bin/bash
# Düşük CPU kullanımlı instance'ları tespit et
# (Son 7 günde ortalama CPU < %5)
PROJECT_ID="my-project-id"
ZONE="europe-west1-b"
echo "Düşük kullanımlı instance'lar kontrol ediliyor..."
gcloud compute instances list
--project=$PROJECT_ID
--format="value(name, zone, status, machineType)" |
while read name zone status machinetype; do
if [ "$status" == "RUNNING" ]; then
# Instance'ın son 7 günlük CPU metriği
AVG_CPU=$(gcloud monitoring metrics list
--filter="metric.type=compute.googleapis.com/instance/cpu/utilization
resource.labels.instance_name=$name"
--format="value(metric.labels.instance_name)" 2>/dev/null | head -1)
echo "Instance: $name | Zone: $zone | Tip: $machinetype"
fi
done
# Durdurulmuş ama silinnmemiş instance'ları listele (boşa para!)
echo ""
echo "=== DURDURULMUŞ INSTANCE'LAR (Disk maliyeti devam ediyor) ==="
gcloud compute instances list
--project=$PROJECT_ID
--filter="status=TERMINATED"
--format="table(name, zone, status, disks[0].source)"
Committed Use Discount (CUD) Analizi
Eğer düzenli ve tahmin edilebilir workload’larınız varsa, Committed Use Discount ile ciddi tasarruf sağlayabilirsiniz. 1 yıllık commitment ile %37, 3 yıllık ile %55’e varan indirim alırsınız.
# Mevcut commitment'ları görüntüle
gcloud compute commitments list
--project=my-project-id
--format="table(name, region, status, endTimestamp, plan)"
# Yeni commitment oluştur (örnek: 1 yıl, 4 vCPU, 16GB RAM)
gcloud compute commitments create my-commitment
--project=my-project-id
--region=europe-west1
--plan=12-month
--resources=vcpu=4,memory=16GB
Preemptible ve Spot VM Kullanımı
Test, batch işlem ve CI/CD pipeline’ları için Spot VM kullanımı maliyeti %60-90 oranında düşürebilir:
# Spot VM oluşturma
gcloud compute instances create batch-processor
--project=my-project-id
--zone=europe-west1-b
--machine-type=n1-standard-4
--provisioning-model=SPOT
--instance-termination-action=STOP
--image-family=debian-11
--image-project=debian-cloud
# Mevcut instance'ı spot'a çevirme (durdurulmuş olmalı)
gcloud compute instances set-scheduling batch-processor
--project=my-project-id
--zone=europe-west1-b
--provisioning-model=SPOT
--instance-termination-action=STOP
Cloud Storage Maliyet Optimizasyonu
Storage maliyetleri sinsi bir şekilde birikir. Özellikle yıllarca biriken log dosyaları, eski backup’lar ve production’a hiç alınmamış artifact’lar ciddi maliyete yol açabilir.
#!/bin/bash
# Bucket bazında boyut ve maliyet analizi
PROJECT_ID="my-project-id"
echo "=== BUCKET ANALİZİ ==="
gsutil ls -p $PROJECT_ID | while read bucket; do
SIZE=$(gsutil du -sh $bucket 2>/dev/null | awk '{print $1}')
OBJECT_COUNT=$(gsutil ls -la $bucket 2>/dev/null | tail -1 | awk '{print $1}')
STORAGE_CLASS=$(gsutil ls -L -b $bucket 2>/dev/null | grep "Storage class" | awk '{print $3}')
echo "Bucket: $bucket"
echo " Boyut: $SIZE | Nesne sayisi: $OBJECT_COUNT | Sinif: $STORAGE_CLASS"
echo ""
done
# 30 günden eski dosyaları Nearline'a taşımak için lifecycle policy
cat > lifecycle.json << 'EOF'
{
"rule": [
{
"action": {
"type": "SetStorageClass",
"storageClass": "NEARLINE"
},
"condition": {
"age": 30,
"matchesStorageClass": ["STANDARD"]
}
},
{
"action": {
"type": "SetStorageClass",
"storageClass": "COLDLINE"
},
"condition": {
"age": 90,
"matchesStorageClass": ["NEARLINE"]
}
},
{
"action": {
"type": "Delete"
},
"condition": {
"age": 365,
"matchesStorageClass": ["COLDLINE"]
}
}
]
}
EOF
# Lifecycle policy'yi uygula
gsutil lifecycle set lifecycle.json gs://my-log-bucket
echo "Lifecycle policy uygulandı"
Storage sınıfları ve kullanım senaryoları hakkında kısa bir özet:
- Standard: Sık erişilen veriler, milisaniye gecikme
- Nearline: Ayda bir veya daha az erişilen veriler, 30 gün minimum depolama
- Coldline: Çeyrek yılda bir veya daha az erişilen veriler, 90 gün minimum
- Archive: Yılda bir veya daha az erişilen veriler, 365 gün minimum, en ucuz seçenek
Idle Kaynakların Tespiti ve Temizlenmesi
GCP ortamlarında “zombie kaynak” denilen, hiç kullanılmayan ama para ödenmeye devam edilen kaynaklar gerçek bir sorun. Bu script ile bu kaynakları tespit edebilirsiniz:
#!/bin/bash
# Idle ve orphan kaynakları tespit et
PROJECT_ID="my-project-id"
REGION="europe-west1"
echo "======================================"
echo "ORPHAN RESOURCE AUDIT - $PROJECT_ID"
echo "======================================"
# 1. Attach edilmemiş persistent diskler
echo ""
echo "--- Attach Edilmemiş Diskler (Para ödüyorsunuz!) ---"
gcloud compute disks list
--project=$PROJECT_ID
--filter="NOT users:*"
--format="table(name, zone, sizeGb, status, type)"
# 2. Kullanılmayan statik IP adresleri
echo ""
echo "--- Rezerve Edilmiş ama Kullanılmayan IP Adresleri ---"
gcloud compute addresses list
--project=$PROJECT_ID
--filter="status=RESERVED"
--format="table(name, region, address, status)"
# 3. Attach edilmemiş load balancer backend'ler
echo ""
echo "--- Boş Target Pool'lar ---"
gcloud compute target-pools list
--project=$PROJECT_ID
--format="table(name, region, instances)"
# 4. Kullanılmayan firewall kuralları
echo ""
echo "--- Hiç Hit Almayan Firewall Kuralları ---"
gcloud compute firewall-rules list
--project=$PROJECT_ID
--format="table(name, disabled, direction, priority)"
--filter="disabled=true"
# 5. Eski snapshot'lar
echo ""
echo "--- 90 Günden Eski Snapshot'lar ---"
CUTOFF_DATE=$(date -d "90 days ago" +%Y-%m-%d)
gcloud compute snapshots list
--project=$PROJECT_ID
--filter="creationTimestamp < $CUTOFF_DATE"
--format="table(name, diskSizeGb, creationTimestamp, storageBytes)"
Bu script’i bir cron job olarak haftada bir çalıştırın ve çıktısını bir Slack kanalına veya e-postaya gönderin. Birçok ekipte bu script çalıştırıldığında ilk haftada ortalama %15-20 maliyet düşüşü gözlemlendi.
Recommender API ile Otomatik Öneriler
Google’ın Recommender API’si, maliyet optimizasyonu için makine öğrenmesi tabanlı öneriler sunar. Bu önerileri programatik olarak çekmek ve uygulamak için:
# Compute Engine için maliyet önerilerini listele
gcloud recommender recommendations list
--project=my-project-id
--location=europe-west1-b
--recommender=google.compute.instance.MachineTypeRecommender
--format="table(name, description, stateInfo.state, primaryImpact.costProjection.cost.units)"
# Idle VM önerilerini kontrol et
gcloud recommender recommendations list
--project=my-project-id
--location=europe-west1-b
--recommender=google.compute.instance.IdleResourceRecommender
--format="json" | python3 -c "
import json, sys
data = json.load(sys.stdin)
for rec in data:
print(f'Öneri: {rec["description"]}')
cost = rec.get('primaryImpact', {}).get('costProjection', {})
if cost:
print(f'Tahmini tasarruf: {cost}')
print('---')
"
Recommender önerileri genellikle şu kategorilerde gelir:
- Oversized instance’lar: Kullanımınızdan büyük makine tipleri
- Idle instance’lar: Uzun süre düşük kullanımda kalan makineler
- Committed Use Discount fırsatları: Önerilen commitment miktarları
- Sosyal tipler arası geçiş: N2’den E2’ye geçiş gibi maliyet tasarrufları
Maliyet Dashboard’u Oluşturma
Ekip içinde görünürlük sağlamak için basit bir maliyet raporlama scripti hazırlamak iyi bir uygulama:
#!/bin/bash
# Haftalik maliyet raporu - email veya Slack'e gonderilebilir
PROJECT_ID="my-project-id"
BILLING_DATASET="my_project.billing_export.gcp_billing_export_v1_XXXXXX"
REPORT_FILE="/tmp/cost_report_$(date +%Y%m%d).txt"
cat > /tmp/cost_query.sql << EOF
SELECT
service.description AS service,
ROUND(SUM(cost), 2) AS weekly_cost,
currency,
COUNT(DISTINCT project.id) AS project_count
FROM `$BILLING_DATASET`
WHERE
DATE(_PARTITIONTIME) >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
AND cost > 0
GROUP BY service, currency
ORDER BY weekly_cost DESC
LIMIT 15
EOF
echo "=== HAFTALIK GCP MALİYET RAPORU ===" > $REPORT_FILE
echo "Tarih: $(date)" >> $REPORT_FILE
echo "" >> $REPORT_FILE
echo "Son 7 Gün - Servis Bazında Maliyet:" >> $REPORT_FILE
echo "-----------------------------------" >> $REPORT_FILE
bq query
--use_legacy_sql=false
--format=csv
--quiet
< /tmp/cost_query.sql >> $REPORT_FILE
echo "" >> $REPORT_FILE
echo "Not: Tam detay icin GCP Billing Console'a bakin" >> $REPORT_FILE
# Raporu Slack'e gonder (webhook URL gerekli)
if [ -n "$SLACK_WEBHOOK_URL" ]; then
REPORT_CONTENT=$(cat $REPORT_FILE)
curl -X POST -H 'Content-type: application/json'
--data "{"text": "```$REPORT_CONTENT```"}"
$SLACK_WEBHOOK_URL
fi
cat $REPORT_FILE
echo "Rapor $REPORT_FILE dosyasina kaydedildi"
Pratik Maliyet Optimizasyon Kontrol Listesi
Gerçek dünya deneyimlerimden derlediğim, uyguladığınızda anında etki göreceksiniz liste:
- Etiketleme zorunlu hale getirin: Organization Policy ile etiketsiz kaynak oluşturulmasını engelleyin
- Idle disk ve IP’leri haftalık temizleyin: Yukarıdaki audit script’ini cron’a ekleyin
- Storage lifecycle policy: Tüm log bucket’larına mutlaka uygulayın
- Dev/test ortamları için schedule: Gece 22:00 ile sabah 08:00 arası kapatın, yüzde 40’a varan tasarruf
- BigQuery slot rezervasyonu: Düzenli sorgu workload’u varsa on-demand yerine reserved capacity değerlendirin
- Recommender önerilerini takip edin: Ayda bir kontrol edin, ücretsiz ve değerli
- Committed Use: Production instance’larınız için mutlaka değerlendirin
- Cloud Run ve Cloud Functions: Sürekli çalışan küçük servisler için container instance yerine serverless tercih edin
- Artifact Registry temizliği: Eski container image’larını temizleyen retention policy ekleyin
- Network egress maliyetleri: Bölgeler arası ve internet çıkışı maliyetli, mimarinizi buna göre tasarlayın
Sonuç
GCP maliyet optimizasyonu bir kere yapıp bitirilen bir iş değil, sürekli devam eden bir pratik. En büyük hata, faturaları sadece ay sonunda kontrol etmek ve o ana kadar binlerce dolarlık gereksiz harcamaya göz yummak. Bugün yapabileceğiniz en değerli üç şey şunlar: BigQuery billing export’u aktif edin, tüm kritik projeler için budget alert kurun ve idle resource audit script’ini haftada bir çalışacak şekilde otomatize edin.
Bütçe aşımlarının büyük çoğunluğu unutulan test instance’larından, etiketsiz kaynaklardan ve storage lifecycle policy’si uygulanmamış bucket’lardan kaynaklanır. Bu yazıda paylaştığım araçlar ve script’lerle bu problemlerin büyük çoğunluğunu proaktif olarak çözebilirsiniz. Sorularınız varsa veya kendi ortamınızda farklı senaryolarla karşılaştıysanız yorumlarda paylaşın, birlikte çözelim.
