Azure CDN ile İçerik Dağıtım Ağı Kurulumu

Web sitenizin kullanıcıları farklı coğrafyalarda dağılmışsa ve sayfa yükleme süreleri canınızı sıkıyorsa, CDN tam da ihtiyacınız olan şey. Azure CDN, Microsoft’un global altyapısını kullanarak statik içeriklerinizi kullanıcılara en yakın edge node’dan sunmanızı sağlıyor. Bu yazıda sıfırdan bir Azure CDN kurulumu yapacağız, gerçek dünya senaryolarıyla pekiştireceğiz ve production ortamında karşılaşacağınız tipik sorunlara çözüm bulacağız.

Azure CDN Nedir ve Neden Kullanmalısınız

CDN’in temel mantığı basit: içeriğinizi dünyanın farklı noktalarındaki sunuculara kopyalarsınız, kullanıcı size istek attığında içerik kaynaktan değil, ona en yakın noktadan gelir. Azure CDN bu işi Microsoft’un 100’den fazla ülkedeki edge location’ları üzerinden yapıyor.

Tipik bir senaryo düşünelim: İstanbul’da barındırdığınız bir e-ticaret sitesini Japonya’dan ziyaret eden bir kullanıcı, büyük görselleri her seferinde İstanbul’dan çekmek zorunda kalır. 200ms’lik bir gecikme, conversion rate üzerinde doğrudan etkisi olan bir metriktir. CDN bu gecikmeyi Tokyo edge’inden sunarak minimuma indirir.

Azure CDN’in sunduğu başlıca avantajlar:

  • Coğrafi yakınlık: İçerik kullanıcıya en yakın PoP’tan (Point of Presence) sunulur
  • Origin sunucu yükünü azaltma: Statik içerik istekleri origin’e hiç ulaşmaz
  • DDoS koruması: Azure’un yerleşik DDoS koruma katmanından yararlanırsınız
  • HTTPS ve HTTP/2 desteği: Kutu dışında geliyor, ekstra yapılandırma gerektirmez
  • Özelleştirilebilir önbellekleme: Cache kurallarını içerik tipine göre granüler ayarlarsınız
  • Gerçek zamanlı analitik: Hangi içeriğin nereden ne kadar çekildiğini görebilirsiniz

Ön Gereksinimler

Başlamadan önce şunlara ihtiyacınız var:

  • Aktif bir Azure aboneliği
  • Azure CLI kurulu ve authenticate edilmiş (az login yapılmış)
  • Bir Azure Storage Account veya App Service (origin olarak kullanacağız)
  • Özel domain kullanacaksanız DNS yönetimi erişimi

Azure CLI versiyonunuzu kontrol edin:

az --version
az extension add --name cdn

Resource Group ve Storage Account Oluşturma

Önce temel altyapıyı kuralım. CDN için origin olarak Azure Blob Storage kullanacağız:

# Resource group oluştur
az group create 
  --name rg-cdn-production 
  --location westeurope

# Storage account oluştur (globally unique isim gerekiyor)
az storage account create 
  --name stcdnproduction2024 
  --resource-group rg-cdn-production 
  --location westeurope 
  --sku Standard_LRS 
  --kind StorageV2 
  --allow-blob-public-access true

# Static website özelliğini etkinleştir
az storage blob service-properties update 
  --account-name stcdnproduction2024 
  --static-website 
  --index-document index.html 
  --404-document 404.html

Static website özelliğini açtığınızda Azure size $web adında özel bir container oluşturur. İçeriklerinizi buraya yükleyeceksiniz.

# Test içerikleri yükle
echo "<html><body><h1>CDN Test Sayfası</h1></body></html>" > index.html

az storage blob upload 
  --account-name stcdnproduction2024 
  --container-name '$web' 
  --name index.html 
  --file index.html 
  --content-type "text/html"

# Origin URL'ini öğren
az storage account show 
  --name stcdnproduction2024 
  --resource-group rg-cdn-production 
  --query "primaryEndpoints.web" 
  --output tsv

CDN Profile ve Endpoint Oluşturma

Azure CDN’de iki katman var: CDN Profile (tier ve provider seçimi) ve CDN Endpoint (asıl yapılandırma). Bir profile altında birden fazla endpoint açabilirsiniz.

Azure’da üç farklı CDN provider seçeneği var:

  • Microsoft CDN (Standard): Azure-native, temel özellikler, uygun maliyet
  • Verizon Premium: Gelişmiş analytics, rules engine, enterprise özellikler
  • Akamai Standard: Özellikle media streaming için optimize, büyük ölçek
# CDN Profile oluştur (Microsoft Standard kullanıyoruz)
az cdn profile create 
  --name cdn-profile-production 
  --resource-group rg-cdn-production 
  --sku Standard_Microsoft 
  --location global

# CDN Endpoint oluştur
az cdn endpoint create 
  --name cdnendpoint-myapp 
  --profile-name cdn-profile-production 
  --resource-group rg-cdn-production 
  --origin stcdnproduction2024.z6.web.core.windows.net 
  --origin-host-header stcdnproduction2024.z6.web.core.windows.net 
  --enable-compression true 
  --content-types-to-compress "text/html" "text/css" "application/javascript" "application/json" 
  --query-string-caching-behavior IgnoreQueryString

Endpoint oluşturulduktan sonra cdnendpoint-myapp.azureedge.net şeklinde bir URL alacaksınız. Global propagation 10-15 dakika sürebilir, beklemekte fayda var.

Cache Kuralları Yapılandırması

Varsayılan cache davranışı çoğu zaman yeterli değil. İçerik tipine göre özelleştirilmiş cache kuralları performansı dramatik biçimde artırır:

# Cache rule ekle - statik asset'ler için uzun TTL
az cdn endpoint rule add 
  --resource-group rg-cdn-production 
  --profile-name cdn-profile-production 
  --name cdnendpoint-myapp 
  --order 1 
  --rule-name "StaticAssetsCaching" 
  --match-variable UrlFileExtension 
  --operator Contains 
  --match-values "jpg" "jpeg" "png" "gif" "webp" "svg" "ico" 
  --action-name CacheExpiration 
  --cache-behavior SetIfMissing 
  --cache-duration "30.00:00:00"

# CSS ve JS için 7 gün cache
az cdn endpoint rule add 
  --resource-group rg-cdn-production 
  --profile-name cdn-profile-production 
  --name cdnendpoint-myapp 
  --order 2 
  --rule-name "CssJsCaching" 
  --match-variable UrlFileExtension 
  --operator Contains 
  --match-values "css" "js" 
  --action-name CacheExpiration 
  --cache-behavior SetIfMissing 
  --cache-duration "7.00:00:00"

# HTML dosyaları için kısa cache (SEO ve içerik güncelliği için)
az cdn endpoint rule add 
  --resource-group rg-cdn-production 
  --profile-name cdn-profile-production 
  --name cdnendpoint-myapp 
  --order 3 
  --rule-name "HtmlCaching" 
  --match-variable UrlFileExtension 
  --operator Contains 
  --match-values "html" "htm" 
  --action-name CacheExpiration 
  --cache-behavior Override 
  --cache-duration "0.01:00:00"

Önemli not: CSS ve JS dosyalarında 7 günlük cache süresi agresif görünebilir. Ancak bu stratejiyi, dosya adlarına hash ekleyerek kullanırsanız (örn. app.a3f9b2.js) deployment sonrası önbellek sorunları yaşamazsınız. Bu yaklaşım cache busting olarak bilinir.

Özel Domain ve HTTPS Yapılandırması

Production ortamında cdnendpoint-myapp.azureedge.net gibi bir URL kullanmazsınız. Özel domain bağlamak için:

# Önce DNS tarafında CNAME oluşturun:
# cdn.siteniz.com -> cdnendpoint-myapp.azureedge.net

# CNAME propagandanı doğrula
dig cdn.siteniz.com CNAME +short

# Özel domain ekle
az cdn custom-domain create 
  --resource-group rg-cdn-production 
  --endpoint-name cdnendpoint-myapp 
  --profile-name cdn-profile-production 
  --name custom-domain-myapp 
  --hostname cdn.siteniz.com

# HTTPS'i etkinleştir (Azure managed certificate - ücretsiz!)
az cdn custom-domain enable-https 
  --resource-group rg-cdn-production 
  --endpoint-name cdnendpoint-myapp 
  --profile-name cdn-profile-production 
  --name custom-domain-myapp

Azure managed certificate ile sertifika yenileme işlemi otomatik oluyor. Kendi sertifikanızı kullanmak istiyorsanız Key Vault entegrasyonuna bakmanız gerekiyor.

Cache Temizleme (Purge) İşlemleri

Deployment yaptınız, içerik güncellendi ama CDN hâlâ eski içeriği gösteriyor. Bu durumda cache purge şart:

# Belirli dosyaları temizle
az cdn endpoint purge 
  --resource-group rg-cdn-production 
  --profile-name cdn-profile-production 
  --name cdnendpoint-myapp 
  --content-paths "/index.html" "/css/main.css" "/js/app.js"

# Tüm cache'i temizle (dikkatli kullanın, origin yükü artar)
az cdn endpoint purge 
  --resource-group rg-cdn-production 
  --profile-name cdn-profile-production 
  --name cdnendpoint-myapp 
  --content-paths "/*"

# Spesifik dizini temizle
az cdn endpoint purge 
  --resource-group rg-cdn-production 
  --profile-name cdn-profile-production 
  --name cdnendpoint-myapp 
  --content-paths "/images/*" "/css/*"

CI/CD pipeline’ınıza deployment sonrası otomatik purge eklemek iyi bir pratik. Aşağıda basit bir deployment script örneği:

#!/bin/bash
# deploy-and-purge.sh

set -e

RESOURCE_GROUP="rg-cdn-production"
CDN_PROFILE="cdn-profile-production"
CDN_ENDPOINT="cdnendpoint-myapp"
STORAGE_ACCOUNT="stcdnproduction2024"

echo "==> Build dosyaları yükleniyor..."
az storage blob sync 
  --source "./dist" 
  --container '$web' 
  --account-name $STORAGE_ACCOUNT 
  --delete-destination true

echo "==> CDN cache temizleniyor..."
az cdn endpoint purge 
  --resource-group $RESOURCE_GROUP 
  --profile-name $CDN_PROFILE 
  --name $CDN_ENDPOINT 
  --content-paths "/*.html" "/css/*" "/js/*"

echo "==> Deployment tamamlandı!"
echo "URL: https://cdn.siteniz.com"

Geo-Filtering ile Erişim Kısıtlama

Yasal gereksinimler veya lisans kısıtlamaları nedeniyle belirli ülkelerden erişimi engellemek gerekebilir:

# Belirli ülkeleri engelle (ülke kodları ISO 3166-1 alpha-2)
az cdn endpoint rule add 
  --resource-group rg-cdn-production 
  --profile-name cdn-profile-production 
  --name cdnendpoint-myapp 
  --order 10 
  --rule-name "GeoRestriction" 
  --match-variable RemoteAddress 
  --operator GeoMatch 
  --match-values "CN" "RU" 
  --action-name UrlRedirect 
  --redirect-type Found 
  --redirect-protocol Https 
  --destination-hostname "blocked.siteniz.com"

Monitoring ve Alerting Kurulumu

CDN’i kurdunuz, çalışıyor. Ama ne kadar iyi çalışıyor? Log Analytics entegrasyonu olmadan kör uçuyorsunuz:

# Log Analytics Workspace oluştur
az monitor log-analytics workspace create 
  --resource-group rg-cdn-production 
  --workspace-name law-cdn-monitoring 
  --location westeurope 
  --sku PerGB2018

# Workspace ID'yi al
WORKSPACE_ID=$(az monitor log-analytics workspace show 
  --resource-group rg-cdn-production 
  --workspace-name law-cdn-monitoring 
  --query id 
  --output tsv)

# CDN endpoint için diagnostic settings ekle
CDN_ENDPOINT_ID=$(az cdn endpoint show 
  --resource-group rg-cdn-production 
  --profile-name cdn-profile-production 
  --name cdnendpoint-myapp 
  --query id 
  --output tsv)

az monitor diagnostic-settings create 
  --name "cdn-diagnostics" 
  --resource $CDN_ENDPOINT_ID 
  --workspace $WORKSPACE_ID 
  --logs '[{"category": "CoreAnalytics", "enabled": true}]' 
  --metrics '[{"category": "AllMetrics", "enabled": true}]'

# Yüksek 4xx hata oranı için alert oluştur
az monitor metrics alert create 
  --name "CDN-High-4xx-Rate" 
  --resource-group rg-cdn-production 
  --scopes $CDN_ENDPOINT_ID 
  --condition "avg Percentage4XX > 5" 
  --window-size 5m 
  --evaluation-frequency 1m 
  --severity 2 
  --description "CDN 4xx hata oranı %5'i aştı"

Gerçek Dünya Senaryosu: E-Ticaret Sitesi için CDN Yapılandırması

Bir e-ticaret platformu için tipik CDN mimarisi şöyle olabilir:

Origin’ler:

  • Statik asset’ler: Azure Blob Storage (resimler, CSS, JS)
  • API: Azure App Service veya AKS üzerinde çalışan backend
  • Ana site: App Service üzerinde SSR (Server-Side Rendering)

Bu senaryo için birden fazla origin ve origin group kullanmanız gerekir:

# İkinci origin ekle (App Service için)
az cdn endpoint origin add 
  --resource-group rg-cdn-production 
  --profile-name cdn-profile-production 
  --endpoint-name cdnendpoint-myapp 
  --name origin-appservice 
  --host-name myapp.azurewebsites.net 
  --origin-host-header myapp.azurewebsites.net 
  --http-port 80 
  --https-port 443 
  --priority 1 
  --weight 1000

# /api/ path'i için farklı cache davranışı
# API endpoint'leri genellikle cache edilmez
az cdn endpoint rule add 
  --resource-group rg-cdn-production 
  --profile-name cdn-profile-production 
  --name cdnendpoint-myapp 
  --order 5 
  --rule-name "ApiNoCache" 
  --match-variable UrlPath 
  --operator BeginsWith 
  --match-values "/api/" 
  --action-name CacheExpiration 
  --cache-behavior BypassCache

Ürün görselleri için özel bir senaryo: E-ticaret sitelerinde görsel CDN performansı kritik. Bir ürünün birden fazla varyantı (renk, beden) olduğunda URL’deki query string’e göre farklı görseller sunulabilir. Bu durumda IgnoreQueryString yerine UseQueryString seçeneğini tercih etmelisiniz:

az cdn endpoint update 
  --resource-group rg-cdn-production 
  --profile-name cdn-profile-production 
  --name cdnendpoint-myapp 
  --query-string-caching-behavior UseQueryString

Yaygın Sorunlar ve Çözümleri

Sorun 1: Cache’lenmiş içerik güncellenmiyor

Origin’deki içeriği güncellediniz ama CDN hâlâ eski içeriği döndürüyor. Önce Cache-Control header’larını kontrol edin:

# Origin'den dönen header'ları kontrol et
curl -I https://stcdnproduction2024.z6.web.core.windows.net/index.html

# CDN'den dönen header'ları kontrol et
curl -I https://cdnendpoint-myapp.azureedge.net/index.html

# X-Cache header'ına bakın:
# X-Cache: HIT = CDN'den geliyor
# X-Cache: MISS = Origin'den geliyor

Sorun 2: CORS hataları

CDN arkasındaki storage’a farklı domain’den istek atıldığında CORS hatası alabilirsiniz:

# Storage account CORS ayarlarını güncelle
az storage cors add 
  --account-name stcdnproduction2024 
  --services b 
  --methods GET HEAD OPTIONS 
  --origins "https://siteniz.com" "https://cdn.siteniz.com" 
  --allowed-headers "*" 
  --max-age 3600

Sorun 3: Endpoint propagation süresi

Yeni endpoint veya kural ekledikten sonra değişiklikler 10-15 dakika içinde global olarak yayılır. Acil durumlarda belirli PoP’ları test etmek yerine propagation’ın tamamlanmasını beklemek daha sağlıklı.

Sorun 4: Origin health check başarısız

# Endpoint durumunu kontrol et
az cdn endpoint show 
  --resource-group rg-cdn-production 
  --profile-name cdn-profile-production 
  --name cdnendpoint-myapp 
  --query "resourceState" 
  --output tsv

# Origin health'i kontrol et
az cdn origin show 
  --resource-group rg-cdn-production 
  --profile-name cdn-profile-production 
  --endpoint-name cdnendpoint-myapp 
  --name origin-storage

