Antalya’da otel + tur operatörü grubu, 38 web uygulamasını (rezervasyon, intranet, içerik, partner portali, raporlama) 18 VM üzerinde host ediyordu. Sezon dışı VM’ler boş, sezonda yetersiz; deployment manuel, downtime şikayeti çok. 5 ayda Azure App Service’e taşındı. Bu yazı kararların nasıl alındığını anlatıyor.
Plan Tipleri ve Karar Matrisi
| Plan | Aylık fiyat (örnek SKU) | Özellik | Use case |
|---|---|---|---|
| Free (F1) | $0 | 60 dk/gün CPU | Demo, hobi |
| Shared (D1) | $10 | 240 dk/gün | Düşük trafik test |
| Basic (B1) | $13 | 1 instance, custom domain | Dev, küçük prod |
| Standard (S1) | $73 | 10 instance, autoscale, slots | Orta trafik prod |
| Premium V3 (P1v3) | $84 | 30 instance, VNet, daha hızlı CPU | Yüksek trafik, düşük latency |
| Isolated (I1v2) | $355+ | Dedicated tenant, App Service Environment | Compliance, enterprise |
38 app dağılımı:
- 4 ana app (rezervasyon, partner, intranet, raporlama) → 1 Premium V3 P2v3 plan, paylaşımlı
- 20 internal/küçük app → 1 Standard S2 plan, paylaşımlı
- 14 dev/test app → 1 Basic B1 plan
Plan Sharing Stratejisi
Her app ayrı plan ≠ verimli. Birkaç app aynı plan’ı paylaşır (CPU, RAM, instance). Avantaj: maliyet. Dezavantaj: noisy neighbor. Karar: trafik karakteri benzer app’ler aynı plan’da.
Deployment Slots
Premium V3 P1v3+ plan’larda slot desteği. Strategy: production + staging + 1 hot-fix slot.
# Yeni versiyon staging'e deploy
az webapp deployment source config-zip
-g rg-web -n app-rezervasyon --slot staging
--src ./build.zip
# Smoke test
curl -s https://app-rezervasyon-staging.azurewebsites.net/health
# Swap (downtime ~~saniyeler, in-place warm-up)
az webapp deployment slot swap
-g rg-web -n app-rezervasyon
--slot staging --target-slot production
Sorun çıkarsa swap geri:
az webapp deployment slot swap
-g rg-web -n app-rezervasyon
--slot production --target-slot staging
Autoscale: Sezonluk Trafik
Yaz sezonu rezervasyon trafiği 8x normal. Autoscale rule:
az monitor autoscale create -g rg-web
--resource asp-prod-p2v3 --resource-type Microsoft.Web/serverfarms
--name asp-prod-autoscale
--min-count 2 --max-count 20 --count 4
# CPU > 70% → scale out 2 instance
az monitor autoscale rule create
--resource-group rg-web --autoscale-name asp-prod-autoscale
--scale out 2 --condition "Percentage CPU > 70 avg 5m"
# CPU < 30% → scale in 1 instance (cooldown 10 dk)
az monitor autoscale rule create
--resource-group rg-web --autoscale-name asp-prod-autoscale
--scale in 1 --condition "Percentage CPU < 30 avg 10m"
--cooldown 10
# Mesai-bazlı schedule (sabah 06:00 base 6 instance)
az monitor autoscale profile create
--resource-group rg-web --autoscale-name asp-prod-autoscale
--name "morning-warmup"
--min-count 6 --max-count 20 --count 6
--recurrence week mon tue wed thu fri --start 06:00 --end 22:00
Custom Domain + TLS
# Domain ekleme
az webapp config hostname add -g rg-web --webapp-name app-rezervasyon
--hostname rezervasyon.tatil.com.tr
# Free App Service Managed Certificate
az webapp config ssl create -g rg-web --name app-rezervasyon
--hostname rezervasyon.tatil.com.tr
# Bind
az webapp config ssl bind -g rg-web --name app-rezervasyon
--certificate-thumbprint XXXXXX --ssl-type SNI
# HTTPS only
az webapp update -g rg-web -n app-rezervasyon --https-only true
VNet Integration + Private Endpoints
App Service’in DB’ye, Cosmos’a, Key Vault’a private endpoint üzerinden erişimi:
# App Service VNet integration
az webapp vnet-integration add -g rg-web -n app-rezervasyon
--vnet vnet-prod --subnet subnet-appservice
# DB private endpoint zaten var, App Service VNet'ten erişebilir
# Public endpoint kapatma (sadece VNet'ten gelsin)
az webapp update -g rg-web -n app-rezervasyon
--public-network-access Disabled
# Front Door üzerinden public erişim sağlanıyor
CI/CD: GitHub Actions
name: deploy-app
on:
push:
branches: [main]
jobs:
build-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with: { dotnet-version: '8.0' }
- run: dotnet publish -c Release -o ./publish
- uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- uses: azure/webapps-deploy@v3
with:
app-name: app-rezervasyon
slot-name: staging
package: ./publish
- run: ./scripts/smoke-test.sh https://app-rezervasyon-staging.azurewebsites.net
- run: az webapp deployment slot swap -g rg-web -n app-rezervasyon --slot staging --target-slot production
Sonuçlar
| Metrik | Önce (VM) | Sonra (App Service) |
|---|---|---|
| Deployment süresi | ~~45 dk (manuel) | ~~6 dk (CI/CD) |
| Deployment downtime | ~~5-10 dk | ~~0 (slot swap) |
| Sezon scale-out süresi | ~~saatler (manuel VM) | ~~5 dk (autoscale) |
| Aylık BT operasyon yükü | ~~80 saat | ~~25 saat |
| Aylık altyapı maliyeti | ~~$1.840 (18 VM, sabit) | ~~$1.080 ortalama (autoscale) |
Sahada Düşülen Üç Tuzak
- Her app’e ayrı plan açmak: Aylık fatura katlanır. Trafik benzeri app’ler paylaşımlı plan’da.
- Slot warm-up’ı atlamak: Cold start’lı app swap sonrası ilk request’lerde yavaş. App Service “warmup” ayarı şart.
- VNet integration’ı sonradan eklemek: VNet’e bağladıktan sonra DNS + connection string güncellenmeli, hatalar oluşur. Day 1 tasarım.
CloudSpark olarak Azure App Service migration, deployment slot stratejisi, autoscale tasarımı, VNet integration ve sezon trafiği yönetimi için danışmanlık veriyoruz.



