AWS Lambda Fonksiyon Oluşturma ve Yapılandırma Rehberi

Serverless dünyanın kapıları açıldığında, çoğu sysadmin gibi ben de “sunucu yok mu, peki kim yönetiyor bunu?” diye düşündüm. Zamanla anladım ki sunucu var, sadece bizim sorunumuz değil. AWS Lambda bu zihniyetin en güzel ürünü: kodu yaz, çalıştır, unut. Ama tabii ki o “unut” kısmına gelmeden önce doğru yapılandırmayı bilmen gerekiyor.

AWS Lambda Nedir ve Neden Önemli

AWS Lambda, olay güdümlü (event-driven) bir hesaplama hizmetidir. Bir HTTP isteği geldiğinde, bir S3 bucket’ına dosya yüklendiğinde ya da bir DynamoDB tablosuna kayıt eklendiğinde tetiklenebilir. Arka planda AWS’nin kendi altyapısı devreye girer, kodu çalıştırır ve işi bitirir. Sen sadece çalışma süresine göre ücret ödersin.

Pratik düşünelim: Bir e-ticaret sitesinde sipariş onay e-postası göndermek için ayrı bir sunucu ayakta tutmak zorunda değilsin. Lambda fonksiyonu yaz, sipariş oluşturulduğunda tetikle, e-posta gönder, bitti. O fonksiyon ayda belki 10.000 kez çalışır, geri kalan zamanda hiçbir maliyet oluşturmaz.

Lambda’nın desteklediği runtime’lar şunlardır:

  • Python (3.8, 3.9, 3.10, 3.11, 3.12)
  • Node.js (18.x, 20.x)
  • Java (8, 11, 17, 21)
  • Go (1.x)
  • .NET (6, 8)
  • Ruby (3.2, 3.3)
  • Custom Runtime (kendi runtime’ını getirebilirsin)

İlk Lambda Fonksiyonunu Oluşturmak

AWS CLI ile Fonksiyon Oluşturma

Konsol üzerinden tıklamak yerine CLI’yi öğrenmek uzun vadede çok daha verimli. Önce gerekli IAM rolünü oluşturalım:

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

# IAM rolünü oluştur
aws iam create-role 
  --role-name my-lambda-execution-role 
  --assume-role-policy-document file://trust-policy.json

# Temel Lambda izinlerini role ekle
aws iam attach-role-policy 
  --role-name my-lambda-execution-role 
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

# Rol ARN'ini değişkene al (hesap ID'ni kendi ID'nle değiştir)
ROLE_ARN=$(aws iam get-role --role-name my-lambda-execution-role --query 'Role.Arn' --output text)
echo "Rol ARN: $ROLE_ARN"

Şimdi basit bir Python fonksiyonu yazalım:

# Fonksiyon kodunu oluştur
mkdir -p lambda-demo && cd lambda-demo

cat > handler.py << 'EOF'
import json
import logging
import os

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    """
    Ana Lambda handler fonksiyonu.
    event: Tetikleyiciden gelen veri
    context: Lambda runtime bilgileri
    """
    logger.info(f"Event alindi: {json.dumps(event)}")
    logger.info(f"Request ID: {context.aws_request_id}")
    logger.info(f"Kalan sure: {context.get_remaining_time_in_millis()}ms")
    
    # Ortam değişkeninden değer çek
    environment = os.environ.get('APP_ENVIRONMENT', 'development')
    
    # Event'ten isim al, yoksa varsayılan kullan
    name = event.get('name', 'Dünya')
    
    response = {
        'statusCode': 200,
        'body': json.dumps({
            'message': f'Merhaba, {name}!',
            'environment': environment,
            'requestId': context.aws_request_id
        }, ensure_ascii=False)
    }
    
    return response
EOF

# Zip dosyası oluştur
zip function.zip handler.py

# Lambda fonksiyonunu oluştur
aws lambda create-function 
  --function-name my-demo-function 
  --runtime python3.12 
  --role $ROLE_ARN 
  --handler handler.lambda_handler 
  --zip-file fileb://function.zip 
  --timeout 30 
  --memory-size 256 
  --description "Demo Lambda fonksiyonu" 
  --environment Variables="{APP_ENVIRONMENT=production}"

Fonksiyonu Test Etmek

# Fonksiyonu senkron olarak çağır
aws lambda invoke 
  --function-name my-demo-function 
  --payload '{"name": "Ahmet"}' 
  --cli-binary-format raw-in-base64-out 
  response.json

# Sonucu görüntüle
cat response.json | python3 -m json.tool

