infra
Platform

모듈 맵

[Kubernetes] VPA(Vertical Pod Autoscaler) 기반 실시간 리소스 최적화

0 / 29 완료

펼치기
0 / 29 완료0%

Kubernetes · 20 / 29

[Kubernetes] VPA(Vertical Pod Autoscaler) 기반 실시간 리소스 최적화

VPA가 파드의 CPU/메모리 requests와 limits를 자동으로 최적화하는 방법과 HPA와의 선택 기준을 이해합니다

🚨INCIDENT ALERT
HIGH

API 서버의 메모리 사용량이 매주 늘어나는데 requests 값은 배포 첫날 그대로입니다. 너무 낮은 requests는 노드 압박을 만들고, 너무 높은 requests는 비용 낭비로 이어집니다. VPA는 실제 사용량을 기반으로 리소스 요청값을 조정하는 방법을 제공합니다.

VPA — 수직 파드 오토스케일러

팀에서 새로운 마이크로서비스를 배포할 때마다 이런 대화가 반복됩니다. "CPU requests를 얼마로 설정해야 하죠?" "일단 250m으로 해보죠." "메모리는요?" "512Mi?" 운이 좋으면 파드가 잘 돌아가지만, 실제 사용량은 requests의 30%에 불과해 자원이 낭비되거나, 반대로 limits에 걸려 파드가 OOM으로 죽기를 반복합니다. VPA(Vertical Pod Autoscaler)는 이 문제를 해결합니다. 파드의 실제 CPU/메모리 사용 패턴을 분석하여 최적의 requests와 limits를 자동으로 조정합니다. HPA가 "파드를 몇 개 띄울지" 결정한다면, VPA는 "각 파드가 얼마나 큰지"를 결정합니다. 이 모듈에서는 VPA의 세 가지 운영 모드와 실무에서 가장 안전하게 사용하는 방법을 다룹니다.

이번 챕터에서 배울 것
  • 1VPA 아키텍처: Recommender, Updater, Admission Controller
  • 2Off / Initial / Auto 모드 비교와 사용 시나리오
  • 3VPA 설정: minAllowed, maxAllowed, updatePolicy
  • 4HPA vs VPA: 선택 기준과 동시 사용 주의사항
  • 5추천값 분석으로 현재 리소스 설정 최적화
  • 6VPA Auto 모드의 파드 재시작 최소화 전략
실습 환경 준비
VPA 설치 여부 확인
kubectl get deployment -n kube-system | grep vpa
VPA CRD 확인
kubectl get crd | grep verticalpodautoscaler
Metrics Server 확인 (VPA 필요)
kubectl top nodes
VPA 설치 (미설치 시)
kubectl apply -f https://github.com/kubernetes/autoscaler/releases/latest/download/vpa-v1-crd-gen.yaml

VPA 아키텍처

VPA는 세 개의 컴포넌트로 동작합니다.

┌─────────────────────────────────────────────────────┐
│                    VPA 동작 흐름                      │
│                                                      │
│  Metrics Server ──► VPA Recommender                  │
│  (실제 사용량 수집)   (분석 + 추천값 계산)              │
│                          │                           │
│                    VPA 오브젝트 (추천값 저장)           │
│                    ├── VPA Updater ─────────────►    │
│                    │   (파드 Evict + 재시작)     파드  │
│                    └── VPA Admission Controller ►    │
│                        (새 파드 생성 시 requests 주입) │
└─────────────────────────────────────────────────────┘
💡개념

Off / Initial / Auto 모드 비교

신규 서비스 배포 후 "requests를 얼마로 설정해야 하죠?"라는 질문이 항상 나옵니다. 과도하게 높으면 노드 자원이 낭비되고, 너무 낮으면 OOM이 발생합니다. VPA는 세 가지 모드로 이 문제에 접근합니다. Off 모드는 실제 사용량을 분석해 추천값만 제시하고 직접 건드리지 않습니다. Initial 모드는 파드 시작 시 한 번만 적용합니다. Auto 모드는 지속적으로 모니터링하며 자동으로 파드를 재시작해 최적값을 유지합니다. 처음 VPA를 도입할 때는 Off 모드로 시작해 추천값을 검토한 후 단계적으로 적용하는 것이 안전합니다.