Maliyet Optimizasyonu

CDN maliyeti iki bileşenden oluşur: çıkış trafiği (egress) ve istek sayısı. Optimizasyon için dikkat edilmesi gerekenler:

  • Agresif cache stratejisi: TTL’leri mümkün olduğunca uzun tutun, cache hit rate’i artırın
  • Compression: Gzip/Brotli sıkıştırmayı aktif edin, transfer boyutunu azaltın
  • Gereksiz dosyaları CDN’e koyma: Log dosyaları, geçici dosyalar origin’de kalsın
  • Bölge bazlı fiyatlandırma: Zone 1 (Kuzey Amerika, Avrupa) en ucuz, Zone 5 en pahalı. Trafiğinizin coğrafi dağılımını analiz edin
# Son 30 günün cache hit ratio'sunu sorgula (Log Analytics üzerinden)
az monitor log-analytics query 
  --workspace $WORKSPACE_ID 
  --analytics-query "
    AzureDiagnostics
    | where ResourceType == 'ENDPOINTS' and Category == 'CoreAnalytics'
    | summarize 
        CacheHits = sum(requestCountCacheHit_d),
        CacheMisses = sum(requestCountCacheMiss_d)
    | extend CacheHitRatio = CacheHits * 100.0 / (CacheHits + CacheMisses)
    | project CacheHitRatio
  " 
  --output table

%80’in üzerinde cache hit ratio iyi bir hedef. Bunun altındaysa cache kurallarınızı gözden geçirin.

Terraform ile Infrastructure as Code

Tek seferlik kurulumlar için CLI yeterli, ama production ortamında her şeyi kod olarak yönetmek şart. Kısa bir Terraform örneği:

# main.tf dosyası oluştur ve terraform ile deploy et
cat > cdn-terraform.tf << 'EOF'
resource "azurerm_cdn_profile" "main" {
  name                = "cdn-profile-production"
  location            = "global"
  resource_group_name = azurerm_resource_group.main.name
  sku                 = "Standard_Microsoft"
}

resource "azurerm_cdn_endpoint" "main" {
  name                = "cdnendpoint-myapp"
  profile_name        = azurerm_cdn_profile.main.name
  location            = "global"
  resource_group_name = azurerm_resource_group.main.name
  
  is_compression_enabled = true
  content_types_to_compress = [
    "text/html",
    "text/css",
    "application/javascript",
    "application/json",
    "image/svg+xml"
  ]
  
  querystring_caching_behaviour = "IgnoreQueryString"

  origin {
    name      = "storage-origin"
    host_name = azurerm_storage_account.main.primary_blob_host
  }

  delivery_rule {
    name  = "StaticAssets"
    order = 1

    url_file_extension_condition {
      operator     = "Contains"
      match_values = ["jpg", "png", "css", "js"]
    }

    cache_expiration_action {
      behavior = "SetIfMissing"
      duration = "7.00:00:00"
    }
  }
}
EOF

terraform init
terraform plan -out=tfplan
terraform apply tfplan

Sonuç

Azure CDN kurulumu göründüğünden daha az karmaşık, ama doğru yapılandırma detaylarda gizleniyor. Önbellek stratejisini içerik tipine göre granüler ayarlamak, CORS kurallarını doğru tanımlamak ve CI/CD pipeline’ınıza purge adımını entegre etmek, production ortamında yaşanabilecek sorunların büyük çoğunluğunun önüne geçiyor.

Yapılandırmanızı Infrastructure as Code ile yönetin, monitoring’i günden bir kurun ve cache hit ratio’nuzu düzenli takip edin. Yüksek bir cache hit ratio hem performansınızı artırır hem de origin sunucularınızdaki yükü azaltır, hem de CDN faturanızı düşürür. Üç taraflı kazanım bu.

Özel domain ve managed certificate kombinasyonu ile birkaç saat içinde global ölçekte, HTTPS destekli, optimize edilmiş bir içerik dağıtım altyapısı kurabilirsiniz. Azure’un CDN altyapısı olgunlaşmış bir ürün ve büyük ölçekli production workload’ları için gayet güvenilir.

Bir yanıt yazın

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