# Log çıktısını da görmek istiyorsan
aws lambda invoke 
  --function-name my-demo-function 
  --payload '{"name": "Mehmet"}' 
  --cli-binary-format raw-in-base64-out 
  --log-type Tail 
  --query 'LogResult' 
  --output text 
  response.json | base64 --decode

Fonksiyon Yapılandırması ve Optimizasyon

Bellek ve Timeout Ayarları

Lambda’da bellek ayarı sadece RAM’i değil, aynı zamanda CPU gücünü de etkiler. 128 MB ile 10,240 MB arasında seçim yapabilirsin. Daha fazla bellek, daha fazla vCPU demek ve bu doğrudan performansı etkiler.

# Mevcut yapılandırmayı güncelle
aws lambda update-function-configuration 
  --function-name my-demo-function 
  --timeout 60 
  --memory-size 512

# Yapılandırmayı kontrol et
aws lambda get-function-configuration 
  --function-name my-demo-function 
  --query '{Timeout: Timeout, MemorySize: MemorySize, Runtime: Runtime}'

Timeout için pratik öneriler:

  • Basit API işlemleri: 10-30 saniye yeterli
  • Dosya işleme, dönüştürme: 60-120 saniye
  • Büyük veri işleme, ML: 300-900 saniye (maksimum 15 dakika)

Environment Variables ile Güvenli Yapılandırma

Hassas bilgileri doğrudan koda yazmak yerine environment variable kullan, ancak bu da yeterli değil. KMS ile şifrelemek en doğrusu:

# KMS anahtarı oluştur (opsiyonel, AWS managed key de kullanılabilir)
KEY_ID=$(aws kms create-key 
  --description "Lambda env vars encryption key" 
  --query 'KeyMetadata.KeyId' 
  --output text)

# KMS key'e alias ekle
aws kms create-alias 
  --alias-name alias/lambda-secrets 
  --target-key-id $KEY_ID

# Environment variable'ları KMS ile şifreleyerek ekle
aws lambda update-function-configuration 
  --function-name my-demo-function 
  --environment Variables="{
    APP_ENVIRONMENT=production,
    DB_HOST=mydb.cluster.rds.amazonaws.com,
    APP_VERSION=1.0.0
  }" 
  --kms-key-arn arn:aws:kms:eu-west-1:123456789:key/$KEY_ID

Gerçek dünyada daha hassas bilgiler (şifreler, API anahtarları) için AWS Secrets Manager veya Parameter Store kullanmak çok daha güvenli:

# Python handler'ında Secrets Manager kullanımı
cat > handler_secure.py << 'EOF'
import json
import boto3
import logging
from botocore.exceptions import ClientError

logger = logging.getLogger()
logger.setLevel(logging.INFO)

# Client'ı dışarıda tanımla - container reuse avantajından yararlan
secrets_client = boto3.client('secretsmanager')

def get_secret(secret_name):
    """Secrets Manager'dan gizli bilgi çek"""
    try:
        response = secrets_client.get_secret_value(SecretId=secret_name)
        return json.loads(response['SecretString'])
    except ClientError as e:
        logger.error(f"Secret alinamadi: {e}")
        raise

# Modül seviyesinde bir kez yükle (cold start'ta çalışır)
db_credentials = None

def lambda_handler(event, context):
    global db_credentials
    
    # Warm start'ta tekrar çekmemek için cache'le
    if db_credentials is None:
        db_credentials = get_secret('production/myapp/db')
        logger.info("DB credentials yuklendi")
    
    # İşlemler...
    return {
        'statusCode': 200,
        'body': json.dumps({'status': 'ok'})
    }
EOF

Katmanlar (Layers) ile Bağımlılık Yönetimi

Fonksiyon boyutu büyüdükçe her deploy’da tüm bağımlılıkları paketlemek zahmetli hale gelir. Lambda Layers bu sorunu çözer: bağımlılıkları bir kez katman olarak yükle, birden fazla fonksiyonda paylaş.

# Bağımlılıkları katman olarak paketleme
mkdir -p layer/python

# Gerekli paketleri katman dizinine kur
pip3 install requests boto3 pandas 
  --target layer/python/ 
  --platform manylinux2014_x86_64 
  --implementation cp 
  --python-version 3.12 
  --only-binary=:all: 
  --upgrade

# Katmanı zip'le
cd layer && zip -r ../my-dependencies-layer.zip python/
cd ..

# Katmanı AWS'e yükle
LAYER_ARN=$(aws lambda publish-layer-version 
  --layer-name my-python-dependencies 
  --description "Python bağımlılıkları: requests, pandas" 
  --zip-file fileb://my-dependencies-layer.zip 
  --compatible-runtimes python3.12 
  --query 'LayerVersionArn' 
  --output text)

