AWS EKS ile Kubernetes Cluster Kurulumu

Kubernetes kurulumunu kendi sunucularında yapmaya çalışıp saatlerce uğraştıktan sonra AWS EKS’i keşfeden herkes aynı şeyi söyler: “Keşke daha önce geçseydim.” EKS, yani Elastic Kubernetes Service, AWS’in yönetilen Kubernetes çözümü. Control plane’i AWS yönetiyor, sen sadece worker node’larına ve uygulamalarına odaklanıyorsun. Kulağa harika geliyor, değil mi? Ama “yönetilen” demek “sıfır konfigürasyon” demek değil. EKS kurulumunda da yapılacak onlarca şey var ve yanlış adım atınca işler karışabiliyor. Bu yazıda sıfırdan production’a hazır bir EKS cluster’ı nasıl kurarsın, adım adım anlatacağım.

Ön Hazırlık: Neye İhtiyacın Var?

Başlamadan önce birkaç şeyin hazır olması gerekiyor. AWS hesabın olmalı ve bu hesapta yeterli IAM yetkilerine sahip olman lazım. Kendi AWS hesabında çalışıyorsan sorun yok, ama şirket hesabında çalışıyorsan IAM yetkileri konusunda önceden network/cloud ekibiyle konuşman gerekebilir.

Local makinende şunların kurulu olması gerekiyor:

  • AWS CLI: AWS servislerini komut satırından yönetmek için
  • eksctl: EKS’e özel CLI aracı, hayatını çok kolaylaştırıyor
  • kubectl: Kubernetes cluster’ını yönetmek için standart araç
  • helm: Uygulama paket yöneticisi, sonradan işine yarayacak

Bunları tek tek kuralım.

AWS CLI Kurulumu

# Linux için
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

# Kurulumu doğrula
aws --version

# AWS kimlik bilgilerini yapılandır
aws configure
# AWS Access Key ID: [buraya access key]
# AWS Secret Access Key: [buraya secret key]
# Default region name: eu-west-1
# Default output format: json

eksctl Kurulumu

# Linux için eksctl kurulumu
ARCH=amd64
PLATFORM=$(uname -s)_$ARCH

curl -sLO "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_$PLATFORM.tar.gz"
tar -xzf eksctl_$PLATFORM.tar.gz -C /tmp && rm eksctl_$PLATFORM.tar.gz
sudo mv /tmp/eksctl /usr/local/bin

# Doğrulama
eksctl version

kubectl Kurulumu

# En güncel stable versiyonu indir
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

# Doğrulama
kubectl version --client

IAM Rol ve Politika Yapılandırması

EKS için iki temel IAM rolüne ihtiyacın var. Birincisi EKS cluster’ının kendisi için olan rol, ikincisi worker node’lar için olan rol. Bu rolleri elle de oluşturabilirsin ama eksctl otomatik hallediyor. Yine de ne döndüğünü anlamak için bir bakalım.

EKS Cluster Rolü için gerekli politikalar:

  • AmazonEKSClusterPolicy: Temel cluster yönetimi
  • AmazonEKSVPCResourceController: VPC kaynak kontrolü

Node Group Rolü için gerekli politikalar:

  • AmazonEKSWorkerNodePolicy: Worker node temel izinleri
  • AmazonEKS_CNI_Policy: Ağ eklentisi için
  • AmazonEC2ContainerRegistryReadOnly: ECR’dan image çekmek için
# Mevcut IAM kullanıcının EKS yetkilerini kontrol et
aws iam get-user
aws sts get-caller-identity

# Hangi politikaların attach olduğunu gör
aws iam list-attached-user-policies --user-name senin-kullanici-adin

VPC Tasarımı: Production’da En Önemli Adım

Çoğu EKS rehberinde VPC kısmı geçiştiriliyor ama bu en kritik adımlardan biri. Yanlış VPC yapısıyla kurduğun cluster’ı sonradan düzeltmek çok acı verici. Production için şunu öneriyorum:

  • En az 2, tercihen 3 Availability Zone kullan
  • Public subnet’ler için /24 CIDR (Load Balancer’lar burada)
  • Private subnet’ler için /20 CIDR (Worker node’lar burada)
  • NAT Gateway ekle (private subnet’lerden internet erişimi için)

