Cloud Native & Serverless Architectures

Cloud native prensipleri, container orchestration, Kubernetes, serverless computing, FaaS, Durable Functions, .NET ile cloud-native uygulama geliştirme, 12-factor app, observability, scalability ve cost optimization stratejileri ele alınır.

Cloud Native & Serverless Architectures

Cloud Native ve Sunucusuz Mimariler: Bulutun Gücünden Tam Verimle Yararlanmak

Günümüzde yazılım geliştirme, sadece kod yazmaktan ibaret değil; aynı zamanda uygulamaları bulutta nasıl çalıştıracağınızı, ölçeklendireceğinizi ve yöneteceğinizi de kapsıyor. Cloud Native (Bulut Yerel), uygulamaların bulut ortamının avantajlarından (ölçeklenebilirlik, dayanıklılık, esneklik) tam olarak yararlanacak şekilde tasarlanması ve çalıştırılmasıdır.【1†L4-L6】Serverless (Sunucusuz) ise bu yaklaşımın bir adım ötesine geçerek, altyapı yönetimini tamamen bulut sağlayıcısına bırakır ve geliştiricilerin sadece kod yazmaya odaklanmasını sağlar.【2†L4-L6】


1. Cloud Native Nedir? (Temel Prensipler)

Cloud Native, bir uygulamanın bulut ortamında dinamik, ölçeklenebilir ve dayanıklı olmasını sağlayan bir dizi prensip ve teknolojiden oluşur. Bu prensipler, 12-Factor App metodolojisi ile özetlenir.【1†L8-L10】

12-Factor App Prensipleri (Özet):

  1. Tek Bir Kod Tabanı (Codebase): Her servis için tek bir kod tabanı, birden fazla deploy ortamı.

  2. Bağımlılıkları Açıkça Beyan Etme (Dependencies): Bağımlılıkları açıkça tanımlayın ve yönetin.

  3. Konfigürasyonu Ortamdan Ayırma (Config): Konfigürasyonu kod dışında, ortam değişkenlerinde saklayın.

  4. Arka Plan Hizmetleri (Backing Services): Veritabanı, cache, message broker gibi hizmetleri bağımsız ve değiştirilebilir kaynaklar olarak ele alın.

  5. Build, Release, Run Ayrımı: Bu üç aşamayı kesinlikle ayırın.

  6. Stateless Süreçler (Processes): Uygulama süreçleri durumsuz (stateless) olmalıdır.

  7. Port Binding: Hizmetleri bağlantı noktalarına (port) bağlayarak sunun.

  8. Concurrency: Süreçleri yatayda ölçeklendirerek eşzamanlılığı yönetin.

  9. Disposability (Atılabilirlik): Süreçler hızlı başlamalı ve düzgün kapanmalıdır (graceful shutdown).

  10. Dev/Prod Parity: Geliştirme, staging ve production ortamlarını olabildiğince benzer tutun.

  11. Logs (Günlükler): Logları olay akışı (event stream) olarak ele alın.

  12. Admin Processes (Yönetici Süreçleri): Veri taşıma (migration) gibi işlemleri ayrı bir süreç olarak çalıştırın.


2. Container Orchestration (Konteyner Orkestrasyonu)

Cloud Native uygulamaların bel kemiği, container (konteyner) teknolojisidir (Docker). Konteynerlar, uygulamayı ve bağımlılıklarını izole edilmiş bir ortamda paketler. Ancak, onlarca veya yüzlerce konteyneri manuel olarak yönetmek imkânsızdır. İşte bu noktada container orchestration araçları devreye girer.

Kubernetes: Endüstri standardı container orchestration platformudur.【3†L6-L9】

  • Otomatik Ölçeklendirme: CPU veya özel metriklerine göre pod sayısını otomatik artırıp azaltır.

  • Kendi Kendini İyileştirme (Self-Healing): Başarısız pod'ları yeniden başlatır, sağlıksız pod'ları değiştirir.

  • Servis Keşfi ve Yük Dengeleme: Servisleri birbirine bağlar ve trafiği dengeler.

  • Rolling Update / Rollback: Yeni sürümleri kademeli olarak (zero-downtime) yayınlar ve hata durumunda geri alır.

  • Secret ve Configuration Yönetimi: Hassas bilgileri (parola, token) güvenle yönetir.