YAML
# 1. Off 모드 — 추천만, 적용 안 함 (안전한 시작점)
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: api-server-vpa
  namespace: production
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  updatePolicy:
    updateMode: "Off"      # 추천만 하고 파드 변경 안 함
  resourcePolicy:
    containerPolicies:
      - containerName: api
        minAllowed:
          cpu: 100m
          memory: 128Mi
        maxAllowed:
          cpu: 2000m
          memory: 4Gi
        controlledResources: ["cpu", "memory"]

Off / Initial / Auto 모드 비교

Kubernetes
# Off 모드 추천값 확인
kubectl describe vpa api-server-vpa -n production
# Recommendation:
#   Container Recommendations:
#     Container Name:  api
#     Lower Bound:
#       Cpu:     150m      ← 현재보다 낮추는 것이 가능한 하한
#       Memory:  256Mi
#     Target:
#       Cpu:     380m      ← VPA가 권장하는 최적값
#       Memory:  512Mi
#     Upper Bound:
#       Cpu:     800m      ← 피크 트래픽 대비 상한 추천
#       Memory:  1Gi
#     Uncapped Target:
#       Cpu:     380m      ← minAllowed/maxAllowed 제한 없이 계산한 값
#       Memory:  512Mi
YAML
# 2. Initial 모드 — 파드 시작 시에만 적용, 이후 변경 안 함
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: batch-job-vpa
  namespace: production
spec:
  targetRef:
    apiVersion: batch/v1
    kind: Job
    name: etl-job
  updatePolicy:
    updateMode: "Initial"  # 파드 생성 시에만 requests 주입
  resourcePolicy:
    containerPolicies:
      - containerName: etl
        minAllowed:
          cpu: 500m
          memory: 1Gi
        maxAllowed:
          cpu: 8000m
          memory: 32Gi
YAML
# 3. Auto 모드 — 지속적으로 추천값 적용 (파드 재시작 포함)
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: worker-vpa
  namespace: production
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: background-worker
  updatePolicy:
    updateMode: "Auto"
    # 최소 업데이트 간격 설정 (기본값은 없음)
    minReplicas: 2         # 최소 2개 실행 중일 때만 Evict 허용
  resourcePolicy:
    containerPolicies:
      - containerName: worker
        minAllowed:
          cpu: 200m
          memory: 256Mi
        maxAllowed:
          cpu: 4000m
          memory: 8Gi
        # limits를 requests 대비 비율로 자동 설정
        controlledResources: ["cpu", "memory"]
💡개념

HPA vs VPA 선택 기준

트래픽이 몰릴 때 파드를 더 띄울지, 아니면 각 파드에 더 많은 자원을 줄지 판단해야 합니다. 잘못 선택하면 HPA가 파드를 늘리는 동안 VPA가 그 파드를 재시작시키는 충돌이 생길 수도 있습니다. HPA는 스테이트리스 서비스의 인스턴스 수를 조정하고, VPA는 수평 확장이 불가능한 서비스의 파드 크기를 조정합니다. 서비스 특성에 맞는 선택이 불필요한 재시작과 과금을 줄입니다.

HPA 선택 ← 수평 확장 가능한 서비스
┌─────────────────────────────────────┐
│ - 스테이트리스 API 서버              │
│ - 웹 프론트엔드                     │
│ - 메시지 컨슈머 (파티션 수만큼 확장) │
│ - 파드 수 늘릴 때 선형 처리량 증가  │
└─────────────────────────────────────┘

