/엔지니어/클라우드/Amazon EKS 실전 — 클러스터 구성, 배포
클라우드고급UbuntumacOSEKSKubernetesAWS

Amazon EKS 실전 — 클러스터 구성, 배포 전략, 운영 패턴

eksctl로 EKS 클러스터를 구성하고, ALB Ingress·HPA·Karpenter를 적용해 프로덕션 수준의 Kubernetes 워크로드를 운영하는 심화 가이드.

EKS 프로덕션 아키텍처 개요

EKS(Elastic Kubernetes Service)는 AWS 관리형 컨트롤 플레인 위에서 Kubernetes를 운영합니다. 프로덕션에서는 Multi-AZ 노드 그룹 + Karpenter 오토스케일링 + ALB Ingress 조합이 표준입니다.


사전 준비 — 도구 설치

Bash
# eksctl
curl -sL "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv /tmp/eksctl /usr/local/bin

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

# helm
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# 버전 확인
eksctl version && kubectl version --client && helm version

클러스터 생성 — eksctl 선언형 설정

YAML
# cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: prod-cluster
  region: ap-northeast-2
  version: "1.29"

iam:
  withOIDC: true  # IRSA(IAM Roles for Service Accounts) 활성화

managedNodeGroups:
  - name: system
    instanceType: m6i.large
    minSize: 2
    maxSize: 4
    desiredCapacity: 2
    availabilityZones: [ap-northeast-2a, ap-northeast-2b, ap-northeast-2c]
    labels:
      role: system
    taints:
      - key: CriticalAddonsOnly
        value: "true"
        effect: NoSchedule
    iam:
      attachPolicyARNs:
        - arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
        - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
        - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy

addons:
  - name: vpc-cni
    version: latest
  - name: coredns
    version: latest
  - name: kube-proxy
    version: latest
  - name: aws-ebs-csi-driver
    version: latest
    wellKnownPolicies:
      ebsCSIController: true
Bash
eksctl create cluster -f cluster.yaml
# kubeconfig 자동 업데이트됨
kubectl get nodes

Karpenter — 지능형 노드 오토스케일링

Cluster Autoscaler 대신 Karpenter를 사용하면 미사용 노드를 빠르게 정리하고 비용을 절감합니다.

Karpenter 설치

Bash
export CLUSTER_NAME=prod-cluster
export AWS_REGION=ap-northeast-2
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

# IRSA 생성
eksctl create iamserviceaccount \
  --name karpenter \
  --namespace karpenter \
  --cluster $CLUSTER_NAME \
  --attach-policy-arn arn:aws:iam::$AWS_ACCOUNT_ID:policy/KarpenterControllerPolicy \
  --approve

# Helm으로 설치
helm upgrade --install karpenter oci://public.ecr.aws/karpenter/karpenter \
  --version v0.37.0 \
  --namespace karpenter --create-namespace \
  --set settings.clusterName=$CLUSTER_NAME \
  --set settings.interruptionQueue=$CLUSTER_NAME \
  --wait

NodePool · NodeClass 정의

YAML
# karpenter-nodepool.yaml
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: default
spec:
  template:
    spec:
      nodeClassRef:
        name: default
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["on-demand", "spot"]
        - key: node.kubernetes.io/instance-type
          operator: In
          values: ["m6i.large", "m6i.xlarge", "m6a.large", "m6a.xlarge"]
        - key: topology.kubernetes.io/zone
          operator: In
          values: ["ap-northeast-2a", "ap-northeast-2b", "ap-northeast-2c"]
  limits:
    cpu: 200
    memory: 400Gi
  disruption:
    consolidationPolicy: WhenUnderutilized
    consolidateAfter: 30s
---
apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: default
spec:
  amiFamily: AL2
  role: KarpenterNodeRole-prod-cluster
  subnetSelectorTerms:
    - tags:
        karpenter.sh/discovery: prod-cluster
  securityGroupSelectorTerms:
    - tags:
        karpenter.sh/discovery: prod-cluster
  blockDeviceMappings:
    - deviceName: /dev/xvda
      ebs:
        volumeSize: 50Gi
        volumeType: gp3
        encrypted: true
Bash
kubectl apply -f karpenter-nodepool.yaml

ALB Ingress Controller + HTTPS 설정

Bash
# AWS Load Balancer Controller 설치
helm repo add eks https://aws.github.io/eks-charts && helm repo update

helm upgrade --install aws-load-balancer-controller eks/aws-load-balancer-controller \
  -n kube-system \
  --set clusterName=$CLUSTER_NAME \
  --set serviceAccount.create=false \
  --set serviceAccount.name=aws-load-balancer-controller
YAML
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-2:ACCOUNT:certificate/CERT-ID
    alb.ingress.kubernetes.io/ssl-redirect: "443"
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
    alb.ingress.kubernetes.io/healthcheck-path: /healthz
spec:
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 80

HPA — CPU/메모리 기반 Pod 오토스케일링

YAML
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api
  minReplicas: 2
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 70
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300  # 5분간 관망 후 스케일 다운
      policies:
        - type: Pods
          value: 2
          periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 0
      policies:
        - type: Percent
          value: 100
          periodSeconds: 30

운영 — 핵심 명령어 모음

Bash
# 클러스터 전체 리소스 사용량
kubectl top nodes
kubectl top pods -A

# Karpenter 노드 현황
kubectl get nodeclaims
kubectl get nodepools

# HPA 상태 모니터링
kubectl get hpa -w

# 롤링 업데이트 (무중단)
kubectl set image deployment/api app=my-image:v2
kubectl rollout status deployment/api

# 롤백
kubectl rollout undo deployment/api
kubectl rollout history deployment/api --revision=3

# 강제 종료 없이 파드 재스케줄
kubectl drain node-id --ignore-daemonsets --delete-emptydir-data

# 비용 최적화: Spot 중단 시뮬레이션
kubectl taint nodes NODE_NAME karpenter.sh/disruption:NoSchedule-

보안 강화 — IRSA와 NetworkPolicy

Bash
# IRSA: Pod에 최소 권한 IAM 역할 부여
eksctl create iamserviceaccount \
  --name s3-reader \
  --namespace production \
  --cluster $CLUSTER_NAME \
  --attach-policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess \
  --approve
YAML
# networkpolicy.yaml — 기본 차단 후 필요한 것만 허용
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes: [Ingress, Egress]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-api-ingress
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-nginx
      ports:
        - port: 8080
#EKS#Kubernetes#AWS#Karpenter#HPA#ALB#DevOps
편집 안내 · Editorial Note

이 가이드는 AI 도구를 활용해 초안을 구성하고 사람이 명령어·문맥을 검토해 발행했습니다. 운영체제와 도구 버전에 따라 결과가 달라질 수 있으므로 적용 전 공식 문서를 함께 확인하세요. 오류를 발견하시면 이메일로 제보해 주세요.

질문 & 답변 (Q&A)

이 가이드에 대해 궁금한 점을 질문해보세요. 확인 후 답변드립니다.