Kahramanmaraş merkezli 32 kişilik bir B2B fintech startup, Series A öncesi AKS cluster’ını yönetme yükünden kurtulmak istedi. 14 microservice’i 3 ayda Azure Container Apps’e taşıdı. Sonuç: aylık maliyet $1.840 → $960 (%48 düşüş), DevOps zamanı %35 azalma, scale-to-zero ile gece/hafta sonu maliyet sıfır. Bu yazı sahadaki teknik notlar.
Container Apps vs AKS Karar Matrisi
| Boyut | AKS | Container Apps |
|---|---|---|
| Kontrol seviyesi | Tam (kubectl, Helm, custom CRD) | Sınırlı (managed) |
| Yönetim yükü | Yüksek (cluster, node, upgrade) | Sıfır |
| Scaling | HPA + Cluster Autoscaler | KEDA (HTTP, queue, custom) |
| Scale-to-zero | Hayır (default) | Evet (KEDA) |
| Cold start | ~~yok (warm pod) | ~~1-3 sn (cold start) |
| Service mesh | Istio, Linkerd | Dapr (built-in) |
| Min cost | ~~$200/ay (system node) | ~~$0 (scale-to-zero) |
| İdeal use case | Karmaşık platform, çok sayıda team | Microservice, async worker, Dapr-friendly |
14 microservice + küçük DevOps ekibi → Container Apps açık kazanç.
Workload Profiles
Container Apps Environment 2 workload profile ile:
- Consumption: Tüm API’ler ve worker’lar (auto-scale, scale-to-zero)
- Dedicated D4 (1 instance): ML inference servisi (warm tutulması lazım)
az containerapp env create -g rg-fintech -n cae-prod
--location northeurope
--infrastructure-subnet-resource-id /subscriptions/.../subnets/cae-subnet
--internal-only false
--enable-workload-profiles
az containerapp env workload-profile add
--resource-group rg-fintech --name cae-prod
--workload-profile-name dedicated-d4
--workload-profile-type D4
--min-nodes 1 --max-nodes 1
Container App Tanımı
properties:
managedEnvironmentId: /subscriptions/.../containerEnvironments/cae-prod
workloadProfileName: Consumption
configuration:
ingress:
external: true
targetPort: 8080
traffic:
- revisionName: api-payment--v1.4.2
weight: 100
secrets:
- name: db-connection
keyVaultUrl: https://kv-fintech.vault.azure.net/secrets/db-conn
identity: system
dapr:
enabled: true
appId: payment-api
appPort: 8080
template:
containers:
- name: api
image: fintech.azurecr.io/payment-api:1.4.2
resources:
cpu: 0.5
memory: 1Gi
env:
- name: DB_CONNECTION
secretRef: db-connection
scale:
minReplicas: 0
maxReplicas: 30
rules:
- name: http-rule
http:
metadata: { concurrentRequests: "100" }
- name: queue-rule
custom:
type: azure-servicebus
metadata:
queueName: payment-queue
messageCount: "20"
auth:
- secretRef: sb-conn
triggerParameter: connection
Dapr ile Microservice Communication
14 servis arasındaki çağrılar Dapr service invocation üzerinden:
// payment-api'den order-api'ye çağrı
var client = new DaprClientBuilder().Build();
var order = await client.InvokeMethodAsync<Order>(
HttpMethod.Get,
"order-api", // Dapr app ID
$"orders/{orderId}");
Dapr otomatik mTLS, retry policy, circuit breaker, observability sağlıyor.
Pub/Sub with Dapr + Service Bus
# Dapr component (Service Bus pub/sub)
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: pubsub
spec:
type: pubsub.azure.servicebus.queues
version: v1
metadata:
- name: connectionString
secretKeyRef: { name: sb-conn, key: sb-conn }
// Publish
await client.PublishEventAsync("pubsub", "payment-completed", paymentEvent);
// Subscribe (controller)
[Topic("pubsub", "payment-completed")]
[HttpPost("payment-completed")]
public async Task<IActionResult> OnPaymentCompleted(PaymentEvent evt)
{
await _orderService.MarkPaidAsync(evt.OrderId);
return Ok();
}
Revisions ve Blue/Green Deployment
Yeni versiyon deploy edildiğinde önceki revision çalışmaya devam ediyor. Traffic kademeli yönlendirilir:
# Yeni revision deploy (traffic 0)
az containerapp update -g rg-fintech -n payment-api
--image fintech.azurecr.io/payment-api:1.4.3
--revision-suffix v1-4-3
# Trafik yönlendirme: %20 yeni
az containerapp ingress traffic set -g rg-fintech -n payment-api
--revision-weight payment-api--v1-4-2=80 payment-api--v1-4-3=20
# Doğrulama → %100 yeni
az containerapp ingress traffic set -g rg-fintech -n payment-api
--revision-weight payment-api--v1-4-3=100
KEDA Scaling Rules
| Service | Scaling rule | Min/Max |
|---|---|---|
| payment-api | HTTP (100 req/replica) | 0-30 |
| order-worker | Service Bus queue (20 msg) | 0-15 |
| notification-worker | Service Bus queue (50 msg) | 0-8 |
| kyc-processor | Cron + queue | 0-5 |
| ml-inference | HTTP (10 req/replica) | 1-4 (warm tutmak için min 1) |
Maliyet Karşılaştırması
| Kalem | AKS (önce) | Container Apps (sonra) |
|---|---|---|
| Cluster (system + user nodes) | $1.420 | — |
| Container Apps Environment (Consumption) | — | $420 |
| Workload profile D4 (1 dedicated) | — | $280 |
| Log Analytics + App Insights | $220 | $180 |
| Container Registry | $60 | $60 |
| Storage + Service Bus | $140 | $120 |
| Toplam | $1.840 | $960 |
%48 tasarruf. Sebep: 14 servisin %60’ı gece + hafta sonu scale-to-zero. AKS’de cluster ayakta kalıyor (idle bile olsa ödüyorsun).
Sahada Düşülen Üç Tuzak
- Scale-to-zero’yu cold start kabul etmeden uygulamak: 1-3 sn cold start latency-critical API’de fark edilir. Müşteri-facing API’lere min 1 replica.
- Container size’ı küçük tutmak: 0.25 CPU + 0.5 GB ile bazı .NET app yavaş başlıyor. Profile + uygun size.
- Dapr learning curve’ünü hafife almak: Service invocation + pub/sub + state management config’i Day 1 kolay değil. Pilot servis ile öğrenilmeli.
CloudSpark olarak Azure Container Apps deployment, AKS → Container Apps migration, Dapr entegrasyonu ve KEDA-based autoscaling projeleri için danışmanlık veriyoruz.