EKS, subnet’leri otomatik keşfedebilmesi için özel tag’lere ihtiyaç duyuyor. Bu tag’leri eksctl otomatik ekliyor ama manuel kurulumda unutulabiliyor:

  • Public subnet’ler için: kubernetes.io/role/elb = 1
  • Private subnet’ler için: kubernetes.io/role/internal-elb = 1
  • Tüm subnet’ler için: kubernetes.io/cluster/CLUSTER_ADI = shared

eksctl bu tag’leri otomatik yönettiği için şimdilik endişelenme.

İlk Cluster Kurulumu: eksctl ile Basit Başlangıç

Teoriden pratiğe geçelim. İlk cluster’ımızı kuralım. Başlangıç için basit bir yapı kullanacağız, sonra production’a uygun hale getireceğiz.

# En basit haliyle cluster oluşturma (test için)
eksctl create cluster 
  --name my-first-cluster 
  --region eu-west-1 
  --nodegroup-name standard-workers 
  --node-type t3.medium 
  --nodes 2 
  --nodes-min 1 
  --nodes-max 4 
  --managed

# Bu komut yaklaşık 15-20 dakika sürer
# CloudFormation stack'leri oluşturduğunu göreceksin

Bu komut şunları otomatik yapıyor: VPC oluşturur, subnet’leri ayarlar, IAM rollerini oluşturur, EKS control plane’i başlatır, node group’u oluşturur ve kubeconfig’ini günceller. Harika değil mi?

Kurulum bittikten sonra doğrulayalım:

# Kubeconfig güncelleme (genelde eksctl hallediyor ama manuel de yapabilirsin)
aws eks update-kubeconfig --region eu-west-1 --name my-first-cluster

# Cluster bileşenlerini kontrol et
kubectl get nodes
kubectl get pods --all-namespaces
kubectl cluster-info

Production’a Hazır Cluster: YAML Config Dosyası

Komut satırı parametreleri test için güzel ama production’da her şeyi bir config dosyasında tutman gerekiyor. Hem versiyon kontrolü altında tutarsın hem de tekrar oluşturmak çok kolay olur.

# eks-production-cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: production-cluster
  region: eu-west-1
  version: "1.28"
  tags:
    Environment: production
    Team: platform
    CostCenter: engineering

vpc:
  cidr: "10.0.0.0/16"
  nat:
    gateway: HighlyAvailable  # Her AZ'de ayrı NAT Gateway
  clusterEndpoints:
    publicAccess: true
    privateAccess: true

managedNodeGroups:
  - name: general-workers
    instanceType: m5.xlarge
    minSize: 2
    maxSize: 10
    desiredCapacity: 3
    privateNetworking: true  # Worker node'lar private subnet'te
    volumeSize: 100
    volumeType: gp3
    amiFamily: AmazonLinux2
    availabilityZones:
      - eu-west-1a
      - eu-west-1b
      - eu-west-1c
    labels:
      role: general
      nodegroup: general-workers
    tags:
      k8s.io/cluster-autoscaler/enabled: "true"
      k8s.io/cluster-autoscaler/production-cluster: "owned"
    iam:
      attachPolicyARNs:
        - arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
        - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
        - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
        - arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy

  - name: spot-workers
    instanceTypes:
      - m5.xlarge
      - m5.2xlarge
      - m4.xlarge
    spot: true
    minSize: 0
    maxSize: 20
    desiredCapacity: 0
    privateNetworking: true
    labels:
      role: spot
      nodegroup: spot-workers
    taints:
      - key: spot
        value: "true"
        effect: NoSchedule

addons:
  - name: vpc-cni
    version: latest
  - name: coredns
    version: latest
  - name: kube-proxy
    version: latest
  - name: aws-ebs-csi-driver
    version: latest

cloudWatch:
  clusterLogging:
    enableTypes:
      - api
      - audit
      - authenticator
      - controllerManager
      - scheduler
# Config dosyasından cluster oluştur
eksctl create cluster -f eks-production-cluster.yaml

# Kurulumu takip et
eksctl utils describe-stacks --region=eu-west-1 --cluster=production-cluster

Cluster Autoscaler Kurulumu

