Azure Kubernetes Service (AKS) Kurulumu ve Yapılandırması

Kubernetes’i kendi altyapında kurup yönetmek gerçekten can sıkıcı olabiliyor. Master node’ların bakımı, etcd yedeklemeleri, CNI eklentileri, sertifika yenilemeleri… Bunların hepsiyle uğraşmak yerine işin asıl önemli kısmına, yani uygulamalarına odaklanmak istiyorsan Azure Kubernetes Service tam da aradığın şey. Microsoft’un yönetilen Kubernetes servisi olan AKS, control plane’i senin için yönetiyor, otomatik ölçeklendirme, Azure AD entegrasyonu ve monitoring gibi özellikleri hazır sunuyor. Bu yazıda sıfırdan production’a hazır bir AKS cluster’ı nasıl kurarsın, adım adım anlatacağım.

Ön Gereksinimler ve Hazırlık

Başlamadan önce birkaç şeyin hazır olması gerekiyor. Azure CLI’nın güncel versiyonunu kurman şart çünkü eski versiyonlarda bazı AKS özellikleri çalışmıyor.

# Azure CLI kurulumu (Ubuntu/Debian)
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

# Versiyon kontrolü - en az 2.50 olmalı
az --version

# Azure'a giriş yap
az login

# Hangi subscription'da çalıştığını kontrol et
az account show

# Birden fazla subscription varsa doğru olanı seç
az account set --subscription "Production-Subscription"

Kubectl de lazım olacak. AKS bunu otomatik kurabilir ama manuel kurulum daha kontrollü:

# kubectl kurulumu
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/

# kubectl versiyon kontrolü
kubectl version --client

Resource Group ve Temel Yapı Hazırlığı

AKS cluster’ını oluşturmadan önce bir resource group’a ihtiyacın var. Naming convention’ına dikkat et, production ortamında sonradan değiştirmek can sıkıcı oluyor.

# Değişkenleri tanımla - bunu bir script haline getirmek mantıklı
RESOURCE_GROUP="rg-production-aks"
LOCATION="westeurope"
CLUSTER_NAME="aks-production-01"
NODE_RESOURCE_GROUP="rg-aks-nodes-production"

# Resource group oluştur
az group create 
  --name $RESOURCE_GROUP 
  --location $LOCATION 
  --tags Environment=Production Team=Platform

# Mevcut resource group'ları listele
az group list --output table

West Europe seçimimin nedeni Türkiye’ye olan düşük latency. Eğer KVKK veya veri yerelleştirme gereksinimlerin varsa bu konuya dikkat etmen gerekiyor. Şu an için Azure’da Türkiye region’ı da mevcut ama bazı servisler henüz orada desteklenmiyor.

Virtual Network Yapılandırması

Birçok tutorial doğrudan cluster oluşturmaya atlıyor ama production’da mutlaka özel bir VNet kullanmalısın. Hem güvenlik hem de network segmentasyonu açısından kritik.

# VNet ve subnet oluştur
VNET_NAME="vnet-production"
SUBNET_NAME="subnet-aks-nodes"

az network vnet create 
  --resource-group $RESOURCE_GROUP 
  --name $VNET_NAME 
  --address-prefix 10.0.0.0/8 
  --subnet-name $SUBNET_NAME 
  --subnet-prefix 10.240.0.0/16

# Subnet ID'sini al - cluster oluştururken lazım olacak
SUBNET_ID=$(az network vnet subnet show 
  --resource-group $RESOURCE_GROUP 
  --vnet-name $VNET_NAME 
  --name $SUBNET_NAME 
  --query id 
  --output tsv)

echo "Subnet ID: $SUBNET_ID"

Pod CIDR ve service CIDR’larını da planlamalısın. Varsayılan değerler çoğu zaman şirket ağıyla çakışabiliyor, özellikle VPN kullanıyorsan bu durum production’da gerçek bir baş ağrısına dönüşebilir.

AKS Cluster Oluşturma

İşte asıl kısım. Burada pek çok parametre var ve her birinin ne işe yaradığını bilmek önemli.

# Production AKS cluster oluşturma
az aks create 
  --resource-group $RESOURCE_GROUP 
  --name $CLUSTER_NAME 
  --node-resource-group $NODE_RESOURCE_GROUP 
  --location $LOCATION 
  --kubernetes-version "1.28.3" 
  --node-count 3 
  --node-vm-size "Standard_D4s_v3" 
  --os-disk-size-gb 128 
  --network-plugin azure 
  --vnet-subnet-id $SUBNET_ID 
  --service-cidr 10.0.0.0/16 
  --dns-service-ip 10.0.0.10 
  --enable-managed-identity 
  --enable-addons monitoring 
  --workspace-resource-id "/subscriptions/SUB-ID/resourcegroups/rg-monitoring/providers/microsoft.operationalinsights/workspaces/law-production" 
  --enable-cluster-autoscaler 
  --min-count 3 
  --max-count 10 
  --zones 1 2 3 
  --tags Environment=Production Team=Platform 
  --generate-ssh-keys