VPA 선택 ← 수직 확장이 필요한 서비스
┌─────────────────────────────────────┐
│ - 단일 레플리카 DB (Postgres, Redis) │
│ - 상태 저장 서비스 (Stateful Set)    │
│ - 배치 Job (더 큰 메모리로 빠르게)   │
│ - 사이드카 컨테이너 (리소스 추정 어려움) │
│ - 초기 requests/limits 설정 최적화  │
└─────────────────────────────────────┘

동시 사용 주의:
HPA는 CPU 사용률 기반으로 파드 수를 조정함
VPA는 requests를 올리면 CPU 사용률이 떨어짐
→ HPA가 파드를 줄이고 VPA가 requests를 올리는 사이클 발생 가능
→ 동시 사용 시: VPA에서 CPU 제어 비활성화하고 메모리만 제어
YAML
# HPA + VPA 동시 사용 시 — CPU는 HPA, 메모리는 VPA
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: api-server-vpa-mem-only
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  updatePolicy:
    updateMode: "Auto"
  resourcePolicy:
    containerPolicies:
      - containerName: api
        # CPU는 VPA가 건드리지 않음 (HPA가 CPU 메트릭으로 파드 수 조정)
        controlledResources: ["memory"]
        minAllowed:
          memory: 256Mi
        maxAllowed:
          memory: 8Gi

실습: 리소스 낭비 파드 최적화

로컬 터미널
# 1. 과도하게 큰 requests를 가진 파드 배포
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: over-provisioned
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: over-provisioned
  template:
    metadata:
      labels:
        app: over-provisioned
    spec:
      containers:
        - name: app
          image: nginx
          resources:
            requests:
              cpu: 2000m    # 실제 사용량은 50m 수준
              memory: 4Gi   # 실제 사용량은 200Mi 수준
            limits:
              cpu: 4000m
              memory: 8Gi
EOF

# 2. 실제 사용량 확인
kubectl top pods -l app=over-provisioned
# NAME                    CPU(cores)  MEMORY(bytes)
# over-provisioned-aaa    52m         185Mi
# over-provisioned-bbb    48m         192Mi
# ← requests의 2.5%만 사용 중
🔍실행 후 확인할 것
  • NAME조회 대상 리소스 이름이 예상한 대상과 일치하는지 확인합니다.
  • STATUS/READYRunning, Ready, Available처럼 정상 상태를 나타내는 필드가 있는지 봅니다.
  • RESTARTS/EVENTS재시작 횟수나 Warning 이벤트가 증가하지 않는지 확인합니다.
YAML
# 3. VPA Off 모드로 추천값 수집 (1-7일 데이터 수집 권장)
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: over-provisioned-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: over-provisioned
  updatePolicy:
    updateMode: "Off"
  resourcePolicy:
    containerPolicies:
      - containerName: app
        minAllowed:
          cpu: 25m
          memory: 64Mi
        maxAllowed:
          cpu: 500m
          memory: 1Gi
Kubernetes
kubectl apply -f over-provisioned-vpa.yaml

# 24시간 후 추천값 확인
kubectl describe vpa over-provisioned-vpa
# Target:
#   Cpu:     75m       ← 2000m → 75m으로 조정 추천
#   Memory:  250Mi     ← 4Gi → 250Mi로 조정 추천

# 4. 추천값을 Deployment에 수동 적용
kubectl patch deployment over-provisioned --type=json -p='[
  {"op": "replace", "path": "/spec/template/spec/containers/0/resources/requests/cpu", "value": "75m"},
  {"op": "replace", "path": "/spec/template/spec/containers/0/resources/requests/memory", "value": "250Mi"},
  {"op": "replace", "path": "/spec/template/spec/containers/0/resources/limits/cpu", "value": "200m"},
  {"op": "replace", "path": "/spec/template/spec/containers/0/resources/limits/memory", "value": "500Mi"}
]'

# 절감 효과
echo "CPU requests 절감: 2000m → 75m (96% 절감)"
echo "Memory requests 절감: 4Gi → 250Mi (94% 절감)"