echo "Layer ARN: $LAYER_ARN"

# Katmanı fonksiyona ekle
aws lambda update-function-configuration 
  --function-name my-demo-function 
  --layers $LAYER_ARN

Tetikleyiciler (Triggers) Yapılandırma

API Gateway ile HTTP Endpoint Oluşturma

En yaygın kullanım senaryolarından biri Lambda’yı bir REST API’nin arkasına koymak:

# HTTP API oluştur (v2 - daha ucuz ve hızlı)
API_ID=$(aws apigatewayv2 create-api 
  --name my-lambda-api 
  --protocol-type HTTP 
  --query 'ApiId' 
  --output text)

# Lambda entegrasyonu oluştur
INTEGRATION_ID=$(aws apigatewayv2 create-integration 
  --api-id $API_ID 
  --integration-type AWS_PROXY 
  --integration-uri "arn:aws:lambda:eu-west-1:123456789:function:my-demo-function" 
  --payload-format-version "2.0" 
  --query 'IntegrationId' 
  --output text)

# Route ekle
aws apigatewayv2 create-route 
  --api-id $API_ID 
  --route-key "GET /hello" 
  --target "integrations/$INTEGRATION_ID"

# Stage oluştur ve deploy et
aws apigatewayv2 create-stage 
  --api-id $API_ID 
  --stage-name prod 
  --auto-deploy

# Lambda'ya API Gateway'den çağrı iznini ver
aws lambda add-permission 
  --function-name my-demo-function 
  --statement-id api-gateway-invoke 
  --action lambda:InvokeFunction 
  --principal apigateway.amazonaws.com 
  --source-arn "arn:aws:execute-api:eu-west-1:123456789:$API_ID/*/*/hello"

echo "API URL: https://$API_ID.execute-api.eu-west-1.amazonaws.com/prod/hello"

S3 Trigger ile Dosya İşleme

Gerçek bir senaryo: Kullanıcılar S3’e CSV yüklüyor, Lambda otomatik olarak işliyor ve DynamoDB’ye kaydediyor.

# S3 bucket oluştur
aws s3 mb s3://my-upload-bucket-demo-2024

