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 westeuropeile mevcut versiyonları görebilirsin - –node-vm-size: Node’ların VM boyutu.
Standard_D4s_v34 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.