API 서버에 VPA Auto 모드를 적용했더니 하루에도 수십 번 파드가 재시작되고 있습니다. 재시작 중에는 서비스 중단이 발생하고, HPA로 파드 수를 늘려도 VPA가 계속 재시작시킵니다.

Kubernetes
# 증상 확인
kubectl get pods -l app=api-server -w
# api-server-aaa  Running → Terminating → Running  (1시간에 3-4회 반복)

kubectl describe pod api-server-aaa | grep -A 5 "Events:"
# Warning  Evicted   VPA Updater evicted pod api-server-aaa
#                    to apply resource recommendation

# 원인 분석: VPA 추천값 변화 빈도 확인
kubectl describe vpa api-server-vpa
# Last Update Time: 2024-01-15 14:23:01  ← 빈번한 업데이트
# Last Update Time: 2024-01-15 14:18:44
# Last Update Time: 2024-01-15 14:11:22
# ← 5분마다 추천값이 크게 변동
Kubernetes
# 트래픽 패턴 분석
kubectl top pods -l app=api-server --containers
# 09:00  api-server  cpu: 50m   memory: 200Mi  (야간 트래픽)
# 12:00  api-server  cpu: 800m  memory: 1.2Gi  (점심 피크)
# 15:00  api-server  cpu: 200m  memory: 400Mi  (오후)
# ← 낮과 밤의 사용량 차이가 16배 → VPA 추천값이 급변
Kubernetes
# 해결책 1: Auto → Initial 모드로 변경 (일일 1회 롤링 업데이트 방식)
kubectl patch vpa api-server-vpa --type=merge -p '
{"spec": {"updatePolicy": {"updateMode": "Initial"}}}'

# 해결책 2: Auto 모드 유지 + minAllowed/maxAllowed 범위 좁히기
# (추천값 변화 범위를 제한하여 Evict 빈도 감소)
kubectl patch vpa api-server-vpa --type=merge -p '
{
  "spec": {
    "resourcePolicy": {
      "containerPolicies": [{
        "containerName": "api",
        "minAllowed": {"cpu": "200m", "memory": "400Mi"},
        "maxAllowed": {"cpu": "1000m", "memory": "2Gi"}
      }]
    }
  }
}'
# 범위를 좁히면 추천값의 최대 변화폭이 줄어들어 재시작 빈도 감소

# 해결책 3: Off 모드로 전환 후 수집한 추천값을 주기적으로 수동 적용
# 주 1회 리뷰 → 허용 변화량 초과 시 Deployment 직접 패치
Kubernetes
# 해결책 4 (권장): 트래픽 패턴이 불규칙하면 HPA + 고정 resources 조합
# VPA로 '안정 구간'의 적정 requests 찾은 후 HPA로 파드 수 조정
# 1. VPA Off 모드 1주일 → 야간 최솟값 확인 (e.g., cpu 200m, mem 512Mi)
# 2. requests를 해당 값으로 고정
# 3. HPA로 CPU 80% 기준 파드 수 자동 조정
# → 재시작 없이 트래픽 변화에 대응

# 최종 안정 설정 확인
kubectl top pods -l app=api-server
kubectl get hpa api-server-hpa

핵심 교훈: VPA Auto 모드는 안정적인 트래픽 패턴을 가진 서비스에 적합합니다. 낮과 밤의 사용량 차이가 크거나 이벤트성 트래픽이 있는 서비스는 VPA Off 모드로 최적 기준값을 찾은 후 HPA를 조합하는 것이 더 안정적입니다.

💼
실무 맥락
현업 패턴

시나리오: 신규 서비스의 requests/limits 초기값 설정

백엔드 팀에서 새로운 Java 마이크로서비스를 K8s에 배포하려는데 "requests를 얼마로 설정해야 하죠?"라는 질문이 왔습니다. 부하 테스트 결과가 없어 추정이 어렵습니다.

로컬 터미널
# 전략: VPA Off 모드로 스테이징에서 1주일 관찰 → 추천값을 프로덕션에 적용