Kullandığım parametreleri açıklayayım:

  • –kubernetes-version: Hangi Kubernetes versiyonunun kurulacağını belirler. az aks get-versions --location westeurope ile mevcut versiyonları görebilirsin
  • –node-vm-size: Node’ların VM boyutu. Standard_D4s_v3 4 vCPU ve 16 GB RAM demek, çoğu workload için iyi bir başlangıç noktası
  • –network-plugin azure: Azure CNI kullanır, pod’lara doğrudan VNet IP adresi verir. kubenet‘ten farklı olarak her pod VNet’te görünür olur
  • –enable-managed-identity: Service principal yerine managed identity kullanır, çok daha güvenli
  • –enable-cluster-autoscaler: Yük arttığında otomatik olarak yeni node ekler, azaldığında kaldırır
  • –zones 1 2 3: Availability zone dağılımı, production’da olmazsa olmaz
  • –min-count ve –max-count: Autoscaler sınırları

Cluster oluşturma 5-10 dakika sürebiliyor. Bunu beklerken bir kahve al.

kubectl Yapılandırması ve Bağlantı Testi

Cluster hazır olduğunda kubectl’i bağlamalısın:

# kubeconfig dosyasını güncelle
az aks get-credentials 
  --resource-group $RESOURCE_GROUP 
  --name $CLUSTER_NAME 
  --overwrite-existing

# Bağlantıyı test et
kubectl get nodes

# Node detaylarını gör
kubectl get nodes -o wide

# Tüm pod'ları kontrol et
kubectl get pods --all-namespaces

Çıktıda node’ların Ready durumunda olduğunu görmelisin. NotReady görüyorsan biraz bekle, sistem bileşenleri henüz başlamıyor olabilir.

Node Pool Yönetimi

Tek node pool her işi yapabilir ama production’da farklı workload’lar için farklı node pool’lar kullanmak mantıklı. Mesela GPU gerektiren ML işleri için ayrı, normal API servisleri için ayrı pool.

# Sistem workload'ları için ayrı bir sistem node pool zaten mevcut
# Uygulama workload'ları için yeni pool ekle
az aks nodepool add 
  --resource-group $RESOURCE_GROUP 
  --cluster-name $CLUSTER_NAME 
  --name "apppool" 
  --node-count 3 
  --node-vm-size "Standard_D8s_v3" 
  --os-disk-size-gb 256 
  --mode User 
  --enable-cluster-autoscaler 
  --min-count 3 
  --max-count 20 
  --zones 1 2 3 
  --labels workload=application 
  --node-taints workload=application:NoSchedule

# Node pool listesini kontrol et
az aks nodepool list 
  --resource-group $RESOURCE_GROUP 
  --cluster-name $CLUSTER_NAME 
  --output table

Taint kullanmak, yanlışlıkla sistem pod’larının uygulama node’larına ya da tam tersi bir durumun önüne geçiyor. Deployment’larında buna uygun toleration eklemeyi unutma.

Azure AD Entegrasyonu ve RBAC

Bu kısmı atlayan çoğu ekip sonradan pişman oluyor. Production’da kimin cluster’a ne yapabileceğini mutlaka Azure AD üzerinden yönet.

# Azure AD entegrasyonunu etkinleştir (cluster oluştururken da yapılabilir)
az aks update 
  --resource-group $RESOURCE_GROUP 
  --name $CLUSTER_NAME 
  --enable-aad 
  --aad-admin-group-object-ids "AAD-GROUP-OBJECT-ID"

# Admin erişimi için kubeconfig al
az aks get-credentials 
  --resource-group $RESOURCE_GROUP 
  --name $CLUSTER_NAME 
  --admin

# Namespace bazlı RBAC örneği
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: dev-team-binding
  namespace: development
subjects:
- kind: Group
  name: "AAD-DEV-GROUP-OBJECT-ID"
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: edit
  apiGroup: rbac.authorization.k8s.io
EOF

Bu yapılandırmayla dev ekibin yalnızca development namespace’ine erişimi olur, production’a dokunamaz.

Ingress Controller Kurulumu

Cluster hazır ama dışarıdan erişim için Ingress Controller gerekiyor. NGINX Ingress Controller en yaygın kullanılan seçenek:

# Helm kurulu değilse kur
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# NGINX Ingress Controller Helm repo ekle
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

# Namespace oluştur
kubectl create namespace ingress-nginx