Production’da workload’lar değişkendir. Gece trafik düşer, gündüz artar. Cluster Autoscaler bunu otomatik yönetir. Node group tag’lerini zaten config’de ekledik, şimdi Cluster Autoscaler’ı kuralım.

# Cluster Autoscaler için IAM politikası oluştur
cat > cluster-autoscaler-policy.json << EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "autoscaling:DescribeAutoScalingGroups",
                "autoscaling:DescribeAutoScalingInstances",
                "autoscaling:DescribeLaunchConfigurations",
                "autoscaling:DescribeScalingActivities",
                "autoscaling:DescribeTags",
                "ec2:DescribeInstanceTypes",
                "ec2:DescribeLaunchTemplateVersions"
            ],
            "Resource": ["*"]
        },
        {
            "Effect": "Allow",
            "Action": [
                "autoscaling:SetDesiredCapacity",
                "autoscaling:TerminateInstanceInAutoScalingGroup",
                "ec2:DescribeImages",
                "ec2:GetInstanceTypesFromInstanceRequirements",
                "eks:DescribeNodegroup"
            ],
            "Resource": ["*"]
        }
    ]
}
EOF

aws iam create-policy 
    --policy-name AmazonEKSClusterAutoscalerPolicy 
    --policy-document file://cluster-autoscaler-policy.json

# IRSA (IAM Roles for Service Accounts) ile service account oluştur
eksctl create iamserviceaccount 
  --cluster=production-cluster 
  --namespace=kube-system 
  --name=cluster-autoscaler 
  --role-name=AmazonEKSClusterAutoscalerRole 
  --attach-policy-arn=arn:aws:iam::ACCOUNT_ID:policy/AmazonEKSClusterAutoscalerPolicy 
  --approve

# Helm ile Cluster Autoscaler kur
helm repo add autoscaler https://kubernetes.github.io/autoscaler
helm repo update

helm install cluster-autoscaler autoscaler/cluster-autoscaler 
  --namespace kube-system 
  --set autoDiscovery.clusterName=production-cluster 
  --set awsRegion=eu-west-1 
  --set rbac.serviceAccount.create=false 
  --set rbac.serviceAccount.name=cluster-autoscaler 
  --set extraArgs.balance-similar-node-groups=true 
  --set extraArgs.skip-nodes-with-system-pods=false

AWS Load Balancer Controller Kurulumu

EKS’te Ingress ve LoadBalancer tipi Service’lerin düzgün çalışması için AWS Load Balancer Controller şart. Bu controller olmadan Kubernetes’in oluşturduğu load balancer’lar eski klasik ELB tipinde oluyor. Bu controller ile ALB ve NLB kullanabiliyorsun.

# Load Balancer Controller için IAM policy indir
curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.7.1/docs/install/iam_policy.json

aws iam create-policy 
    --policy-name AWSLoadBalancerControllerIAMPolicy 
    --policy-document file://iam_policy.json

# Service account oluştur
eksctl create iamserviceaccount 
  --cluster=production-cluster 
  --namespace=kube-system 
  --name=aws-load-balancer-controller 
  --role-name=AmazonEKSLoadBalancerControllerRole 
  --attach-policy-arn=arn:aws:iam::ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy 
  --approve

# Helm ile kur
helm repo add eks https://aws.github.io/eks-charts
helm repo update eks

helm install aws-load-balancer-controller eks/aws-load-balancer-controller 
  -n kube-system 
  --set clusterName=production-cluster 
  --set serviceAccount.create=false 
  --set serviceAccount.name=aws-load-balancer-controller 
  --set region=eu-west-1 
  --set vpcId=vpc-XXXXXXXXX

# Kurulumu doğrula
kubectl get deployment -n kube-system aws-load-balancer-controller

IRSA: IAM Roles for Service Accounts

Bu konuyu ayrıca vurgulamak istiyorum çünkü çok önemli ama sıklıkla atlanıyor. Uygulamaların AWS servislerine erişmesi gerektiğinde (S3’e dosya yazmak, SQS’ten mesaj okumak vs.) eski yöntem node üzerinde IAM rolü kullanmaktı. Bu güvenli değil çünkü o node’daki tüm pod’lar aynı yetkiye sahip oluyor.

