Ekim 19 2026

Hibrit Bulut Stratejileri: LocalStack’ten Üretim Ortamına Geçişin Riskleri

Hepimiz o sahneyi yaşadık: Docker daemon üzerinde koşan LocalStack konteyneri kusursuz çalışıyor, entegrasyon testleri saniyeler içinde yeşile dönüyor, CI/CD hattından geçen pipeline sorunsuz tamamlanıyor. Ancak deployment paketini gerçek bir AWS ortamına fırlattığınız an—ister staging olsun ister prod—CloudWatch logları kırmızıya boyanıyor. Cloud migration ve yerel geliştirme döngülerinde simülatör kullanmak harika bir maliyet avantajı sağlasa da, simülasyon ile gerçek dünya arasındaki uçurum bazen bir cuma akşamınızı mahvetmeye yeter.

Bu yazıda “LocalStack nedir, nasıl kurulur?” gibi giriş seviyesi konuları es geçiyoruz. 5 yıldan uzun süredir terminal başında sabahlayan bir mühendisin gözünden; LocalStack’in taklit edemediği alt seviye mimari nüansları, IAM’in sessiz tuzaklarını ve prodüksiyon seviyesinde baş ağrıtan asenkron davranış farklarını masaya yatırıyoruz.

1. IAM İllüzyonu: “Her Şeye İzin Ver” Rahatlığından Prod Çakılmasına

LocalStack Community sürümünün en büyük handikabı, varsayılan olarak IAM izinlerini denetlememesidir. S3’e dosya yazan bir Lambda fonksiyonu yazarsınız; fonksiyona hiçbir s3:PutObject izni tanımlamazsınız ama yerel ortamda tıkır tıkır çalışır. Pro sürümde ENFORCE_IAM=1 bayrağını açsanız bile, AWS IAM Evaluation Logic motorunun tüm karmaşıklığını Docker içinde replike etmek imkansıza yakındır.

Özellikle Resource-based Policies ile Identity-based Policies kesiştiğinde ve araya KMS şifrelemesi girdiğinde LocalStack havlu atar. Aşağıdaki tipik Terraform bloğunu ele alalım:

# LocalStack üzerinde çalışırken KMS yetkisi eksik olsa bile hata vermeyen 
# ancak AWS üzerinde anında 403 Access Denied fırlatan senaryo

resource "aws_s3_bucket_policy" "strict_policy" {
  bucket = aws_s3_bucket.data_lake.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid       = "EnforceKMSAuth"
        Effect    = "Deny"
        Principal = "*"
        Action    = "s3:PutObject"
        Resource  = "${aws_s3_bucket.data_lake.arn}/*"
        Condition = {
          StringNotEquals = {
            "s3:x-amz-server-side-encryption-aws-kms-key-id" = aws_kms_key.custom_key.arn
          }
        }
      }
    ]
  })
}

Neden böyle? AWS IAM motoru, bir isteği işlerken explicit deny, SCP (Service Control Policies), Permissions Boundary ve Session Policies gibi çok katmanlı bir evaluation tree üzerinden geçer. LocalStack ise Python tabanlı basitleştirilmiş bir kural kontrolü yapar. Sonuç: CI ortamında yeşil geçen test, canlı deployment sonrası API Gateway arkasındaki servisinizin KMS.AccessDeniedException hatasıyla çökmesine yol açar.

2. Dağıtık Sistemlerdeki Zamanlama ve Eventual Consistency Farkları

LocalStack bellekte (in-memory) veya hafif SQLite/DynamoDB-Local süreçleriyle çalışır. Bu mimari, AWS’in küresel bazda dağıtık veri merkezlerindeki gecikme ve tutarlılık modellerini maskeler.

DynamoDB: Tek Node Yanılgısı

LocalStack üzerinde koşan DynamoDB Local, tek bir Java prosesidir. Prodüksiyon ortamındaki partition splitting, hot partition, read/write capacity throttling (RCU/WCU) veya Burst Capacity tüketimini yerelde gözlemleyemezsiniz. Yerelde 5000 RPS ile geçen yük testiniz, AWS üzerinde rastgele ProvisionedThroughputExceededException fırlatabilir; çünkü veriniz gerçek partition’lara düzgün dağılmamıştır.

SQS ve SNS: Sıralama ve Görünürlük

LocalStack üzerinde FIFO kuyrukları simüle ederken MessageGroupId mantığı kusursuz gibi görünür. Ancak gerçek AWS SQS FIFO’da maksimum 300 msg/s (veya batching ile 3000) sınırı, message deduplication interval penceresi (5 dakika) ve visibility timeout yarış koşulları (race conditions) çok daha agresiftir.

# Yerelde anında mesaj çeken bu kod, AWS SQS üzerinde ReceiveMessageWaitTimeSeconds 
# ve VisibilityTimeout dinamikleri yüzünden mesaj kaybı/çift işleme yaratabilir.

aws --endpoint-url=http://localhost:4566 sqs receive-message \
    --queue-url http://localhost:4566/000000000000/orders.fifo \
    --max-number-of-messages 10 \
    --wait-time-seconds 0

LocalStack’te mesaj hemen oradadır. AWS’te ise kuyruk arka planda onlarca storage node’a dağılmıştır; kısa yoklama (short polling) yaptığınızda kuyrukta mesaj olmasına rağmen boş yanıt dönebilir. Testinizi WaitTimeSeconds=20 ile yazmadıysanız prod ortamında hayalet bug’lar peşinizi bırakmaz.

3. Ağ ve Altyapı İzolasyonu: Docker Bridge vs. AWS VPC

LocalStack konteynerleri varsayılan olarak Docker network’ü üzerinden konuşur. Bu durum, AWS’in karmaşık VPC mimarisini, Security Group kurallarını ve en önemlisi VPC Endpoint politikalarını tamamen görmezden gelmenize yol açar.

Gerçek hayatta Lambda’yı bir VPC içine aldığınızda ne olur? Hyperplane ENI (Elastic Network Interface) atanır. İlk başlatmada soğuk başlatma (cold start) süreleri uzar ve outbound internet trafiğiniz için bir NAT Gateway veya VPC Endpoint (PrivateLink) tanımlamanız gerekir. LocalStack içinde çalışan bir Lambda ise Docker host’un internetini doğrudan kullanır.

# Docker Compose ile LocalStack ve bağımlı servisler çalıştırılırken 
# ağ gecikmesi ve DNS kısıtlamaları simüle edilemez

services:
  localstack:
    image: localstack/localstack:latest
    ports:
      - "4566:4566"
    environment:
      - SERVICES=s3,sqs,sns,lambda,dynamodb
      - DOCKER_HOST=unix:///var/run/docker.sock
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"

Eğer Lambda fonksiyonunuz bir S3 bucket’ına VPC Endpoint olmadan erişmeye çalışıyorsa ve subnet’inizde NAT Gateway rotası yoksa, prod ortamında timeout alırsınız. LocalStack testlerinizde bu senaryonun patlama ihtimali sıfırdır; çünkü Docker konteyneri her yere doğrudan routing yapar.

4. Terraform Konfigürasyonunda “Provider Kirliliği” (Provider Drift)

CI/CD pipeline’larında LocalStack kullanırken altyapı kodunu (IaC) simülatöre yönlendirmek için genellikle Terraform provider override teknikleri kullanılır:

# main_override.tf örneği
provider "aws" {
  access_key                  = "mock_key"
  secret_key                  = "mock_secret"
  region                      = "eu-central-1"
  s3_use_path_style           = true
  skip_credentials_validation = true
  skip_metadata_api_check     = true
  skip_requesting_account_id  = true

  endpoints {
    s3       = "http://localhost:4566"
    dynamodb = "http://localhost:4566"
    sqs      = "http://localhost:4566"
  }
}

Bu yaklaşımın iki büyük riski vardır:

  • s3_use_path_style: AWS, S3 için path-style (s3.amazonaws.com/bucket) erişimini yıllar önce deprecated ilan etti ve virtual-hosted-style (bucket.s3.amazonaws.com) modeline zorluyor. LocalStack’te path-style kullanıp production konfigürasyonunda bunu unutursanız, DNS resolution ve SSL wildcard sertifika hatalarıyla karşılaşırsınız.
  • Feature Parity Eksikliği: Terraform AWS Provider’ın her yeni sürümünde eklenen yeni argümanlar (örneğin gelişmiş S3 Lifecycle kuralları veya EventBridge Pipe filtreleri), LocalStack tarafından hemen desteklenmeyebilir. Kod yerelde InvalidParameter verirken AWS’te geçerli olabilir veya tam tersi yaşanabilir.

5. LocalStack Risklerini Sıfıra İndiren Hibrit Pipeline Mimarisi

LocalStack’i tamamen çöpe mi atalım? Kesinlikle hayır. Hızlı geri bildirim (feedback loop) ve birim entegrasyon testleri için rakipsizdir. Ancak deployment stratejinizi sadece LocalStack onayına bağlayamazsınız.

Önerilen Doğrulama Piramidi

  1. Pre-commit / Local Dev: Mock kütüphaneleri (moto vb.) veya LocalStack Community. Sadece “happy-path” iş mantığı doğrulaması.
  2. CI Pipeline (PR Aşaması): Testcontainers ile izole LocalStack üzerinde API sözleşme testleri (Contract Testing).
  3. CD Pipeline (Merge Sonrası – Staging/Ephemeral): Gerçek bir AWS Sandbox hesabında, kısa ömürlü (TTL: 2 saat) dinamik ortamlar. Terraform ile gerçek kaynakların ayağa kaldırılması ve end-to-end (E2E) testlerin koşulması.
#!/usr/bin/env bash
# CI/CD aşamasında Ephemeral Environment yaşam döngüsü

ENVIRONMENT_ID="ci-pr-${PR_NUMBER}-${GITHUB_SHA:0:7}"

echo "Deploying ephemeral stack to real AWS: $ENVIRONMENT_ID"
terraform init
terraform workspace new "$ENVIRONMENT_ID"
terraform apply -auto-approve -var="env=$ENVIRONMENT_ID"

# Gerçek AWS API üzerinde testleri koştur
pytest tests/e2e --aws-env="$ENVIRONMENT_ID"
TEST_EXIT_CODE=$?

# Temizlik adımı (Cost Optimization)
echo "Tearing down ephemeral stack..."
terraform destroy -auto-approve -var="env=$ENVIRONMENT_ID"
terraform workspace select default
terraform workspace delete "$ENVIRONMENT_ID"

exit $TEST_EXIT_CODE

LocalStack harika bir geliştirme aracıdır; ancak hiçbir zaman nihai bir doğrulama katmanı değildir. Gerçek bir cloud migration sürecinde ve kesintisiz CI/CD hatlarında parite farklarını hesaba katmayan ekipler, simülasyonun konforunda boğulup faturayı canlı ortam kesintileriyle öderler.

Etiketler: , , , ,
Copyright 20254541. All rights reserved.

Posted 19 Ekim 2026 by Kerem Danış in category "Genel