# NGINX Ingress Controller kur
helm install ingress-nginx ingress-nginx/ingress-nginx 
  --namespace ingress-nginx 
  --set controller.replicaCount=2 
  --set controller.nodeSelector."kubernetes.io/os"=linux 
  --set defaultBackend.nodeSelector."kubernetes.io/os"=linux 
  --set controller.service.annotations."service.beta.kubernetes.io/azure-load-balancer-health-probe-request-path"=/healthz

# External IP'yi kontrol et (birkaç dakika bekle)
kubectl get service ingress-nginx-controller 
  --namespace ingress-nginx 
  --watch

EXTERNAL-IP kolonunda gerçek bir IP görünene kadar bekle. Bu IP adresine DNS kaydı oluşturarak domain’ini bağlayabilirsin.

Container Registry Entegrasyonu

AKS’i Azure Container Registry ile bağlamak neredeyse zorunlu. Özel image’larını çekmek için credential yönetimiyle uğraşmak yerine managed identity üzerinden yap:

# ACR oluştur (eğer yoksa)
ACR_NAME="acrproduction001"

az acr create 
  --resource-group $RESOURCE_GROUP 
  --name $ACR_NAME 
  --sku Premium 
  --location $LOCATION

# AKS'e ACR erişimi ver
az aks update 
  --resource-group $RESOURCE_GROUP 
  --name $CLUSTER_NAME 
  --attach-acr $ACR_NAME

# ACR'ye image push et ve AKS'ten çek
az acr login --name $ACR_NAME

# Test için bir image tag'le ve push et
docker tag myapp:latest $ACR_NAME.azurecr.io/myapp:latest
docker push $ACR_NAME.azurecr.io/myapp:latest

Artık deployment’larında $ACR_NAME.azurecr.io/myapp:latest kullanabilirsin, imagePullSecret’a gerek yok.

Monitoring ve Logging

Azure Monitor ile entegrasyon cluster oluşturulurken yapıldı ama birkaç ek yapılandırma gerekiyor:

# Container Insights'ın çalıştığını kontrol et
kubectl get pods -n kube-system | grep omsagent

# Prometheus metriklerini etkinleştir
az aks update 
  --resource-group $RESOURCE_GROUP 
  --name $CLUSTER_NAME 
  --enable-azure-monitor-metrics

# Diagnostic settings - audit log'ları kaydet
az monitor diagnostic-settings create 
  --resource "/subscriptions/SUB-ID/resourcegroups/$RESOURCE_GROUP/providers/microsoft.containerservice/managedclusters/$CLUSTER_NAME" 
  --name "aks-diagnostics" 
  --workspace "/subscriptions/SUB-ID/resourcegroups/rg-monitoring/providers/microsoft.operationalinsights/workspaces/law-production" 
  --logs '[{"category":"kube-apiserver","enabled":true},{"category":"kube-controller-manager","enabled":true},{"category":"kube-scheduler","enabled":true},{"category":"kube-audit","enabled":true},{"category":"guard","enabled":true}]'

Audit log’ları mutlaka etkinleştir. Birisi cluster’da beklenmedik bir şey yaparsa ilk bakacağın yer burası olacak.

Güvenlik Sertleştirme

Production cluster’ı için birkaç kritik güvenlik adımı:

# API server'a yetkisiz erişimi kısıtla - sadece belirli IP'lerden erişime izin ver
az aks update 
  --resource-group $RESOURCE_GROUP 
  --name $CLUSTER_NAME 
  --api-server-authorized-ip-ranges "203.0.113.0/24,10.0.0.0/8"

# Pod Security Standards etkinleştir
kubectl label namespace production 
  pod-security.kubernetes.io/enforce=restricted 
  pod-security.kubernetes.io/audit=restricted 
  pod-security.kubernetes.io/warn=restricted

# Network Policy örneği - namespace izolasyonu
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-ingress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
EOF

–api-server-authorized-ip-ranges özelliğini kullanırken dikkatli ol. CI/CD pipeline’larının IP’lerini de eklemeyi unutursan deployment’lar başarısız olur, bunu yaşayan tek kişi ben değilimdir.

Upgrade Stratejisi

Cluster’ı güncel tutmak önemli ama production’da dikkatli yapılması gerekiyor:

# Mevcut versiyon ve mevcut upgrade'leri gör
az aks get-upgrades 
  --resource-group $RESOURCE_GROUP 
  --name $CLUSTER_NAME 
  --output table

# Node pool'u kontrollü upgrade et (önce test et)
az aks nodepool upgrade 
  --resource-group $RESOURCE_GROUP 
  --cluster-name $CLUSTER_NAME 
  --name agentpool 
  --kubernetes-version "1.29.0" 
  --max-surge 1 
  --no-wait

