Azure Cost Management ile Bütçe Yönetimi
Bulut maliyetleri konusunda en sık duyduğum şikayet şu: “Ay sonunda fatura geldi, ne kadar geldiğini görünce gözlerimiz döndü.” Azure kullanmaya başlayan ekiplerin büyük çoğunluğu ilk birkaç ay bu sürprizle karşılaşıyor. Geliştirici bir VM açıyor, test için bir veritabanı ayağa kaldırıyor, load test sırasında otomatik ölçekleme devreye giriyor ve fatura beklenenin üç katına çıkıyor. İşte tam bu noktada Azure Cost Management devreye giriyor ve doğru yapılandırıldığında gerçekten hayat kurtarıyor.
Azure Cost Management Nedir ve Neden Önemlidir
Azure Cost Management, Microsoft’un Azure harcamalarınızı izlemenizi, analiz etmenizi ve kontrol altında tutmanızu sağlayan yerleşik servisidir. Ayrıca AWS ve Google Cloud harcamalarını da takip edebildiği için hibrit ve çoklu bulut ortamlarında çalışan ekipler için de kullanışlıdır.
Buradaki temel mantık şu: Görünmeyeni kontrol edemezsiniz. Maliyet yönetimi sadece para biriktirmekle ilgili değil, aynı zamanda hangi kaynakların ne kadar harcadığını anlamakla, bu harcamaların iş gereksinimlerine uygun olup olmadığını sorgulamakla ve anormal harcamaları erken tespit etmekle ilgilidir.
Sysadmin olarak bizi ilgilendiren kısımlar özellikle şunlar:
- Bütçe limitleri belirlemek ve aşıldığında uyarı almak
- Kaynak bazında maliyet analizi yapmak
- Otomatik aksiyonlar (örneğin belirli limiti geçince VM’leri durdurmak) tanımlamak
- Tag stratejisiyle maliyetleri ekip veya proje bazında raporlamak
Temel Kavramlar
Scope (Kapsam) Nedir
Azure Cost Management’ta her şey scope kavramı üzerine kurulu. Hangi seviyede maliyet takibi yapacağınızı belirlemeniz gerekiyor. Scope seçenekleri şunlar:
- Management Group: Birden fazla subscription’ı kapsayan en üst seviye
- Subscription: Tek bir Azure aboneliği
- Resource Group: Belirli bir kaynak grubu
- Resource: Tek bir Azure kaynağı
Küçük bir ekipseniz subscription seviyesi genellikle yeterli. Büyük organizasyonlarda her departmanın ayrı resource group’u varsa, o seviyede bütçe tanımlamak daha mantıklı oluyor.
Budget vs Alert Farkı
Bütçe, harcamak istediğiniz maksimum miktarı tanımlar. Alert ise bu bütçenin belirli bir yüzdesine ulaşıldığında sizi haberdar eden mekanizmadır. Bütçe tanımlamak tek başına harcamaları durdurmaz, sadece izler ve bildirir. Harcamaları otomatik durdurmak için Action Group ve Automation entegrasyonu gereklidir.
Azure CLI ile Cost Management Kurulumu
Teoriden pratiğe geçelim. Azure CLI kullanarak adım adım bütçe ve alert yapılandırması yapacağız. Önce CLI’ın güncel ve giriş yapılmış olduğundan emin olun:
# Azure CLI versiyonunu kontrol et
az --version
# Azure hesabına giriş yap
az login
# Mevcut subscription'ları listele
az account list --output table
# Çalışacağınız subscription'ı ayarla
az account set --subscription "subscription-id-buraya"
İlk Bütçeyi Oluşturmak
Subscription seviyesinde aylık 1000 USD’lik bir bütçe oluşturalım. Bu bütçe, %80 ve %100 eşiklerinde email bildirimi gönderecek:
# Subscription ID'yi değişkene al
SUBSCRIPTION_ID=$(az account show --query id --output tsv)
# Bütçe oluştur
az consumption budget create
--budget-name "monthly-prod-budget"
--amount 1000
--time-grain Monthly
--start-date "2024-01-01"
--end-date "2025-12-31"
--category Cost
--notifications
"enabled=true threshold=80 operator=GreaterThan contactEmails=['[email protected]','[email protected]'] contactRoles=['Owner']"
--subscription $SUBSCRIPTION_ID
Resource group seviyesinde bütçe tanımlamak istiyorsanız:
# Resource group bazlı bütçe
az consumption budget create
--budget-name "rg-dev-monthly-budget"
--amount 300
--time-grain Monthly
--start-date "2024-01-01"
--end-date "2025-12-31"
--category Cost
--resource-group "rg-development"
--notifications
"enabled=true threshold=50 operator=GreaterThan contactEmails=['[email protected]']"
"enabled=true threshold=90 operator=GreaterThan contactEmails=['[email protected]','[email protected]']"
Mevcut Bütçeleri Listelemek ve İncelemek
# Tüm bütçeleri listele
az consumption budget list --output table
# Belirli bir bütçenin detaylarını gör
az consumption budget show
--budget-name "monthly-prod-budget"
--output json
# Bütçeyi sil (gerekirse)
az consumption budget delete
--budget-name "eski-butce"
PowerShell ile İleri Seviye Bütçe Yönetimi
Bazı senaryolarda PowerShell daha güçlü bir araç haline geliyor. Özellikle birden fazla resource group için toplu bütçe oluşturmak gerektiğinde:
# Az modülünü yükle ve bağlan
Install-Module -Name Az -AllowClobber -Scope CurrentUser
Connect-AzAccount
# Tüm resource group'ları çek
$resourceGroups = Get-AzResourceGroup
# Her resource group için otomatik bütçe oluştur
foreach ($rg in $resourceGroups) {
$budgetName = "budget-$($rg.ResourceGroupName)"
# Bütçe mevcut mu kontrol et
$existingBudget = Get-AzConsumptionBudget -Name $budgetName -ErrorAction SilentlyContinue
if (-not $existingBudget) {
# Notification nesnesi oluştur
$notification = New-AzConsumptionBudgetNotification `
-NotificationKey "Alert80" `
-Threshold 80 `
-Operator GreaterThan `
-Enabled $true `
-ContactEmail @("[email protected]") `
-ContactRole @("Owner", "Contributor")
# Bütçeyi oluştur
New-AzConsumptionBudget `
-Name $budgetName `
-Amount 500 `
-StartDate (Get-Date -Day 1 -Hour 0 -Minute 0 -Second 0) `
-EndDate (Get-Date).AddYears(1) `
-TimeGrain Monthly `
-Notification @{Alert80 = $notification} `
-ResourceGroupName $rg.ResourceGroupName
Write-Host "Butce olusturuldu: $budgetName" -ForegroundColor Green
} else {
Write-Host "Butce zaten mevcut: $budgetName" -ForegroundColor Yellow
}
}
Maliyet Analizi ve Raporlama
Bütçe oluşturmak güzel, ama asıl değer maliyet verilerini analiz etmekten geliyor. Azure CLI ile maliyet sorgulama yapalım:
# Son 30 günün harcamalarını kaynak bazında getir
az costmanagement query
--type Usage
--scope "/subscriptions/$SUBSCRIPTION_ID"
--timeframe MonthToDate
--dataset-granularity Daily
--dataset-aggregation "{'totalCost': {'name': 'Cost', 'function': 'Sum'}}"
--dataset-grouping "name=ResourceType,type=Dimension"
--output table
# Belirli bir tarih aralığı için harcama raporu
az costmanagement query
--type Usage
--scope "/subscriptions/$SUBSCRIPTION_ID"
--timeframe Custom
--time-period from="2024-01-01T00:00:00" to="2024-01-31T23:59:59"
--dataset-granularity Monthly
--dataset-aggregation "{'totalCost': {'name': 'Cost', 'function': 'Sum'}}"
--dataset-grouping "name=ServiceName,type=Dimension"
--output json
Tag Stratejisi ile Maliyet Takibi
Bu kısım gerçekten kritik. Tag’ler olmadan maliyet takibi yapmaya çalışmak, karanlıkta yürümeye benziyor. Her kaynağa anlamlı tag’ler ekleyerek hangi projenin, hangi ekibin, hangi ortamın ne kadar harcadığını görebilirsiniz.
Önerdiğim minimum tag seti şu şekilde olmalı:
- Environment: prod, staging, dev, test
- Project: proje kodu veya adı
- Team: ekip adı veya kodu
- Owner: sorumlu kişinin email adresi
- CostCenter: muhasebe merkezi kodu
Tag’leri toplu olarak uygulamak için:
# Belirli bir resource group'taki tüm kaynaklara tag ekle
RESOURCE_GROUP="rg-production"
# Resource group'taki tüm kaynak ID'lerini al
RESOURCE_IDS=$(az resource list
--resource-group $RESOURCE_GROUP
--query "[].id"
--output tsv)
# Her kaynağa tag ekle
for RESOURCE_ID in $RESOURCE_IDS; do
az tag update
--resource-id "$RESOURCE_ID"
--operation Merge
--tags
Environment=prod
Project=ecommerce
Team=platform
CostCenter=CC-001
echo "Tag eklendi: $RESOURCE_ID"
done
# Resource group'un kendisine de tag ekle
az group update
--name $RESOURCE_GROUP
--tags
Environment=prod
Project=ecommerce
Team=platform
CostCenter=CC-001
Otomatik Aksiyon: Bütçe Aşımında VM’leri Durdur
İşte en heyecan verici kısım burası. Bütçe aşıldığında sadece email almak yeterli değil, bazı senaryolarda otomatik olarak kaynakları durdurmak gerekiyor. Bunun için Azure Automation Account ve Action Group birlikteliği kullanıyoruz.
Önce bir Automation Account oluşturup, bütçe alert’i tetiklendiğinde çalışacak runbook yazalım:
# Automation Account oluştur
az automation account create
--automation-account-name "cost-automation"
--location "westeurope"
--resource-group "rg-management"
--sku Basic
# System-assigned managed identity'yi etkinleştir
az automation account identity assign
--automation-account-name "cost-automation"
--resource-group "rg-management"
# Managed identity'ye Contributor rolü ver
AUTOMATION_IDENTITY=$(az automation account show
--automation-account-name "cost-automation"
--resource-group "rg-management"
--query "identity.principalId"
--output tsv)
az role assignment create
--assignee $AUTOMATION_IDENTITY
--role "Contributor"
--scope "/subscriptions/$SUBSCRIPTION_ID"
Şimdi VM’leri durduracak PowerShell runbook’u oluşturalım:
# Bu kodu bir .ps1 dosyasına kaydet: Stop-DevVMs.ps1
param(
[string]$ResourceGroupName = "rg-development",
[string]$TagKey = "Environment",
[string]$TagValue = "dev"
)
# Managed Identity ile bağlan
Connect-AzAccount -Identity
Write-Output "Maliyet limiti asimi tespit edildi. Dev VM'leri durduruluyor..."
# Tag'e göre çalışan VM'leri bul
$runningVMs = Get-AzVM -ResourceGroupName $ResourceGroupName -Status |
Where-Object {
$_.Tags[$TagKey] -eq $TagValue -and
$_.Statuses[1].Code -eq "PowerState/running"
}
if ($runningVMs.Count -eq 0) {
Write-Output "Durdurulacak VM bulunamadi."
exit
}
foreach ($vm in $runningVMs) {
Write-Output "VM durduruluyor: $($vm.Name)"
Stop-AzVM -ResourceGroupName $ResourceGroupName `
-Name $vm.Name `
-Force `
-NoWait
Write-Output "Durdurma komutu gonderildi: $($vm.Name)"
}
Write-Output "Toplam $($runningVMs.Count) VM icin durdurma islemi basladi."
# Sonuclari Teams webhook ile bildir (opsiyonel)
$teamsWebhookUrl = "https://sirket.webhook.office.com/webhookb2/xxxxx"
$message = @{
text = "UYARI: Butce limiti asildi! $($runningVMs.Count) adet dev VM durduruldu."
} | ConvertTo-Json
Invoke-RestMethod -Method Post -Uri $teamsWebhookUrl -Body $message -ContentType "application/json"
Gerçek Dünya Senaryosu: E-ticaret Şirketinin Maliyet Krizi
Bir e-ticaret şirketinde yaşanan gerçek bir senaryoyu ele alalım. Şirketin Azure ortamında production, staging ve development ortamları mevcut. Her ay fatura 8000-10000 USD arasında seyrediyor ve kimse tam olarak neden bu kadar geldiğini bilmiyor.
Yaptığımız analiz şunları ortaya çıkardı:
- Development VM’leri hafta sonları da çalışıyor (kimse kapatmıyor)
- Staging ortamında production’a eşdeğer boyutlarda VM’ler kullanılıyor
- Bir yıl önce oluşturulan ve artık kullanılmayan 5 adet managed disk faturalanmaya devam ediyor
- Log Analytics workspace’i gereksiz yere uzun retention süresiyle yapılandırılmış
Bu tespitlerin ardından uyguladığımız çözüm:
# Kullanılmayan managed disk'leri bul
az disk list
--query "[?diskState=='Unattached'].{Name:name, Size:diskSizeGb, SKU:sku.name, RG:resourceGroup}"
--output table
# Kullanılmayan public IP'leri bul
az network public-ip list
--query "[?ipAddress==null].{Name:name, RG:resourceGroup}"
--output table
# Boyutu büyük ama CPU kullanımı düşük VM'leri tespit et (son 7 gün)
az monitor metrics list
--resource "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/rg-staging/providers/Microsoft.Compute/virtualMachines/staging-app-vm"
--metric "Percentage CPU"
--interval PT1H
--start-time 2024-01-01T00:00:00Z
--end-time 2024-01-07T00:00:00Z
--aggregation Average
--output table
Bu analizler sonucunda aylık maliyet 8000-10000 USD’den 4500-5000 USD’ye düştü. Yaklaşık %45 tasarruf.
Cost Anomaly Detection ile Anormal Harcamaları Yakalamak
Azure’un yerleşik anomaly detection özelliği, alışılmışın dışında harcama patikalarını otomatik olarak tespit ediyor. Bu özelliği CLI ile yönetmek mümkün:
# Anomaly alert ayarla
az costmanagement alert create
--scope "/subscriptions/$SUBSCRIPTION_ID"
--alert-type Budget
--definition-type Actual
--details "role=Owner,[email protected],message=Anormal harcama tespit edildi"
# Mevcut anomaly'leri listele
az costmanagement alert list
--scope "/subscriptions/$SUBSCRIPTION_ID"
--output table
Anomaly detection için dikkat edilmesi gereken noktalar:
- Sensitivity: Yüksek hassasiyet daha fazla false positive üretir, düşük hassasiyet önemli anomalileri kaçırabilir
- Lookback period: Azure genellikle son 30-60 günlük veriyi baz alır
- Weekend/Holiday patterns: Hafta sonu düşen trafiği anomaly olarak algılamaması için baseline doğru kurgulanmalı
Advisor Önerileri ile Maliyet Optimizasyonu
Azure Advisor, maliyet optimizasyonu için otomatik öneriler sunuyor. Bu önerileri CLI ile çekmek ve aksiyona geçirmek mümkün:
# Cost kategorisindeki Advisor önerilerini listele
az advisor recommendation list
--category Cost
--output table
# Önerilerin özetini gör
az advisor recommendation list
--category Cost
--query "[].{Problem:shortDescription.problem, Impact:impact, Savings:extendedProperties.annualSavingsAmount}"
--output table
# Belirli bir öneriyi ertelemek veya reddetmek
RECOMMENDATION_ID="öneri-id-buraya"
az advisor recommendation disable
--ids $RECOMMENDATION_ID
--days 30
Advisor’ın en sık önerdiği şeyler:
- Kullanılmayan veya az kullanılan VM’ler için boyut küçültme
- Reserved Instance satın alımı (1 veya 3 yıllık taahhüt ile %40-72 tasarruf)
- Unattached managed disk’lerin silinmesi
- Eski snapshot’ların temizlenmesi
- Kullanılmayan App Service planlarının kaldırılması
Maliyet Raporlarını Otomatik Email ile Göndermek
Haftalık veya aylık maliyet raporunu otomatik olarak ilgili kişilere göndermek için basit bir betik yazalım:
#!/bin/bash
# weekly-cost-report.sh
SUBSCRIPTION_ID=$(az account show --query id --output tsv)
REPORT_DATE=$(date +%Y-%m-%d)
START_DATE=$(date -d "7 days ago" +%Y-%m-%d)T00:00:00
END_DATE=$(date +%Y-%m-%d)T23:59:59
REPORT_FILE="/tmp/cost-report-$REPORT_DATE.json"
echo "Haftalik maliyet raporu olusturuluyor: $REPORT_DATE"
# Servis bazlı maliyet verisi cek
az costmanagement query
--type Usage
--scope "/subscriptions/$SUBSCRIPTION_ID"
--timeframe Custom
--time-period from="$START_DATE" to="$END_DATE"
--dataset-granularity None
--dataset-aggregation '{"totalCost": {"name": "Cost", "function": "Sum"}}'
--dataset-grouping '{"name": "ServiceName", "type": "Dimension"}'
--output json > $REPORT_FILE
# Toplam maliyeti hesapla
TOTAL_COST=$(cat $REPORT_FILE | jq '[.properties.rows[] | .[0]] | add | . * 100 | round / 100')
echo "Haftalik toplam maliyet: $TOTAL_COST USD"
# Raporu log'a yaz
echo "[$REPORT_DATE] Haftalik maliyet: $TOTAL_COST USD" >> /var/log/azure-cost-report.log
# Yuksek maliyet uyarisi
THRESHOLD=2000
if (( $(echo "$TOTAL_COST > $THRESHOLD" | bc -l) )); then
echo "UYARI: Haftalik maliyet $THRESHOLD USD'yi asti! Mevcut: $TOTAL_COST USD"
# Buraya email veya Slack bildirimi eklenebilir
fi
# Raporu temizle
rm -f $REPORT_FILE
echo "Rapor tamamlandi."
Bu betiği cron’a ekleyin:
# Her Pazartesi sabah 08:00'de çalışsın
echo "0 8 * * 1 /opt/scripts/weekly-cost-report.sh >> /var/log/cost-report-cron.log 2>&1" | crontab -
Sık Yapılan Hatalar ve Çözümleri
Yıllar içinde gördüğüm en yaygın maliyet yönetimi hataları:
- Bütçe oluşturmak yeterli sanmak: Bütçe tek başına harcamaları durdurmaz. Alert + otomatik aksiyon kombinasyonu şart.
- Tag stratejisini ertelemek: “İleride ekleriz” deniyor ama hiç eklenmiyor. Kaynak oluşturma politikalarıyla tag’leri zorunlu hale getirin.
- Sadece toplam maliyete bakmak: Servis bazında, kaynak grubu bazında ve tag bazında kırılım olmadan optimization yapamazsınız.
- Reserved Instance fırsatını kaçırmak: Bir yıldan uzun süre çalışacak VM’ler için Reserved Instance büyük tasarruf sağlar ama çoğu ekip bunu ihmal ediyor.
- Development ortamlarını 7/24 çalıştırmak: Geliştirici mesai saatleri dışında VM’lere para ödemek gereksiz. Otomatik shutdown politikaları kurun.
Sonuç
Azure Cost Management, doğru yapılandırıldığında bulut harcamalarınızı tahmin edilebilir ve kontrol edilebilir hale getirir. Ancak bu bir araç olduğu kadar bir kültür meselesidir. Ekibin maliyet farkındalığına sahip olması, her kaynağın bir bedeli olduğunu bilmesi ve bu bilgiyle hareket etmesi gerekiyor.
Başlangıç için önerim şu: Önce mevcut harcamaları servis ve kaynak bazında analiz edin. Ardından mantıklı tag stratejisi belirleyin ve tüm ortamlara uygulayın. Sonra her ortam için ayrı bütçe tanımlayın. Son olarak anomaly detection’ı etkinleştirin ve haftalık raporları otomatize edin.
Bu adımları tamamladıktan sonra genellikle ilk bir ay içinde %20-30 tasarruf sağlanabiliyor. Bunun ötesine geçmek için Reserved Instance, Spot VM kullanımı ve uygulama mimarisindeki optimizasyonlar devreye giriyor. Ama o konular ayrı bir yazı konusu.
Maliyet yönetimi bir sprint işi değil, sürekli bir süreçtir. Aylık gözden geçirmeler, ekiple paylaşılan raporlar ve otomatik uyarılar bu süreci sürdürülebilir hale getirir.