IRSA ile her pod’un kendi IAM rolü olabiliyor. Önce OIDC provider’ı aktif etmen gerekiyor:

# OIDC provider oluştur
eksctl utils associate-iam-oidc-provider 
    --region eu-west-1 
    --cluster production-cluster 
    --approve

# OIDC provider'ı doğrula
aws eks describe-cluster --name production-cluster --query "cluster.identity.oidc.issuer" --output text

# Örnek: Bir uygulama için S3 erişimli service account oluştur
eksctl create iamserviceaccount 
  --name s3-reader-sa 
  --namespace production 
  --cluster production-cluster 
  --attach-policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess 
  --approve 
  --override-existing-serviceaccounts

# Service account'u doğrula (annotation olmalı)
kubectl describe serviceaccount s3-reader-sa -n production

Monitoring: CloudWatch Container Insights

Cluster çalışıyor ama içinde ne dönüyor? CloudWatch Container Insights ile hem metrik hem log toplama yapabilirsin.

# CloudWatch agent için namespace oluştur
kubectl apply -f https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/cloudwatch-namespace.yaml

# FluentBit için configmap oluştur
ClusterName=production-cluster
RegionName=eu-west-1
FluentBitHttpPort='2020'
FluentBitReadFromHead='Off'

kubectl create configmap fluent-bit-cluster-info 
  --from-literal=cluster.name=$ClusterName 
  --from-literal=http.port=$FluentBitHttpPort 
  --from-literal=http.server='On' 
  --from-literal=read.head=$FluentBitReadFromHead 
  --from-literal=read.tail='On' 
  --from-literal=logs.region=$RegionName 
  -n amazon-cloudwatch

# FluentBit ve CloudWatch agent'ı kur
kubectl apply -f https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/fluent-bit/fluent-bit.yaml

# Kurulumu doğrula
kubectl get pods -n amazon-cloudwatch

Gerçek Dünya Senaryosu: Multi-Team Cluster Yönetimi

Diyelim ki şirkette 3 farklı ekip var ve hepsi aynı cluster’ı kullanıyor: backend, frontend ve data ekipleri. Her birinin kendi namespace’i olmalı ve birbirlerinin kaynaklarına erişememeliler.

# Her ekip için namespace oluştur
kubectl create namespace backend
kubectl create namespace frontend
kubectl create namespace data-team

# Her namespace için resource quota uygula
kubectl apply -f - << EOF
apiVersion: v1
kind: ResourceQuota
metadata:
  name: backend-quota
  namespace: backend
spec:
  hard:
    requests.cpu: "10"
    requests.memory: 20Gi
    limits.cpu: "20"
    limits.memory: 40Gi
    count/deployments.apps: "20"
    count/services: "20"
    persistentvolumeclaims: "10"
EOF

# Network policy ile namespace izolasyonu
kubectl apply -f - << EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-cross-namespace
  namespace: backend
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: backend
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: backend
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
    - ports:
        - protocol: UDP
          port: 53
EOF

# Ekip üyeleri için RBAC yapılandır
kubectl apply -f - << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: backend-developer
  namespace: backend
rules:
  - apiGroups: ["", "apps", "batch"]
    resources: ["pods", "deployments", "services", "configmaps", "jobs"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["get", "list"]
EOF

Cluster Upgrade Stratejisi

EKS versiyon güncellemeleri production’da hassas bir konu. AWS her Kubernetes versiyonunu belirli bir süre destekliyor, sonra End of Life oluyor. Upgrade’i doğru yapmazsam uygulama kesintisi kaçınılmaz.

Önerdiğim strateji şu:

  • Önce staging cluster’ında dene
  • Control plane’i önce upgrade et
  • Ardından node group’ları sırayla upgrade et
  • Her adımda uygulamaların çalıştığını doğrula
# Mevcut cluster versiyonunu kontrol et
aws eks describe-cluster --name production-cluster --query "cluster.version" --output text

# Uygun upgrade versiyonlarını gör
aws eks describe-addon-versions --kubernetes-version 1.29 --query "addons[].addonVersions[0].addonVersion"

# Control plane upgrade (bir versiyon atlama)
eksctl upgrade cluster 
  --name production-cluster 
  --version 1.29 
  --approve

# Addon'ları upgrade et
eksctl utils update-kube-proxy 
  --cluster production-cluster 
  --approve

eksctl utils update-aws-node 
  --cluster production-cluster 
  --approve

eksctl utils update-coredns 
  --cluster production-cluster 
  --approve

# Node group upgrade (rolling update ile)
eksctl upgrade nodegroup 
  --name general-workers 
  --cluster production-cluster 
  --kubernetes-version 1.29

Maliyet Optimizasyonu İpuçları

EKS’in kendisinin saatlik ücreti var (control plane için yaklaşık 0.10 USD/saat). Üstüne EC2 maliyetleri geliyor. Bunları kontrol altında tutmak için:

  • Spot instance kullanımı: Production’da stateless workload’lar için spot instance’lar ciddi tasarruf sağlar, %60-70’e kadar inebilir
  • Karpenter: Cluster Autoscaler’ın daha akıllı alternatifi, spot/on-demand karışımını otomatik optimize eder
  • Node bin packing: Pod’ların node’lara verimli yerleşmesi için resource request’lerini doğru ayarla
  • Fargate: Test ortamları için düşük trafikli namespace’leri Fargate’e al, boşta bekleyen node maliyeti ödersin
  • Scheduled scaling: Trafik düşük olan gece saatlerinde node sayısını azalt
# Cluster'ın maliyet etiketlemesini kontrol et
kubectl get nodes --show-labels | grep nodegroup

# Resource kullanımını gör
kubectl top nodes
kubectl top pods --all-namespaces --sort-by=memory

# Kullanılmayan kaynakları bul
kubectl get pods --all-namespaces | grep -E "Evicted|Error|OOMKilled"

Yaygın Hatalar ve Çözümleri

Yıllar içinde karşılaştığım en sık sorunlar ve çözümleri:

Nodes NotReady durumu: Genellikle security group sorunu. Worker node’ların control plane ile 443 ve 10250 portlarında iletişim kurabildiğinden emin ol.

Pods Pending kalıyor: Ya resource quota dolmuştur ya da uygun node yok. kubectl describe pod POD_ADI ile detaya bak.

ImagePullBackOff hatası: ECR’dan image çekemiyorsa node’un IAM rolünde AmazonEC2ContainerRegistryReadOnly politikasını kontrol et.

ALB oluşturulmuyor: Load Balancer Controller log’larına bak. Subnet tag’leri eksik olabilir veya IAM izinleri yetersiz olabilir.

Kubeconfig bozuluyor: Birden fazla cluster kullanıyorsan context yönetimi karışabilir. kubectl config get-contexts ve kubectl config use-context komutlarıyla düzelt.

# Debug için genel komutlar
kubectl get events --all-namespaces --sort-by='.lastTimestamp'
kubectl describe node NODE_ADI
kubectl logs -n kube-system deployment/aws-load-balancer-controller
eksctl utils describe-stacks --cluster production-cluster --region eu-west-1

Sonuç

EKS, Kubernetes yolculuğunun en zevkli kısımlarından biri çünkü altyapı yönetimini AWS’e bırakıp asıl işine, yani uygulamaları çalıştırmaya odaklanabiliyorsun. Ama bu yazıda gördüğün gibi “yönetilen” demek “düşünmeden kur” demek değil. VPC tasarımı, IAM yapılandırması, autoscaling, monitoring ve upgrade stratejisi gibi konuları iyi planlamadan kurduğun cluster production’da başını ağrıtacak.

Benim önerim şu şekilde ilerlemek: Önce eksctl ile basit bir test cluster’ı kur ve Kubernetes temellerini öğren. Ardından YAML config dosyasıyla production’a yakın bir yapı oluştur. Cluster Autoscaler ve Load Balancer Controller olmadan production’a gitme. IRSA’yı mutlaka kullan, node IAM rolü üzerinden AWS servislerine erişmek hem güvenli değil hem de sonradan düzeltmesi zahmetli.

En önemlisi, her şeyi kod olarak yaz ve bir git repository’sinde sakla. Bugün kurduğun cluster’ı 6 ay sonra sıfırdan oluşturman gerekebilir. O zaman YAML config dosyan seni kurtarır.

Bir yanıt yazın

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