# Lambda'ya S3 erişim izni ver
cat > s3-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::my-upload-bucket-demo-2024/*"
    }
  ]
}
EOF

aws iam put-role-policy 
  --role-name my-lambda-execution-role 
  --policy-name s3-access-policy 
  --policy-document file://s3-policy.json

# Lambda'ya S3'ten çağrı iznini ver
aws lambda add-permission 
  --function-name my-demo-function 
  --statement-id s3-trigger-permission 
  --action lambda:InvokeFunction 
  --principal s3.amazonaws.com 
  --source-arn arn:aws:s3:::my-upload-bucket-demo-2024

# S3 bucket notification'ı yapılandır
cat > notification-config.json << 'EOF'
{
  "LambdaFunctionConfigurations": [
    {
      "LambdaFunctionArn": "arn:aws:lambda:eu-west-1:123456789:function:my-demo-function",
      "Events": ["s3:ObjectCreated:Put"],
      "Filter": {
        "Key": {
          "FilterRules": [
            {
              "Name": "suffix",
              "Value": ".csv"
            }
          ]
        }
      }
    }
  ]
}
EOF

aws s3api put-bucket-notification-configuration 
  --bucket my-upload-bucket-demo-2024 
  --notification-configuration file://notification-config.json

Concurrency ve Throttling Yönetimi

Lambda varsayılan olarak hesap bazında 1000 eş zamanlı çalışma limiti sunar. Production ortamında bu limiti iyi yönetmezsen kritik fonksiyonların throttle edilmesi durumuna düşebilirsin.

# Fonksiyona reserved concurrency ata (diğer fonksiyonlardan koruma)
aws lambda put-function-concurrency 
  --function-name my-demo-function 
  --reserved-concurrent-executions 100

# Provisioned concurrency ile cold start'ı önle (maliyetlidir)
# Önce fonksiyon versiyonu yayınla
VERSION=$(aws lambda publish-version 
  --function-name my-demo-function 
  --description "v1.0.0 production release" 
  --query 'Version' 
  --output text)

# Alias oluştur
aws lambda create-alias 
  --function-name my-demo-function 
  --name production 
  --function-version $VERSION

# Alias'a provisioned concurrency ekle
aws lambda put-provisioned-concurrency-config 
  --function-name my-demo-function 
  --qualifier production 
  --provisioned-concurrent-executions 10

Concurrency stratejileri:

  • Reserved Concurrency: Fonksiyona maksimum kapasite ayır, fazlasını throttle et
  • Provisioned Concurrency: Container’ları önceden ısıt, cold start’ı sıfıra indir
  • 0 reserved concurrency: Fonksiyonu tamamen devre dışı bırak (emergency için)

CloudWatch ile İzleme ve Alarm

Lambda metriklerini izlemek için CloudWatch alarm kurmak şart:

# Hata oranı için alarm oluştur
aws cloudwatch put-metric-alarm 
  --alarm-name "lambda-error-rate-high" 
  --alarm-description "Lambda hata orani %5 ustunde" 
  --metric-name Errors 
  --namespace AWS/Lambda 
  --statistic Sum 
  --period 300 
  --threshold 10 
  --comparison-operator GreaterThanThreshold 
  --dimensions Name=FunctionName,Value=my-demo-function 
  --evaluation-periods 2 
  --alarm-actions arn:aws:sns:eu-west-1:123456789:my-alert-topic 
  --treat-missing-data notBreaching

# Duration (süre) alarmı - timeout'a yaklaşıyorsa uyar
aws cloudwatch put-metric-alarm 
  --alarm-name "lambda-duration-high" 
  --alarm-description "Lambda suresi timeout limitine yaklasiyor" 
  --metric-name Duration 
  --namespace AWS/Lambda 
  --statistic Average 
  --period 300 
  --threshold 25000 
  --comparison-operator GreaterThanThreshold 
  --dimensions Name=FunctionName,Value=my-demo-function 
  --evaluation-periods 3 
  --alarm-actions arn:aws:sns:eu-west-1:123456789:my-alert-topic

# Son 1 saatin log'larını çek
aws logs filter-log-events 
  --log-group-name /aws/lambda/my-demo-function 
  --start-time $(date -d '1 hour ago' +%s000) 
  --filter-pattern "ERROR" 
  --query 'events[*].message' 
  --output text

Dead Letter Queue (DLQ) ile Hata Yönetimi

Asenkron çağrılan Lambda fonksiyonları başarısız olduğunda event kaybolabilir. DLQ ile bu eventleri yakala:

# SQS Dead Letter Queue oluştur
DLQ_ARN=$(aws sqs create-queue 
  --queue-name lambda-dlq 
  --attributes '{"MessageRetentionPeriod":"1209600"}' 
  --query 'QueueUrl' 
  --output text | xargs aws sqs get-queue-attributes 
  --attribute-names QueueArn 
  --query 'Attributes.QueueArn' 
  --output text)

# Lambda'ya SQS yazma izni ver
aws iam attach-role-policy 
  --role-name my-lambda-execution-role 
  --policy-arn arn:aws:iam::aws:policy/AmazonSQSFullAccess

# Fonksiyona DLQ ekle ve retry ayarla
aws lambda update-function-configuration 
  --function-name my-demo-function 
  --dead-letter-config TargetArn=$DLQ_ARN

# Asenkron invocation retry ayarları
aws lambda put-function-event-invoke-config 
  --function-name my-demo-function 
  --maximum-retry-attempts 2 
  --maximum-event-age-in-seconds 3600 
  --destination-config '{
    "OnFailure": {"Destination": "'$DLQ_ARN'"},
    "OnSuccess": {"Destination": "arn:aws:sqs:eu-west-1:123456789:success-queue"}
  }'

VPC Entegrasyonu

Lambda’nın private RDS veya ElastiCache gibi VPC içindeki kaynaklara erişmesi gerekiyorsa VPC yapılandırması zorunlu:

# VPC bilgilerini al
VPC_ID=$(aws ec2 describe-vpcs 
  --filters "Name=tag:Name,Values=my-production-vpc" 
  --query 'Vpcs[0].VpcId' 
  --output text)

SUBNET_IDS=$(aws ec2 describe-subnets 
  --filters "Name=vpc-id,Values=$VPC_ID" "Name=tag:Type,Values=private" 
  --query 'Subnets[*].SubnetId' 
  --output text | tr 't' ',')

SG_ID=$(aws ec2 describe-security-groups 
  --filters "Name=vpc-id,Values=$VPC_ID" "Name=group-name,Values=lambda-sg" 
  --query 'SecurityGroups[0].GroupId' 
  --output text)

# Fonksiyonu VPC'ye bağla
aws lambda update-function-configuration 
  --function-name my-demo-function 
  --vpc-config SubnetIds=$SUBNET_IDS,SecurityGroupIds=$SG_ID

# VPC içinde Lambda için gerekli ek izin
aws iam attach-role-policy 
  --role-name my-lambda-execution-role 
  --policy-arn arn:aws:iam::aws:policy/AWSLambdaVPCAccessExecutionRole

VPC’ye bağlı Lambda’da dikkat edilecekler:

  • Cold start süresi artar: ENI oluşturma ek süre alır (Provisioned Concurrency ile çözülebilir)
  • NAT Gateway gerekir: Dış dünyaya erişim için public subnet’teki NAT Gateway zorunlu
  • Security Group: RDS security group’u Lambda’nın SG’sinden gelen trafiğe izin vermeli

Fonksiyon Versiyonlama ve Alias Stratejisi

Production ortamında versiyonlama ve alias kullanmak deployment süreçlerini çok daha güvenli hale getirir:

# Yeni kod deploy et ve versiyon yayınla
zip -r function-v2.zip handler.py
aws lambda update-function-code 
  --function-name my-demo-function 
  --zip-file fileb://function-v2.zip

# Yeni versiyon yayınla
NEW_VERSION=$(aws lambda publish-version 
  --function-name my-demo-function 
  --description "v2.0.0 - yeni ozellikler eklendi" 
  --query 'Version' 
  --output text)

# Canary deployment: %10 yeni versiyona gönder
aws lambda update-alias 
  --function-name my-demo-function 
  --name production 
  --function-version $NEW_VERSION 
  --routing-config AdditionalVersionWeights={"$NEW_VERSION"=0.1}

# Sorun yoksa tüm trafiği yeni versiyona taşı
aws lambda update-alias 
  --function-name my-demo-function 
  --name production 
  --function-version $NEW_VERSION 
  --routing-config AdditionalVersionWeights={}

# Eski versiyonu temizle (opsiyonel)
OLD_VERSION=$((NEW_VERSION - 1))
aws lambda delete-function 
  --function-name my-demo-function 
  --qualifier $OLD_VERSION

Maliyet Optimizasyonu İpuçları

Lambda fiyatlandırması şu iki bileşene dayanır:

  • İstek sayısı: İlk 1 milyon istek/ay ücretsiz, sonrası $0.20/milyon
  • Hesaplama süresi: GB-saniye cinsinden, bellek ve sürenin çarpımı

Maliyeti düşürmek için pratik öneriler:

  • Doğru bellek boyutu seç: Lambda Power Tuning aracını kullan, bazen daha fazla bellek hem daha hızlı hem daha ucuz olabiliyor
  • Connection pooling yap: RDS Proxy veya connection pooling kütüphanesi kullan, her invocation’da yeni bağlantı açma
  • Arm64 (Graviton2) kullan: x86’ya göre aynı fiyata %20 daha iyi performans
  • Gereksiz log’ları kaldır: CloudWatch Logs maliyeti gözden kaçan bir kalemdir
# Arm64 mimarisine geç
aws lambda update-function-configuration 
  --function-name my-demo-function 
  --architectures arm64

# Log retention süresini sınırla (varsayılan: sonsuz)
aws logs put-retention-policy 
  --log-group-name /aws/lambda/my-demo-function 
  --retention-in-days 30

Sonuç

AWS Lambda’yı doğru yapılandırmak, sadece “fonksiyon oluştur ve çalıştır” adımının çok ötesine geçiyor. IAM rolleri ile güvenlik sınırlarını belirlemek, katmanlarla bağımlılıkları yönetmek, concurrency ayarları ile sistemi korumak, DLQ ile hata senaryolarını ele almak ve CloudWatch ile her şeyi izlemek bütünün parçaları.

Serverless mimarisi özellikle başlangıçta sysadmin’lere yabancı gelebilir. “Nerede bu sunucu?” sorusu mantıklı ama cevabı şu: sunucu AWS’de, sen sadece koda odaklanıyorsun. Ancak bu “sıfır sorumluluk” anlamına gelmiyor. Timeout yönetimi, cold start optimizasyonu, VPC entegrasyonu gibi konular hala senin sorumluluğunda.

Küçük başla: tek bir fonksiyon oluştur, CLI ile yönetmeyi öğren, ardından Infrastructure as Code (Terraform veya AWS SAM) tarafına geç. Lambda’nın gerçek gücü, EventBridge, SQS, SNS gibi servislerle kombinlendiğinde ortaya çıkıyor. O noktaya geldiğinde serverless’ın neden bu kadar popüler olduğunu çok daha iyi anlayacaksın.

Bir yanıt yazın

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