# 1단계: 스테이징 배포 (보수적 초기값)
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: new-java-service
  namespace: staging
spec:
  replicas: 2
  template:
    spec:
      containers:
        - name: app
          image: myrepo/java-service:v1.0
          resources:
            requests:
              cpu: 500m       # Java는 시작 시 CPU 소비 많음
              memory: 512Mi   # JVM 힙 기본 256Mi + 오버헤드
            limits:
              cpu: 2000m
              memory: 2Gi
---
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: java-service-vpa
  namespace: staging
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: new-java-service
  updatePolicy:
    updateMode: "Off"   # 관찰만
  resourcePolicy:
    containerPolicies:
      - containerName: app
        minAllowed:
          cpu: 100m
          memory: 256Mi
        maxAllowed:
          cpu: 4000m
          memory: 4Gi
EOF

# 2단계: 1주일 후 추천값 확인
kubectl describe vpa java-service-vpa -n staging | grep -A 10 "Recommendation:"

# 3단계: 추천값 기반으로 프로덕션 초기값 설정
# Target CPU: 320m → requests: 350m, limits: 1000m
# Target Memory: 768Mi → requests: 800Mi, limits: 1.5Gi

# 4단계: 프로덕션 배포 후 VPA Off 모드로 계속 모니터링

실무 포인트: Java 서비스는 JVM 웜업으로 초기 CPU/메모리가 높고, 안정화 후 낮아집니다. VPA는 최근 사용 패턴을 가중치 있게 반영하므로 웜업 기간 이후 데이터가 충분히 쌓인 후의 추천값이 더 정확합니다. 스테이징에서 최소 1주일(주중+주말 패턴 포함) 관찰을 권장합니다.

HPA vs VPA 선택 요약

기준HPAVPA
확장 방향수평 (파드 수)수직 (파드 크기)
적합한 서비스스테이트리스 APIDB, Stateful, 배치 Job
반응 속도빠름 (파드 수 즉시 조정)느림 (재시작 필요)
서비스 중단없음Auto 모드: 재시작 시 순단
초기 설정 최적화불가Off/Initial 모드로 가능
동시 사용주의 필요 (CPU 충돌)메모리만 VPA 제어 시 가능

핵심 요약

개념명령/설정실무 사용 빈도
VPA 조회kubectl get vpa -n <ns>리소스 최적화 시
추천값 확인kubectl describe vpa <name>Off 모드 분석
Off 모드updateMode: "Off"초기 추천값 수집
Initial 모드updateMode: "Initial"배치 Job, 안정적 적용
Auto 모드updateMode: "Auto"안정적 트래픽 서비스
범위 제한minAllowed / maxAllowed추천값 급변 방지
CPU+메모리 분리controlledResources: ["memory"]HPA 동시 사용 시
실제 사용량 확인kubectl top pods --containersVPA 전 현황 파악

지식 확인

퀴즈 — 4문제

Q1

VPA의 Off 모드는 어떤 상황에 유용한가요?

Q2

VPA Auto 모드에서 파드가 자주 재시작되는 주요 원인은?

Q3

HPA 대신 VPA를 선택해야 하는 상황은?

Q4

VPA의 minAllowed와 maxAllowed 설정의 목적은?

0 / 4 답변

🧪 실습으로 확인하기

K8s 기초 — Pod/Deployment/Service 생성

초급

kubectl로 nginx Pod를 생성하고 Deployment와 Service를 차례로 만들어 클러스터 외부에서 접근 가능한 상태까지 구성한다. K8s 3대 리소스의 역할과 관계를 직접 손으로 익힌다.

40📋 5단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요

kubernetes고급 · 70
[Kubernetes] 나만의 커스텀 Helm Chart 작성법과 환경별 Value 튜닝
Kubernetes 트랙 계속
docker입문 · 30
[Docker] 백엔드 개발자에게 Docker와 컨테이너 가상화가 필수인 이유
Docker 트랙 시작점