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.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir