AWS Billing ve Bütçe Alarmı Kurulumu

AWS hesabınızı açtığınız ilk günden itibaren faturanızı takip etmek, cloud yönetiminin en kritik parçalarından biridir. “Ben sadece test için bir şeyler deniyorum” diye düşünürken, unutulan bir EC2 instance veya yanlış yapılandırılmış bir S3 bucket sizi ciddi para kaybına uğratabilir. Bu yazıda AWS Billing yapılandırmasını, bütçe alarmlarını ve maliyet optimizasyonu için gerekli tüm araçları adım adım ele alacağız.

AWS Billing Temellerine Giriş

AWS, kullandıkça öde modeliyle çalışır. Bu model güzel bir şey gibi görünse de yönetilmezse kolayca kontrolden çıkabilir. AWS Billing konsoluna girmeden önce, hesabınızda birkaç temel ayarı aktif etmeniz gerekiyor.

Cost Allocation Tags etkinleştirilmezse, hangi ekibin veya projenin ne kadar harcadığını asla bilemezsiniz. Cost Explorer aktif edilmezse geçmiş harcamalarınızı analiz edemezsiniz. Billing Alerts kurulmadan bir sabah uyanıp beklenmedik bir fatura ile karşılaşabilirsiniz.

IAM Kullanıcılarına Billing Erişimi Verme

Root hesabı kullanarak billing’e erişmek kötü bir pratiktir. Önce IAM kullanıcılarının billing sayfasına erişebilmesi için root hesaptan şu ayarı yapmanız gerekiyor:

# AWS CLI ile billing erişimini kontrol etme
aws iam get-account-summary --query 'SummaryMap.AccountMFAEnabled'

# Root hesapla yapılması gereken bu ayar CLI ile değil, console üzerinden yapılır:
# AWS Console > Account > IAM User and Role Access to Billing Information > Edit > Activate

IAM politikası oluşturmak için:

# billing-policy.json dosyası oluşturun
cat > billing-policy.json << 'EOF'
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "aws-portal:ViewBilling",
                "aws-portal:ViewUsage",
                "budgets:ViewBudget",
                "budgets:ModifyBudget",
                "ce:GetCostAndUsage",
                "ce:GetCostForecast",
                "ce:DescribeCostCategoryDefinition"
            ],
            "Resource": "*"
        }
    ]
}
EOF

# Politikayı oluştur
aws iam create-policy 
    --policy-name BillingReadWritePolicy 
    --policy-document file://billing-policy.json 
    --description "Billing ve budget yonetim politikasi"

CloudWatch ile Billing Alarm Kurulumu

AWS’nin en temel maliyet uyarı yöntemi CloudWatch Billing Alarms’tır. Ancak dikkat: Bu alarmlar sadece us-east-1 (N. Virginia) region’ında çalışır. Alarm kurarken mutlaka bu region’ı seçin.

CloudWatch Billing Alarmı Oluşturma

# Önce SNS topic oluşturun (email bildirimi için)
aws sns create-topic 
    --name billing-alarm-topic 
    --region us-east-1

# Topic'e email subscribe edin
aws sns subscribe 
    --topic-arn arn:aws:sns:us-east-1:123456789012:billing-alarm-topic 
    --protocol email 
    --notification-endpoint [email protected] 
    --region us-east-1

# $50 eşiği için CloudWatch Billing Alarm oluşturun
aws cloudwatch put-metric-alarm 
    --alarm-name "BillingAlarm-50USD" 
    --alarm-description "Fatura 50 USD esigini asti" 
    --metric-name EstimatedCharges 
    --namespace AWS/Billing 
    --statistic Maximum 
    --period 86400 
    --threshold 50 
    --comparison-operator GreaterThanOrEqualToThreshold 
    --dimensions Name=Currency,Value=USD 
    --evaluation-periods 1 
    --alarm-actions arn:aws:sns:us-east-1:123456789012:billing-alarm-topic 
    --treat-missing-data notBreaching 
    --region us-east-1

Bu alarm günde bir kez kontrol eder ve tahmini ücretler 50 USD’yi aştığında email gönderir. Ancak CloudWatch Billing Alarms oldukça basit bir çözümdür. Gerçek dünya senaryolarında AWS Budgets kullanmak çok daha sağlıklıdır.

AWS Budgets ile Gelişmiş Bütçe Yönetimi

AWS Budgets, CloudWatch’a göre çok daha esnek ve detaylı bir bütçe yönetim aracıdır. Servis bazında, proje bazında, hatta belirli tag’lere göre bütçe tanımlayabilirsiniz.

Basit Maliyet Bütçesi Oluşturma

# monthly-budget.json dosyası oluşturun
cat > monthly-budget.json << 'EOF'
{
    "BudgetName": "MonthlyTotalBudget",
    "BudgetLimit": {
        "Amount": "200",
        "Unit": "USD"
    },
    "TimeUnit": "MONTHLY",
    "BudgetType": "COST",
    "CostFilters": {},
    "CostTypes": {
        "IncludeTax": true,
        "IncludeSubscription": true,
        "UseBlended": false,
        "IncludeRefund": false,
        "IncludeCredit": false,
        "IncludeUpfront": true,
        "IncludeRecurring": true,
        "IncludeOtherSubscription": true,
        "IncludeSupport": true,
        "IncludeDiscount": true,
        "UseAmortized": false
    }
}
EOF

# Bütçeyi oluşturun
aws budgets create-budget 
    --account-id 123456789012 
    --budget file://monthly-budget.json

Bütçe Bildirimi Ekleme

Bütçeyi oluşturduktan sonra bildirim kurallarını ayrıca eklemeniz gerekiyor:

# Bütçenin %80'ine ulaşıldığında uyarı
aws budgets create-notification 
    --account-id 123456789012 
    --budget-name "MonthlyTotalBudget" 
    --notification '{
        "NotificationType": "ACTUAL",
        "ComparisonOperator": "GREATER_THAN",
        "Threshold": 80,
        "ThresholdType": "PERCENTAGE",
        "NotificationState": "ALARM"
    }' 
    --subscribers '[
        {
            "SubscriptionType": "EMAIL",
            "Address": "[email protected]"
        }
    ]'

# Bütçenin %100'üne ulaşıldığında uyarı
aws budgets create-notification 
    --account-id 123456789012 
    --budget-name "MonthlyTotalBudget" 
    --notification '{
        "NotificationType": "ACTUAL",
        "ComparisonOperator": "GREATER_THAN",
        "Threshold": 100,
        "ThresholdType": "PERCENTAGE",
        "NotificationState": "ALARM"
    }' 
    --subscribers '[
        {
            "SubscriptionType": "EMAIL",
            "Address": "[email protected]"
        },
        {
            "SubscriptionType": "SNS",
            "Address": "arn:aws:sns:us-east-1:123456789012:billing-alarm-topic"
        }
    ]'

Servis Bazında Bütçe Tanımlama

Gerçek dünya senaryolarında tek bir genel bütçe yeterli değildir. EC2 için ayrı, RDS için ayrı, S3 için ayrı bütçeler tanımlamanız gerekebilir. Özellikle büyük ekiplerde her servisin kendi bütçesi olması, hangi alanın şiştiğini hızlıca görmenizi sağlar.

# EC2 için özel bütçe
cat > ec2-budget.json << 'EOF'
{
    "BudgetName": "EC2-Monthly-Budget",
    "BudgetLimit": {
        "Amount": "100",
        "Unit": "USD"
    },
    "TimeUnit": "MONTHLY",
    "BudgetType": "COST",
    "CostFilters": {
        "Service": ["Amazon Elastic Compute Cloud - Compute"]
    },
    "CostTypes": {
        "IncludeTax": false,
        "IncludeSubscription": true,
        "UseBlended": false,
        "IncludeRefund": false,
        "IncludeCredit": false,
        "IncludeUpfront": true,
        "IncludeRecurring": true,
        "IncludeOtherSubscription": true,
        "IncludeSupport": false,
        "IncludeDiscount": true,
        "UseAmortized": false
    }
}
EOF

aws budgets create-budget 
    --account-id 123456789012 
    --budget file://ec2-budget.json

Cost Allocation Tags ile Proje Bazında Takip

Tags olmadan maliyet takibi yapmak, gözlerinizi kapatarak araba sürmek gibidir. Her kaynağa mutlaka anlamlı tag’ler eklemelisiniz.

# Mevcut EC2 instance'larına tag ekleme
aws ec2 create-tags 
    --resources i-0123456789abcdef0 
    --tags 
        Key=Project,Value=backend-api 
        Key=Environment,Value=production 
        Key=Team,Value=devops 
        Key=CostCenter,Value=engineering

# Tag bazlı bütçe için
cat > project-budget.json << 'EOF'
{
    "BudgetName": "BackendAPI-Project-Budget",
    "BudgetLimit": {
        "Amount": "150",
        "Unit": "USD"
    },
    "TimeUnit": "MONTHLY",
    "BudgetType": "COST",
    "CostFilters": {
        "TagKeyValue": ["user:Project$backend-api"]
    },
    "CostTypes": {
        "IncludeTax": true,
        "IncludeSubscription": true,
        "UseBlended": false,
        "IncludeRefund": false,
        "IncludeCredit": false,
        "IncludeUpfront": true,
        "IncludeRecurring": true,
        "IncludeOtherSubscription": true,
        "IncludeSupport": true,
        "IncludeDiscount": true,
        "UseAmortized": false
    }
}
EOF

aws budgets create-budget 
    --account-id 123456789012 
    --budget file://project-budget.json

Önemli not: Tag bazlı filtreleme için önce AWS Cost Management konsolundan Cost Allocation Tags bölümüne gidip kullandığınız tag key’lerini aktif etmeniz gerekiyor. Bu olmadan tag filtreleri çalışmaz.

Lambda ile Otomatik Maliyet Kontrolü

Sadece alarm almak yetmez, bazen otomatik aksiyon da almanız gerekebilir. Bütçe aşıldığında belirli instance’ları durdurmak veya ekibinize Slack bildirimi göndermek için Lambda kullanabilirsiniz.

# Lambda fonksiyonu için IAM role oluşturun
cat > lambda-trust-policy.json << 'EOF'
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "lambda.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
EOF

aws iam create-role 
    --role-name BudgetAlarmLambdaRole 
    --assume-role-policy-document file://lambda-trust-policy.json

# Gerekli policy'leri attach edin
aws iam attach-role-policy 
    --role-name BudgetAlarmLambdaRole 
    --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

aws iam attach-role-policy 
    --role-name BudgetAlarmLambdaRole 
    --policy-arn arn:aws:iam::aws:policy/AmazonEC2FullAccess

Lambda fonksiyon kodu (Python):

# lambda_function.py dosyasını oluşturun
cat > lambda_function.py << 'PYEOF'
import boto3
import json
import os
import urllib3

def lambda_handler(event, context):
    """
    SNS üzerinden gelen Budget alarm mesajını işler
    ve ilgili aksiyonları alır
    """
    
    # SNS mesajını parse et
    message = json.loads(event['Records'][0]['Sns']['Message'])
    budget_name = message.get('budgetName', 'Bilinmiyor')
    actual_spend = message.get('actualSpend', {}).get('amount', '0')
    budget_limit = message.get('budgetedAmount', {}).get('amount', '0')
    
    print(f"Budget alarmı tetiklendi: {budget_name}")
    print(f"Mevcut harcama: {actual_spend} USD / Limit: {budget_limit} USD")
    
    # Slack webhook URL'si environment variable'dan al
    slack_webhook_url = os.environ.get('SLACK_WEBHOOK_URL')
    
    if slack_webhook_url:
        slack_message = {
            "text": f"*AWS Bütçe Uyarısı!*",
            "attachments": [
                {
                    "color": "danger",
                    "fields": [
                        {
                            "title": "Bütçe",
                            "value": budget_name,
                            "short": True
                        },
                        {
                            "title": "Harcama / Limit",
                            "value": f"{actual_spend} / {budget_limit} USD",
                            "short": True
                        }
                    ]
                }
            ]
        }
        
        http = urllib3.PoolManager()
        response = http.request(
            'POST',
            slack_webhook_url,
            body=json.dumps(slack_message).encode('utf-8'),
            headers={'Content-Type': 'application/json'}
        )
        print(f"Slack bildirimi gönderildi: {response.status}")
    
    # Dev environment instance'larını durdur (isteğe bağlı)
    if "production" not in budget_name.lower():
        stop_dev_instances()
    
    return {'statusCode': 200, 'body': 'Alarm işlendi'}

def stop_dev_instances():
    """Development tagged instance'ları durdurur"""
    ec2 = boto3.client('ec2', region_name='eu-west-1')
    
    # Environment=dev tagged ve running instance'ları bul
    response = ec2.describe_instances(
        Filters=[
            {'Name': 'tag:Environment', 'Values': ['dev', 'development']},
            {'Name': 'instance-state-name', 'Values': ['running']}
        ]
    )
    
    instance_ids = []
    for reservation in response['Reservations']:
        for instance in reservation['Instances']:
            instance_ids.append(instance['InstanceId'])
    
    if instance_ids:
        ec2.stop_instances(InstanceIds=instance_ids)
        print(f"Durdurulan instance'lar: {instance_ids}")
    else:
        print("Durdurulacak dev instance bulunamadı")

PYEOF

# Lambda deployment package oluşturun
zip lambda_deployment.zip lambda_function.py

# Lambda fonksiyonunu deploy edin
aws lambda create-function 
    --function-name BudgetAlarmHandler 
    --runtime python3.11 
    --role arn:aws:iam::123456789012:role/BudgetAlarmLambdaRole 
    --handler lambda_function.lambda_handler 
    --zip-file fileb://lambda_deployment.zip 
    --environment Variables="{SLACK_WEBHOOK_URL=https://hooks.slack.com/services/XXX/YYY/ZZZ}" 
    --timeout 30 
    --region us-east-1

Cost Explorer ile Maliyet Analizi

Otomatik raporlama için Cost Explorer API’sini kullanabilirsiniz. Bu script ile aylık maliyet raporunu otomatik olarak alabilirsiniz:

# Aylık servis bazında maliyet raporu
aws ce get-cost-and-usage 
    --time-period Start=2024-01-01,End=2024-01-31 
    --granularity MONTHLY 
    --metrics "BlendedCost" "UsageQuantity" 
    --group-by Type=DIMENSION,Key=SERVICE 
    --query 'ResultsByTime[0].Groups[*].{Servis: Keys[0], Maliyet: Metrics.BlendedCost.Amount}' 
    --output table

# Günlük maliyet trendi (son 7 gün)
aws ce get-cost-and-usage 
    --time-period Start=$(date -d '7 days ago' +%Y-%m-%d),End=$(date +%Y-%m-%d) 
    --granularity DAILY 
    --metrics "UnblendedCost" 
    --query 'ResultsByTime[*].{Tarih: TimePeriod.Start, Maliyet: Total.UnblendedCost.Amount}' 
    --output table

Gerçek Dünya Senaryosu: Startup Ortamı

Diyelim ki 5 kişilik bir startup’ta sysadmin olarak çalışıyorsunuz. Production, staging ve dev ortamlarınız var. Her ay 500 USD bütçeniz var. İşte bu senaryo için pratik bir yapılandırma:

#!/bin/bash
# setup-billing-alerts.sh

ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
EMAIL="[email protected]"
REGION="us-east-1"

echo "Hesap ID: $ACCOUNT_ID"
echo "Billing alarm kurulumu başlıyor..."

# 1. SNS Topic oluştur
TOPIC_ARN=$(aws sns create-topic 
    --name billing-alerts 
    --region $REGION 
    --query TopicArn 
    --output text)

echo "SNS Topic: $TOPIC_ARN"

# 2. Email subscribe
aws sns subscribe 
    --topic-arn $TOPIC_ARN 
    --protocol email 
    --notification-endpoint $EMAIL 
    --region $REGION

# 3. Genel aylık bütçe (%80 = 400 USD, %100 = 500 USD)
aws budgets create-budget 
    --account-id $ACCOUNT_ID 
    --budget '{
        "BudgetName": "Startup-Monthly-500USD",
        "BudgetLimit": {"Amount": "500", "Unit": "USD"},
        "TimeUnit": "MONTHLY",
        "BudgetType": "COST",
        "CostTypes": {
            "IncludeTax": true,
            "IncludeSubscription": true,
            "UseBlended": false,
            "IncludeRefund": false,
            "IncludeCredit": false,
            "IncludeUpfront": true,
            "IncludeRecurring": true,
            "IncludeOtherSubscription": true,
            "IncludeSupport": true,
            "IncludeDiscount": true,
            "UseAmortized": false
        }
    }'

# 4. %80 uyarısı
aws budgets create-notification 
    --account-id $ACCOUNT_ID 
    --budget-name "Startup-Monthly-500USD" 
    --notification '{
        "NotificationType": "ACTUAL",
        "ComparisonOperator": "GREATER_THAN",
        "Threshold": 80,
        "ThresholdType": "PERCENTAGE",
        "NotificationState": "ALARM"
    }' 
    --subscribers "[{"SubscriptionType":"EMAIL","Address":"$EMAIL"}]"

# 5. %100 uyarısı
aws budgets create-notification 
    --account-id $ACCOUNT_ID 
    --budget-name "Startup-Monthly-500USD" 
    --notification '{
        "NotificationType": "ACTUAL",
        "ComparisonOperator": "GREATER_THAN",
        "Threshold": 100,
        "ThresholdType": "PERCENTAGE",
        "NotificationState": "ALARM"
    }' 
    --subscribers "[{"SubscriptionType":"EMAIL","Address":"$EMAIL"},{"SubscriptionType":"SNS","Address":"$TOPIC_ARN"}]"

# 6. Tahmin bazlı uyarı (ay sonu tahmini bütçeyi asacaksa)
aws budgets create-notification 
    --account-id $ACCOUNT_ID 
    --budget-name "Startup-Monthly-500USD" 
    --notification '{
        "NotificationType": "FORECASTED",
        "ComparisonOperator": "GREATER_THAN",
        "Threshold": 90,
        "ThresholdType": "PERCENTAGE",
        "NotificationState": "ALARM"
    }' 
    --subscribers "[{"SubscriptionType":"EMAIL","Address":"$EMAIL"}]"

echo "Billing alarm kurulumu tamamlandı!"
echo "Lütfen $EMAIL adresini doğrulamak için email kutunuzu kontrol edin."

Bu scripti çalıştırın ve SNS subscription onay mailini unutmayın. Onaylamadan bildirimler gelmez ve bunu ancak alarm tetiklendiğinde fark edersiniz, bu da oldukça can sıkıcı bir deneyimdir.

Maliyet Optimizasyonu için Ek Öneriler

Alarm kurmak yetmez, maliyetleri aktif olarak takip etmek gerekir:

  • Reserved Instance kontrolü: On-demand çalışan uzun süreli instance’larınız varsa Reserved Instance veya Savings Plans ile %30-70 tasarruf edebilirsiniz
  • Spot Instance kullanımı: Dev ve test ortamları için Spot Instance kullanmak ciddi tasarruf sağlar
  • S3 lifecycle policy: Eski objeleri Glacier’a taşımak veya silmek storage maliyetini düşürür
  • Unused resource temizliği: Unattached EBS volume’lar, kullanılmayan Elastic IP’ler ve eski snapshot’lar para yer
  • Data transfer maliyeti: Region’lar arası veri transferi ücretlidir, mimari tasarımda buna dikkat edin
  • RDS Multi-AZ değerlendirmesi: Dev ortamlarında Multi-AZ gerekmez, bunu kapatmak maliyeti yarıya indirir
  • Auto Scaling doğru yapılandırması: Scale-out agresif, scale-in ise temkinli olmamalı

AWS Trusted Advisor ve Compute Optimizer araçlarını da düzenli kontrol edin. Bu araçlar kullanılmayan veya aşırı boyutlandırılmış kaynakları otomatik olarak tespit eder.

Sonuç

AWS billing yönetimi, cloud operasyonlarının göz ardı edilmesi en kolay ama sonuçları en ağır olan parçalarından biridir. Bu yazıda anlattığımız yapıyı kurduğunuzda elinizde şunlar olacak: CloudWatch üzerinde temel billing alarmı, AWS Budgets üzerinde servis ve proje bazlı gelişmiş bütçe takibi, SNS ve Lambda entegrasyonuyla Slack bildirimleri ve otomatik aksiyon mekanizması, Cost Explorer ile tarihsel maliyet analizi.

Başlangıç için karmaşık görünebilir ama bir kez kurulduktan sonra kendinizi güvende hissedersiniz. En azından bir sabah kalkıp beklenmedik 2000 dolarlık fatura görmek yerine, gün ortasında “hey 400 dolara ulaştık” diye mail alırsınız ve durumu kontrol altına alabilirsiniz.

Peki ya siz AWS hesabınızda billing alarmı var mı? Eğer yoksa bu yazıyı okuduktan sonra ilk yapacağınız iş bu olsun. Bir dakika bile ertelemek istemezsiniz, inanın.

Bir yanıt yazın

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