.NET ile Kubernetes'te Çalışma:

dockerfile

# Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["MyApp.csproj", "."]
RUN dotnet restore
COPY . .
RUN dotnet build -c Release -o /app/build

FROM build AS publish
RUN dotnet publish -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyApp.dll"]

yaml

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myregistry/myapp:latest
        ports:
        - containerPort: 80
        env:
        - name: ConnectionStrings__Default
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: connection-string
---
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
spec:
  selector:
    app: myapp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: LoadBalancer

Horizontal Pod Autoscaler (HPA):

yaml

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: myapp-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myapp-deployment
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

3. Serverless (Sunucusuz) Mimariler

Serverless, bulut sağlayıcısının altyapıyı (sunucular, ölçeklendirme, kapasite planlaması) tamamen yönettiği, geliştiricilerin sadece kod yazmaya odaklandığı bir modeldir.【2†L4-L6】FaaS (Function as a Service), serverless'ın en yaygın uygulama şeklidir.

Temel Özellikler:

  • Event-Driven (Olay Tabanlı): Fonksiyonlar, bir HTTP isteği, kuyruk mesajı, zamanlayıcı veya dosya yükleme gibi olaylar (events) tarafından tetiklenir.

  • Otomatik Ölçeklendirme: Gelen istek hacmine göre otomatik olarak ölçeklenir (sıfırdan binlere).

  • Kullanım Başına Ödeme (Pay-per-use): Sadece fonksiyon çalıştığı süre (ve işlem gücü) için ödeme yapılır.

  • Altyapı Yönetimi Yok: Sunucu kurulumu, bakımı, güvenlik yamaları tamamen sağlayıcı tarafından yapılır.

Popüler Serverless Platformları:

  • Azure Functions: .NET ile en iyi entegrasyonu sunar.

  • AWS Lambda: En olgun ve yaygın kullanılan platformdur.

  • Google Cloud Functions: Google Cloud ekosistemi ile entegredir.

Azure Functions ile .NET Örneği:

csharp

// HTTP Tetiklemeli Function
[FunctionName("HttpTriggerFunction")]
public static async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
    ILogger log)
{
    log.LogInformation("C# HTTP trigger function processed a request.");

    string name = req.Query["name"];
    string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
    dynamic data = JsonConvert.DeserializeObject(requestBody);
    name = name ?? data?.name;

    return name != null
        ? (ActionResult)new OkObjectResult($"Hello, {name}")
        : new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}

csharp

// Queue Tetiklemeli Function
[FunctionName("QueueTriggerFunction")]
public static void Run(
    [QueueTrigger("myqueue-items", Connection = "AzureWebJobsStorage")] string myQueueItem,
    ILogger log)
{
    log.LogInformation($"C# Queue trigger function processed: {myQueueItem}");
}

csharp

// Timer Tetiklemeli Function (Zamanlayıcı)
[FunctionName("TimerTriggerFunction")]
public static void Run(
    [TimerTrigger("0 */5 * * * *")] TimerInfo myTimer, // Her 5 dakikada bir
    ILogger log)
{
    log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
}

4. Durable Functions (Stateful Serverless)

Serverless fonksiyonlar genelde durumsuz (stateless) olsa da, Durable Functions, state'li (durumlu) ve uzun süren iş akışlarını serverless ortamda yönetmenizi sağlar.【4†L6-L9】

Kullanım Senaryoları:

  • SAGA Pattern: Dağıtık işlemlerde (distributed transactions) eventual consistency sağlamak.

  • İnsan Onayı (Human Approval): Bir iş akışında beklenmesi gereken adımlar (ör. yönetici onayı).

  • Uzun Süren İşlemler: Saatlerce veya günlerce süren iş akışları.

csharp

[FunctionName("OrderOrchestrator")]
public static async Task<List<string>> RunOrchestrator(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var orderId = context.GetInput<string>();

    // 1. Ödemeyi işle
    var paymentResult = await context.CallActivityAsync<bool>("ProcessPayment", orderId);
    if (!paymentResult)
    {
        // Ödeme başarısız, sipariş iptal et
        await context.CallActivityAsync("CancelOrder", orderId);
        return new List<string> { "Payment failed, order cancelled." };
    }

    // 2. Stok rezervasyonu yap
    var stockResult = await context.CallActivityAsync<bool>("ReserveStock", orderId);
    if (!stockResult)
    {
        // Stok yok, ödemeyi iade et
        await context.CallActivityAsync("RefundPayment", orderId);
        await context.CallActivityAsync("CancelOrder", orderId);
        return new List<string> { "Out of stock, order cancelled and payment refunded." };
    }

    // 3. Kargo oluştur
    await context.CallActivityAsync("CreateShipment", orderId);

    // 4. Sipariş tamamlandı
    await context.CallActivityAsync("CompleteOrder", orderId);

    return new List<string> { "Order completed successfully!" };
}

5. Serverless vs. Containers: Ne Zaman Hangisi?

Kriter Serverless (Azure Functions / AWS Lambda) Containers (Azure Container Instances / Kubernetes)
Ölçeklenebilirlik Otomatik, anlık (sıfırdan binlere) Manuel veya otomatik (HPA), daha yavaş
Maliyet Kullanım başına ödeme (çalışma süresi) 7/24 çalışan kaynaklar için sabit maliyet
Başlangıç Süresi (Cold Start) İlk çağrıda gecikme (cold start) olabilir Her zaman sıcak (hot), sıfır gecikme
Altyapı Kontrolü Sınırlı (sağlayıcıya bağlı) Tam kontrol (OS, network, güvenlik)
Uzun Süren İşlemler Timeout limitleri var (Azure'da 10 dakika) Sınırsız (uygulama kontrolünde)
State Yönetimi Stateless, Durable Functions ile state'li State'li veya state'siz uygulama
.NET Uyumluluğu .NET 8, 9, 10 desteği (Azure Functions) Tam .NET desteği
Kullanım Senaryosu Event-driven, API'ler, background işlemler Karmaşık, uzun süren, özel altyapı gerektiren işler

6. .NET ile Cloud Native Uygulama Geliştirme İpuçları

  1. 12-Factor App Prensiplerini Uygulayın: Konfigürasyonu (appsettings.json yerine environment variables), loglamayı (Serilog, OpenTelemetry) ve bağımlılıkları doğru yönetin.

  2. Health Checks (Sağlık Kontrolleri): Uygulamanızın durumunu izlemek için /health endpoint'i ekleyin.

    csharp

    builder.Services.AddHealthChecks()
        .AddDbContextCheck<AppDbContext>()
        .AddUrlGroup(new Uri("https://api.example.com"), "External API");
  3. Distributed Caching: Redis ile önbellekleme yaparak veritabanı yükünü azaltın.

  4. Resilience (Dayanıklılık): Polly ile retry, circuit breaker, timeout politikaları uygulayın.

  5. Observability (Gözlemlenebilirlik): OpenTelemetry ile metrics, logging ve distributed tracing entegrasyonu yapın.

  6. Container Image Optimizasyonu: Docker image'larınızı küçük ve güvenli tutun (Alpine tabanlı, çok aşamalı build).

  7. CI/CD Pipeline: GitHub Actions, Azure DevOps veya GitLab CI ile otomatik build, test ve deploy pipeline'ı oluşturun.

Sonuç:

Cloud Native ve Serverless mimariler, modern yazılım geliştirmenin geleceğini şekillendiriyor. Cloud Native, uygulamalarınızı bulutun gücünden tam olarak yararlanacak şekilde tasarlamanızı sağlarken; Serverless, altyapı yönetimini tamamen ortadan kaldırarak geliştiricilerin sadece kod yazmaya odaklanmasına olanak tanır.

.NET ekosistemi, her iki yaklaşım için de zengin araçlar sunar: Kubernetes ile container orchestration, Azure Functions ile serverless, Durable Functions ile state'li iş akışları. Doğru stratejiyi seçmek, uygulamanızın ihtiyaçlarına, maliyet hedeflerine ve ekip yetkinliklerine bağlıdır. Unutmayın: Bulut, sadece bir hosting ortamı değil, uygulama mimarinizin ayrılmaz bir parçasıdır.

Tüm yazılar