EKS Pod Resource Optimization Guide
📅 Written: 2026-02-12 | Last Modified: 2026-02-14 | ⏱️ Reading Time: ~35 min
📅 Published: 2026-02-12 | ⏱️ Reading time: ~20 minutes
📌 Reference Environment: EKS 1.30+, Kubernetes 1.30+, Metrics Server v0.7+
This document is currently being translated from Korean to English. The Korean source contains 5,582 lines of detailed technical content. Until the full professional translation is complete, some sections may remain in Korean.
개요
Kubernetes 환경에서 Pod 리소스 설정은 클러스터 효율성과 비용에 직접적인 영향을 미칩니다. 컨테이너의 50%가 요청한 CPU의 1/3만 사용하며, 이는 평균 40-60%의 리소스 낭비로 이어집니다. 이 가이드는 Pod 레벨 리소스 최적화를 통해 클러스터 효율성을 극대화하고 비용을 30-50% 절감하는 실전 전략을 제공합니다.
- karpenter-autoscaling.md: 노드 레벨 오토스케일링 (이 문서는 Pod 레벨)
- cost-management.md: 전체 비용 전략 (이 문서는 리소스 설정에 집중)
- eks-resiliency-guide.md: 리소스 설정을 체크리스트 항목으로만 다룸
핵심 내용
- Requests vs Limits 심층 이해: CPU throttling과 OOM Kill 메커니즘
- QoS 클래스 전략: Guaranteed, Burstable, BestEffort의 실전 활용
- VPA 완벽 가이드: 자동 리소스 조정과 HPA 공존 패턴
- Right-Sizing 방법론: P95 기반 리소스 산정 및 Goldilocks 활용
- 비용 영향 분석: 리소스 최적화의 실제 절감 효과
학습 목표
이 가이드를 완료하면 다음을 수행할 수 있습니다:
- CPU와 Memory requests/limits의 정확한 동작 원리 이해
- 워크로드 특성에 맞는 QoS 클래스 선택
- VPA와 HPA를 안전하게 공존시키는 구성
- 실제 사용량 기반 Right-Sizing 수행
- 리소스 효율성 30% 이상 개선
사전 요구사항
필요한 도구
| 도구 | 버전 | 용도 |
|---|---|---|
| kubectl | 1.28+ | Kubernetes 클러스터 관리 |
| helm | 3.12+ | VPA, Goldilocks 설치 |
| metrics-server | 0.7+ | 리소스 메트릭 수집 |
| kubectl-top | 내장 | 리소스 사용량 확인 |
필요한 권한
# RBAC 권한 확인
kubectl auth can-i get pods --all-namespaces
kubectl auth can-i get resourcequotas
kubectl auth can-i create verticalpodautoscaler
선행 지식
- Kubernetes Pod, Deployment 기본 개념
- YAML 매니페스트 작성 경험
- Linux cgroups 기본 이해 (권장)
- Prometheus/Grafana 기본 사용법 (권장)
Resource Requests & Limits 심층 이해
2.1 Requests vs Limits의 정확한 의미
Resource requests와 limits는 Kubernetes 리소스 관리의 핵심 개념입니다.
Requests (요청량)
- 정의: 스케줄러가 Pod 배치 시 보장하는 최소 리소스
- 역할: 노드 선택 기준, QoS 클래스 결정
- 보장: kubelet이 이 양을 항상 확보
Limits (제한량)
- 정의: kubelet이 강제하는 최대 리소스
- 역할: 리소스 고갈 방지, 노이지 네이버(noisy neighbor) 제한
- 강제: CPU는 throttling, Memory는 OOM Kill
핵심 차이점
| 속성 | CPU | Memory |
|---|---|---|
| Requests 초과 시 | 다른 Pod가 사용 안 하면 사용 가능 | 다른 Pod가 사용 안 하면 사용 가능 |
| Limits 초과 시 | Throttling (프로세스 속도 저하) | OOM Kill (프로세스 강제 종료) |
| 압축 가능 여부 | 압축 가능 (Compressible) | 압축 불가 (Incompressible) |
| 초과 사용 위험 | 성능 저하 | 서비스 중단 |
2.2 CPU 리소스 깊이 이해
CPU Millicore 단위
# CPU 표기법
resources:
requests:
cpu: "500m" # 500 millicore = 0.5 CPU core
cpu: "1" # 1000 millicore = 1 CPU core
cpu: "2.5" # 2500 millicore = 2.5 CPU cores
1 CPU core = 1000 millicore
- AWS vCPU, Azure vCore 모두 동일
- 하이퍼스레딩 환경에서도 논리 코어 기준
CFS Bandwidth Throttling
Linux CFS (Completely Fair Scheduler)는 CPU limits를 강제합니다:
# cgroups v2 기준
/sys/fs/cgroup/cpu.max
# 예시: "100000 100000" = 100ms 주기당 100ms 사용 가능 (100% = 1 CPU)
# 예시: "50000 100000" = 100ms 주기당 50ms 사용 가능 (50% = 0.5 CPU)
Throttling 메커니즘
시간 주기: 100ms
CPU Limit: 500m (0.5 CPU)
→ 100ms 중 50ms만 사용 가능
실제 동작:
[0-50ms] ████████████████████ (실행)
[50-100ms] ...................... (throttled)
[100-150ms] ████████████████████ (실행)
[150-200ms] ...................... (throttled)
Google, Datadog 등 대규모 클러스터 운영 조직은 CPU limits를 설정하지 않습니다:
이유:
- CPU는 압축 가능한 리소스 (다른 Pod가 필요하면 자동 조정)
- Throttling으로 인한 불필요한 성능 저하 방지
- Requests만으로도 스케줄링과 QoS 제어 가능
대신 권장:
- CPU requests는 P95 사용량 기준으로 설정
- HPA로 부하에 따른 수평 확장
- Node-level 리소스 모니터링 강화
예외 (Limits 설정 필요):
- 배치 작업 (CPU 독점 방지)
- 신뢰할 수 없는 워크로드
- 멀티테넌트 환경
CPU 리소스 설정 예시
# 패턴 1: Requests만 설정 (권장)
apiVersion: v1
kind: Pod
metadata:
name: web-server
spec:
containers:
- name: nginx
image: nginx:1.25
resources:
requests:
cpu: "250m" # P95 사용량 기준
memory: "128Mi"
# limits 생략 - CPU 압축 가능 리소스 활용
---
# 패턴 2: 배치 작업 (Limits 설정)
apiVersion: batch/v1
kind: Job
metadata:
name: data-processing
spec:
template:
spec:
containers:
- name: processor
image: data-processor:v1
resources:
requests:
cpu: "1000m"
limits:
cpu: "2000m" # CPU 독점 방지
memory: "4Gi"
restartPolicy: OnFailure
2.3 Memory 리소스 깊이 이해
Memory 단위
# Memory 표기법 (1024 기반 vs 1000 기반)
resources:
requests:
memory: "128Mi" # 128 * 1024^2 bytes = 134,217,728 bytes
memory: "128M" # 128 * 1000^2 bytes = 128,000,000 bytes
memory: "1Gi" # 1 * 1024^3 bytes = 1,073,741,824 bytes
memory: "1G" # 1 * 1000^3 bytes = 1,000,000,000 bytes
권장: Mi, Gi 사용 (1024 기반, Kubernetes 표준)
OOM Kill 메커니즘
Memory limits 초과 시 Linux OOM Killer가 프로세스를 강제 종료합니다:
실제 사용량 > Memory Limit
→ cgroup memory.max 초과
→ Kernel OOM Killer 발동
→ 프로세스 SIGKILL
→ Pod 상태: OOMKilled
→ kubelet이 Pod 재시작 (RestartPolicy 따름)
OOM Score 계산
# 프로세스별 OOM Score 확인
cat /proc/<PID>/oom_score
# OOM Score 계산 요소
# 1. 메모리 사용량 (높을수록 점수 높음)
# 2. oom_score_adj 값 (QoS 클래스별로 다름)
# 3. 루트 프로세스 보호 (-1000 = 절대 Kill 안 함)
Memory는 압축 불가능한 리소스이므로 반드시 limits 설정 필요:
이유:
- Memory 고갈 시 전체 노드 불안정
- Kernel Panic 가능성
- 다른 Pod에 영향 (노드 Eviction)
권장 설정:
requests = limits(Guaranteed QoS)- 또는
limits = requests * 1.5(Burstable QoS) - JVM 애플리케이션: Heap 크기는 limits의 75%로 설정
Memory 리소스 설정 예시
# 패턴 1: Guaranteed QoS (안정성 최우선)
apiVersion: apps/v1
kind: Deployment
metadata:
name: database
spec:
replicas: 3
template:
spec:
containers:
- name: postgres
image: postgres:16
resources:
requests:
cpu: "2000m"
memory: "4Gi"
limits:
cpu: "2000m" # requests와 동일
memory: "4Gi" # requests와 동일 (Guaranteed)
---
# 패턴 2: JVM 애플리케이션
apiVersion: apps/v1
kind: Deployment
metadata:
name: java-app
spec:
template:
spec:
containers:
- name: app
image: java-app:v1
env:
- name: JAVA_OPTS
value: "-Xmx3072m -Xms3072m" # limits의 75% (4Gi * 0.75 = 3Gi)
resources:
requests:
memory: "4Gi"
limits:
memory: "4Gi"
---
# 패턴 3: Node.js 애플리케이션
apiVersion: apps/v1
kind: Deployment
metadata:
name: nodejs-api
spec:
template:
spec:
containers:
- name: api
image: nodejs-api:v2
env:
- name: NODE_OPTIONS
value: "--max-old-space-size=896" # limits의 70% (1280Mi * 0.7 = 896Mi)
resources:
requests:
memory: "1280Mi"
limits:
memory: "1280Mi"
2.4 Ephemeral Storage
컨테이너 로컬 스토리지도 리소스로 관리할 수 있습니다:
apiVersion: v1
kind: Pod
metadata:
name: ephemeral-demo
spec:
containers:
- name: app
image: busybox
resources:
requests:
ephemeral-storage: "2Gi" # 최소 보장
limits:
ephemeral-storage: "4Gi" # 최대 사용량
volumeMounts:
- name: cache
mountPath: /cache
volumes:
- name: cache
emptyDir:
sizeLimit: "4Gi"
Ephemeral Storage 포함 항목:
- 컨테이너 레이어 쓰기
- 로그 파일 (
/var/log) - emptyDir 볼륨
- 임시 파일
노드 Eviction Threshold:
# kubelet 설정
evictionHard:
nodefs.available: "10%" # 노드 전체 디스크 10% 미만 시 eviction
nodefs.inodesFree: "5%" # inode 5% 미만 시 eviction
imagefs.available: "10%" # 이미지 파일시스템 10% 미만 시 eviction
2.5 EKS Auto Mode 리소스 최적화
EKS Auto Mode는 Kubernetes 클러스터 운영의 복잡성을 극적 으로 줄이는 완전 관리형 솔루션입니다. 컴퓨팅, 스토리지, 네트워킹의 프로비저닝부터 지속적 유지보수까지 자동화하여 운영팀이 인프라 관리 대신 애플리케이션 개발에 집중할 수 있게 합니다.
2.5.1 Auto Mode 개요
핵심 기능:
- 단일 클릭 활성화: 클러스터 생성 시
--compute-config autoMode플래그만으로 활성화 - 자동 인프라 프로비저닝: Pod 스케줄링 요구사항에 따라 최적 인스턴스 타입 자동 선택
- 지속적 유지보수: OS 패치, 보안 업데이트, 코어 애드온 관리 자동화
- 비용 최적화: Graviton 프로세서와 Spot 인스턴스 자동 활용
- 통합 보안: AWS 보안 서비스 기본 통합
# Auto Mode 클러스터 생성
aws eks create-cluster \
--name my-auto-cluster \
--compute-config autoMode=ENABLED \
--kubernetes-network-config serviceIpv4Cidr=10.100.0.0/16 \
--access-config bootstrapClusterCreatorAdminPermissions=true
Auto Mode는 기존 수동 관리 방식을 완전히 대체하는 것이 아니라, 운영 오버헤드를 최소화하려는 팀을 위한 보완적 선택지입니다. 세밀한 제어가 필요한 경우 여전히 수동 관리 방식을 선택할 수 있습니다.
2.5.2 Auto Mode vs 수동 관리 비교
| 항목 | 수동 관리 | Auto Mode |
|---|---|---|
| 노드 프로비저닝 | Managed Node Group, Self-managed, Karpenter 직접 구성 | 자동 프로비저닝 (EC2 Managed Instances 기반) |
| 인스턴스 타입 선택 | 수동 선택 및 NodePool 구성 | Pod 요구사항 기반 자동 선택 (Graviton 우선) |
| VPA 설정 | 수동 설치 및 구성 필요 | 필요 없음 (자동 리소스 최적화) |
| HPA 설정 | 수동 설정 및 메트릭 구성 | 자동 구성 가능 (개발자는 선언만) |
| OS 패치 | 수동 또는 자동화 스크립트 | 완전 자동 (무중단) |
| 보안 업데이트 | 수동 적용 | 자동 적용 |
| 코어 애드온 관리 | 수동 업그레이드 (CoreDNS, kube-proxy, VPC CNI) | 자동 업그레이드 |
| 비용 최적화 | Spot, Graviton 수동 구성 | 자동 활용 (최대 90% 절감) |
| Request/Limit 설정 | 개발자 책임 (필수) | 개발자 책임 (여전히 필수) |
| 리소스 효율성 | VPA Off 모드 + 수동 적용 | 자동 Right-Sizing (지속적) |
| 학습 곡선 | 높음 (Kubernetes, AWS 전문 지식 필요) | 낮음 (Kubernetes 기본만 필요) |
| 운영 오버헤드 | 높음 | 최소 |
Auto Mode는 인프라를 자동화하지만, Pod-level requests/limits 설정은 여전히 개발자의 책임입니다. 이는 애플리케이션의 실제 리소스 요구사항을 가장 잘 아는 사람이 개발자이기 때문입니다.
2.5.3 Graviton + Spot 조합 최적화
Auto Mode는 AWS Graviton 프로세서와 Spot 인스턴스를 지능적으로 조합하여 비용 효율성을 극대화합니다.
Graviton 프로세서의 장점:
- 40% 향상된 가격 대비 성능 (x86 대비)
- 범용 워크로드, 웹 서버, 컨테이너화된 마이크로서비스에 최적
- Arm64 아키텍처 지원 (대부분의 컨테이너 이미지 호환)
Spot 인스턴스 절감:
- 최대 90% 비용 절감 (On-Demand 대비)
- Auto Mode가 자동으로 Spot 가용성 모니터링 및 Fallback 처리
- 중단 2분 전 알림으로 Graceful Termination 보장
NodePool YAML 예시 (수동 관리 클러스터 - Karpenter 기반):
# Auto Mode는 이러한 NodePool을 자동 생성하지만,
# 참고를 위해 수동 설정 시 Graviton + Spot 패턴을 보여줍니다
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
name: graviton-spot-pool
spec:
template:
spec:
requirements:
# Graviton 인스턴스 우선
- key: kubernetes.io/arch
operator: In
values: ["arm64"]
# Spot 우선, Fallback으로 On-Demand
- key: karpenter.sh/capacity-type
operator: In
values: ["spot", "on-demand"]
# 범용 워크로드용 인스턴스 패밀리
- key: node.kubernetes.io/instance-type
operator: In
values: ["m7g.medium", "m7g.large", "m7g.xlarge", "m7g.2xlarge"]
nodeClassRef:
name: default
# Spot 중단 처리
disruption:
consolidationPolicy: WhenUnderutilized
expireAfter: 720h
# 리소스 제한
limits:
cpu: "1000"
memory: "1000Gi"
---
# Fallback: x86 On-Demand (Spot 불가 시)
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
name: x86-ondemand-fallback
spec:
weight: 10 # 낮은 우선순위
template:
spec:
requirements:
- key: kubernetes.io/arch
operator: In
values: ["amd64"]
- key: karpenter.sh/capacity-type
operator: In
values: ["on-demand"]
- key: node.kubernetes.io/instance-type
operator: In
values: ["m6i.large", "m6i.xlarge", "m6i.2xlarge"]
nodeClassRef:
name: default
Auto Mode에서의 자동 처리:
Auto Mode는 위와 같은 NodePool 구성을 수동으로 작성할 필요 없이, Pod의 리소스 요구사항과 워크로드 특성을 분석하여 자동으로 최적 인스턴스를 선택합니다.
# Auto Mode 환경에서 개발자가 작성하는 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
namespace: production
spec:
replicas: 10
template:
spec:
containers:
- name: nginx
image: nginx:1.25-arm64 # Graviton용 이미지
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
memory: "1Gi"
# Auto Mode가 자동으로:
# 1. Graviton Spot 인스턴스 선택 시도
# 2. Spot 불가 시 Graviton On-Demand로 Fallback
# 3. 인스턴스 타입 자동 선택 (m7g.large 등)
# 4. 노드 프로비저닝 및 Pod 배치
Graviton 인스턴스를 활용하려면 arm64 아키텍처 컨테이너 이미지가 필요합니다. 대부분의 공식 이미지는 multi-arch 를 지원하므로, 동일한 이미지 태그로 Graviton과 x86 모두에서 실행 가능합니다.
# multi-arch 이미지 확인
docker manifest inspect nginx:1.25 | jq '.manifests[].platform'
# 출력 예시:
# { "architecture": "amd64", "os": "linux" }
# { "architecture": "arm64", "os": "linux" }
실제 비용 절감 예시:
| 시나리오 | 인스턴스 타입 | 시간당 비용 | 월간 비용 (730시간) | 절감률 |
|---|---|---|---|---|
| x86 On-Demand | m6i.2xlarge | $0.384 | $280.32 | - |
| Graviton On-Demand | m7g.2xlarge | $0.3264 | $238.27 | 15% |
| Graviton Spot | m7g.2xlarge | $0.0979 | $71.47 | 75% |
10개 노드 기준:
- x86 On-Demand: $2,803/월
- Graviton On-Demand: $2,383/월 (15% 절감)
- Graviton Spot: $715/월 (75% 절감) ⭐
Graviton4 특화 최적화:
Graviton4 (R8g, M8g, C8g) 인스턴스는 Graviton3 대비 30% 향상된 컴퓨팅 성능과 75% 향상된 메모리 대역폭을 제공합니다.
| 세대 | 인스턴스 패밀리 | 성능 개선 | 주요 워크로드 |
|---|---|---|---|
| Graviton3 | m7g, c7g, r7g | 기준 | 범용 웹/API, 컨테이너 |
| Graviton4 | m8g, c8g, r8g | +30% 컴퓨팅, +75% 메모리 | 고성능 데이터베이스, ML 추론, 실시간 분석 |
ARM64 Multi-Arch 빌드 파이프라인:
Graviton 인스턴스를 최대한 활용하려면 ARM64와 AMD64를 모두 지원하는 multi-arch 컨테이너 이미지가 필요합니다.
# Multi-arch Dockerfile 예시
FROM golang:1.22-alpine AS builder
ARG TARGETOS TARGETARCH
WORKDIR /app
COPY . .
# 타겟 아키텍처에 맞게 빌드
RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o app .
# 런타임 이미지
FROM alpine:3.19
COPY /app/app /usr/local/bin/app
ENTRYPOINT ["/usr/local/bin/app"]
GitHub Actions CI/CD에서 multi-arch 빌드:
# .github/workflows/build.yml
name: Build Multi-Arch Image
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to ECR
uses: aws-actions/amazon-ecr-login@v2
- name: Build and push multi-arch
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64 # ARM64 포함
push: true
tags: |
${{ secrets.ECR_REGISTRY }}/myapp:${{ github.sha }}
${{ secrets.ECR_REGISTRY }}/myapp:latest
cache-from: type=gha
cache-to: type=gha,mode=max
Graviton3 → Graviton4 마이그레이션 벤치마크 포인트:
# Graviton4 우선 NodePool 예시 (Karpenter)
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
name: graviton4-spot-pool
spec:
template:
spec:
requirements:
# Graviton4 우선, Graviton3 Fallback
- key: node.kubernetes.io/instance-type
operator: In
values:
# Graviton4 (최우선)
- "m8g.medium"
- "m8g.large"
- "m8g.xlarge"
- "m8g.2xlarge"
# Graviton3 (Fallback)
- "m7g.medium"
- "m7g.large"
- "m7g.xlarge"
- "m7g.2xlarge"
- key: kubernetes.io/arch
operator: In
values: ["arm64"]
- key: karpenter.sh/capacity-type
operator: In
values: ["spot", "on-demand"]
nodeClassRef:
name: default
disruption:
consolidationPolicy: WhenUnderutilized
consolidateAfter: 30s
limits:
cpu: "1000"
memory: "2000Gi"
Graviton4 성능 벤치마크 체크포인트:
마이그레이션 시 다음 메트릭을 모니터링하여 성능 개선을 검증합니다:
| 메트릭 | Graviton3 기준 | Graviton4 목표 | 측정 방법 |
|---|---|---|---|
| P99 응답 시간 | 100ms | 70ms (-30%) | Prometheus http_request_duration_seconds |
| 처리량 (RPS) | 1000 req/s | 1300 req/s (+30%) | Load testing (k6, Locust) |
| 메모리 대역폭 | 205 GB/s | 358 GB/s (+75%) | sysbench memory |
| CPU 사용률 | 60% | 45% (-25%) | node_cpu_seconds_total |
# Graviton4 성능 테스트 스크립트
#!/bin/bash
# 1. 메모리 대역폭 테스트
sysbench memory --memory-total-size=100G --memory-oper=write run
# 2. CPU 벤치마크
sysbench cpu --cpu-max-prime=20000 --threads=8 run
# 3. 애플리케이션 부하 테스트 (k6)
k6 run --vus 100 --duration 5m loadtest.js
# 4. Prometheus 메트릭 수집
curl -s http://localhost:9090/api/v1/query?query=rate(http_request_duration_seconds_sum[5m]) | jq .
- 컨테이너 이미지: ARM64 지원 확인 (
docker manifest inspect) - 의존성 라이브러리: ARM64 호환성 검증
- CI/CD 파이프라인: Multi-arch 빌드 활성화
- NodePool 우선순위: Graviton4 → Graviton3 → x86 순서 설정
- 성능 벤치마크: P99 레이턴시, 처리량, CPU 사용률 측정
- 비용 분석: Graviton3 대비 가격/성능 비율 계산
2.5.4 Auto Mode 환경의 리소스 설정 권장사항
Auto Mode는 많은 부분을 자동화하지만, 개발자는 여전히 애플리케이션의 리소스 요구사항을 정확히 설정해야 합니다.
Auto Mode가 자동 처리하는 항목:
| 항목 | 수동 관리 | Auto Mode |
|---|---|---|
| 노드 프로비저닝 | Karpenter, Managed Node Group 설정 | 자동 |
| 인스턴스 타입 선택 | NodePool에서 수동 지정 | Pod requests 기반 자동 선택 |
| Spot/On-Demand 전환 | 수동 또는 Karpenter 설정 | 자동 Fallback |
| 노드 스케일링 | HPA + Cluster Autoscaler/Karpenter | 자동 |
| OS 패치 | 수동 또는 자동화 스크립트 | 자동 (무중단) |
개발자가 여전히 설정해야 하는 항목:
| 항목 | 이유 | 권장 방법 |
|---|---|---|
| CPU Requests | 스케줄링 결정 기준 | P95 사용량 + 20% |
| Memory Requests | 스케줄링 및 OOM 방지 | P95 사용량 + 20% |
| Memory Limits | OOM Kill 방지 (필수) | Requests × 1.5~2 |
| CPU Limits | 일반 워크로드는 미설정 권장 | 배치 작업만 설정 |
| HPA 메트릭 | 수평 확장 기준 | CPU 70%, Custom Metrics |
Auto Mode 환경에서의 VPA 역할 변화:
Auto Mode에서 VPA는:
- 별도 설치 불필요
- 내장 Right-Sizing 엔진이 지속적으로 워크로드 분석
- 개발자에게 권장사항 제공 (자동 적용 대신)
- 개발자가 검토 후 Deployment 매니페스트에 반영
권장 워크플로우:
# 1. Auto Mode 클러스터에 배포
kubectl apply -f deployment.yaml
# 2. 7-14일 후 Auto Mode 대시보드에서 권장사항 확인
# (AWS Console → EKS → Clusters → <cluster-name> → Insights)
# 3. 권장사항을 Deployment에 반영
kubectl set resources deployment web-app \
--requests=cpu=300m,memory=512Mi \
--limits=memory=1Gi
# 4. GitOps로 매니페스트 업데이트
git add deployment.yaml
git commit -m "chore: apply Auto Mode resource recommendations"
git push
Auto Mode는 다음과 같은 경우에 특히 유용합니다:
- 신규 클러스터: 기존 인프라 없이 빠르게 시작
- 운영 리소스 부족: 소규모 팀에서 Kubernetes 전문가 없이 운영
- 비용 최적화 우선: Graviton + Spot 자동 활용으로 즉시 절감
- 표준화된 워크로드: 일반적인 웹/API 서버, 마이크로서비스
수동 관리 권장 시나리오:
- 세밀한 제어 필요: 특정 인스턴스 타입, AZ 배치, 네트워크 구성
- 기존 Karpenter 투자: 고도화된 NodePool 정책 보유
- 규제 요구사항: 특정 하드웨어, 보안 그룹 강제
Auto Mode + 수동 Right-Sizing 비교:
| 항목 | 수동 Right-Sizing (VPA Off) | Auto Mode |
|---|---|---|
| 초기 설정 복잡도 | 높음 (VPA 설치, Prometheus 구성) | 낮음 (클러스터 생성 시 플래그만) |
| 권장사항 생성 시간 | 7-14일 | 7-14일 (동일) |
| 권장사항 정확도 | 높음 (Prometheus 기반) | 높음 (내장 분석 엔진) |
| 적용 방식 | 수동 (개발자가 매니페스트 수 정) | 수동 (개발자가 매니페스트 수정) |
| 지속적 모니터링 | 수동 (주기적 VPA 확인) | 자동 (대시보드 알림) |
| 인프라 최적화 | 수동 (Karpenter 설정) | 자동 (Graviton + Spot) |
| 총 운영 오버헤드 | 높음 | 낮음 |
결론:
Auto Mode는 리소스 최적화의 복잡성을 제거하지만, 리소스 설정의 책임은 제거하지 않습니다. 개발자는 여전히 애플리케이션의 requests/limits를 설정해야 하며, Auto Mode는 이를 기반으로 최적의 인프라를 자동으로 프로비저닝합니다.
이는 **"개발자는 애플리케이션 요구사항 정의, AWS는 인프라 관리"**라는 명확한 책임 분리를 통해, 양측 모두가 자신의 전문 분야에 집중할 수 있게 합니다.
QoS (Quality of Service) 클래스
3.1 세 가지 QoS 클래스
Kubernetes는 리소스 설정에 따라 Pod를 3가지 QoS 클래스로 분류합니다:
Guaranteed (최고 우선순위)
조건:
- 모든 컨테이너에 CPU와 Memory requests와 limits 설정
- requests == limits (동일 값)
apiVersion: v1
kind: Pod
metadata:
name: guaranteed-pod
labels:
qos: guaranteed
spec:
containers:
- name: app
image: nginx:1.25
resources:
requests:
cpu: "500m"
memory: "256Mi"
limits:
cpu: "500m" # requests와 동일
memory: "256Mi" # requests와 동일
- name: sidecar
image: fluentd:v1
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "100m"
memory: "128Mi"
특징:
- oom_score_adj: -997 (가장 낮음, OOM Kill 우선순위 최하)
- 노드 압박 시에도 마지막에 Eviction
- CPU 스케줄링 우선순위 높음
Burstable (중간 우선순위)
조건:
- 최소 1개 컨테이너에 CPU 또는 Memory requests 설정
- Guaranteed 조건을 만족하지 않음
apiVersion: v1
kind: Pod
metadata:
name: burstable-pod
labels:
qos: burstable
spec:
containers:
- name: app
image: web-app:v1
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m" # requests보다 큼 (Burstable)
memory: "1Gi" # requests보다 큼
- name: cache
image: redis:7
resources:
requests:
memory: "256Mi" # CPU requests 없음 (Burstable)
limits:
memory: "512Mi"
특징:
- oom_score_adj: min(max(2, 1000 - (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)
- 사용량에 따라 동적으로 조정
- 여유 있을 때 burst 가능
BestEffort (최저 우선순위)
조건:
- 모든 컨테이너에 requests와 limits 미설정
apiVersion: v1
kind: Pod
metadata:
name: besteffort-pod
labels:
qos: besteffort
spec:
containers:
- name: app
image: test-app:latest
# resources 섹션 없음 또는 비어있음
특징:
- oom_score_adj: 1000 (가장 높음, OOM Kill 최우선)
- 노드 압박 시 가장 먼저 Eviction
- 개발/테스트 환경에서만 사용 권장