# Upgrade durumunu izle
az aks show 
  --resource-group $RESOURCE_GROUP 
  --name $CLUSTER_NAME 
  --query "agentPoolProfiles[].{Name:name,Version:orchestratorVersion,Status:provisioningState}" 
  --output table

–max-surge 1 parametresi upgrade sırasında bir fazladan node oluşturarak çalışır, bu sayede mevcut workload’lar kesintisiz devam eder. Production’da bunu kullanmak zorundasın.

Maliyet Optimizasyonu

AKS’te fatura sürprizlerini önlemek için birkaç pratik adım:

# Spot instance node pool ekle - yüzde 80'e kadar tasarruf
az aks nodepool add 
  --resource-group $RESOURCE_GROUP 
  --cluster-name $CLUSTER_NAME 
  --name "spotpool" 
  --node-count 0 
  --node-vm-size "Standard_D8s_v3" 
  --priority Spot 
  --eviction-policy Delete 
  --spot-max-price -1 
  --enable-cluster-autoscaler 
  --min-count 0 
  --max-count 10 
  --node-taints "kubernetes.azure.com/scalesetpriority=spot:NoSchedule"

# Kullanılmayan node'ları temizle
az aks nodepool scale 
  --resource-group $RESOURCE_GROUP 
  --cluster-name $CLUSTER_NAME 
  --name apppool 
  --node-count 3

Spot instance’ları batch job’lar, CI/CD worker’ları ve fault tolerant uygulamalar için kullanabilirsin. Kritik servisler için kesinlikle regular node pool’da tut.

Gerçek Dünya Senaryosu: Çok Ortamlı Yapı

Tipik bir şirkette development, staging ve production ortamları oluyor. Bu ortamları yönetmek için şu yaklaşımı kullanıyorum:

Ayrı cluster yerine aynı cluster’da namespace izolasyonu tercih ediyorum maliyeti düşürmek için. Development ve staging için cluster autoscaler min değerlerini düşük tut, production için yüksek. Her namespace için ayrı resource quota tanımla ki dev ekibi production kaynaklarını tüketmesin.

Resource quota örneği:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ResourceQuota
metadata:
  name: development-quota
  namespace: development
spec:
  hard:
    requests.cpu: "4"
    requests.memory: 8Gi
    limits.cpu: "8"
    limits.memory: 16Gi
    pods: "20"
    services: "10"
    persistentvolumeclaims: "10"
EOF

Bu yapı sayesinde dev ortamındaki bir deployment yanlışlıkla sonsuz resource istese bile production etkilenmiyor.

Yaygın Sorunlar ve Çözümleri

Production’da karşılaşabileceğin bazı durumlar:

OOMKilled pod’lar: Resource limits doğru ayarlanmamış demek. kubectl describe pod POD-NAME ile Last State bölümüne bak.

ImagePullBackOff: ACR bağlantısı kopmuş olabilir. az aks update --attach-acr ile yeniden bağla ya da managed identity’nin doğru rol atamasına sahip olduğunu kontrol et.

Node NotReady: Çoğunlukla VM boyutu yetersiz ya da disk dolu. kubectl describe node NODE-NAME ile events’lere bak.

Pending pod’lar: Node’larda yeterli resource yok ya da taint/toleration uyuşmazlığı var. kubectl describe pod POD-NAME ile Events bölümüne bak.

API server 429 hataları: Çok fazla watch/list isteği gönderiliyor. Informer cache’lerini doğru kullanan uygulama geliştir ya da rate limit ayarlarına bak.

Sonuç

AKS, Kubernetes’in operasyonel yükünü ciddi ölçüde azaltıyor. Control plane yönetimi, sertifika rotasyonu, etcd yedeklemesi gibi konularla vakit harcamak yerine uygulamalarına ve platform özelliklerine odaklanabiliyorsun. Anlattığım yapılandırmalar bir başlangıç noktası, her ortamın kendine özgü gereksinimleri olacak.

En önemli nokta şu: Cluster’ı kurduktan sonra işin bitmedi. Düzenli upgrade’leri takip et, güvenlik taramalarını otomatize et, maliyet raporlarını haftalık kontrol et. AKS Azure Cost Management ile entegre çalışıyor, tag’leri doğru kullanırsan hangi ekibin ne kadar harcadığını rahatlıkla görebilirsin.

Bir de şunu söyleyeyim: Terraform veya Bicep ile bu kurulumu Infrastructure as Code haline getirmeni şiddetle tavsiye ederim. Burada CLI komutlarını anlattım çünkü ne yaptığını görmek öğrenme aşamasında çok önemli, ama production’da her şey kod olarak yönetilmeli. Bu konuyu da ayrı bir yazıda ele alacağım.

Bir yanıt yazın

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