워크로드 및 연동 솔루션 별 고려 사항

최종 수정: 2026. 1. 23.

Skuber+ Optimize 워크로드 및 연동 솔루션 별 고려 사항


목차

  1. Skuber+ Optimize 동작 원리
  2. 워크로드별 호환성 매트릭스
  3. Stateful 워크로드
  4. 데이터베이스 워크로드
  5. 메시지 큐 / 스트리밍
  6. JVM 기반 애플리케이션
  7. GPU/ML 워크로드
  8. GitOps 연동
  9. Service Mesh 연동
  10. 모니터링/Observability 연동
  11. Operator 기반 워크로드
  12. Batch/CronJob 워크로드
  13. 고객 사전 점검 체크리스트
  14. 권장 설정 템플릿

개요

본 문서는 Skuber+ Optimize(VPA 기반 리소스 최적화 솔루션)를 Kubernetes 환경에 적용할 때 고려해야 하는 워크로드 유형과 연동 솔루션들에 대한 종합 가이드입니다.


1. Skuber+ Optimize 동작 원리

1.1 목표: 클라우드 비용 최적화

Kubernetes 환경에서 리소스 오버프로비저닝은 클라우드 비용 낭비의 주요 원인입니다. 많은 조직이 "안전을 위해" 실제 사용량보다 2~3배 높은 리소스를 할당하며, 이는 불필요한 비용 지출로 이어집니다.

Skuber+ Optimize의 핵심 가치:

  • 실제 사용량 기반의 적정 리소스 할당으로 비용 절감
  • 안전 마진과 OOM 방지 메커니즘으로 안정성 보장
  • 자동화된 리소스 관리로 운영 부담 감소

1.2 적용 대상: Deployment만 지원

Skuber+ Optimize는 Deployment 워크로드에만 적용됩니다.

워크로드 유형 Optimize 적용 설명
Deployment 자동 적용 Stateless 워크로드, 안전한 롤링 업데이트 가능
StatefulSet 추천값만 제공 순차적 재시작 필요, 수동 적용 권장
DaemonSet 추천값만 제공 노드별 실행, 수동 검토 필요
Job/CronJob 추천값만 제공 실행 시간 짧음, 참고용

Deployment만 지원하는 이유:

  • Deployment는 롤링 업데이트를 통해 서비스 중단 없이 리소스 변경 가능
  • StatefulSet, DaemonSet 등은 재시작 시 서비스 영향이 크거나 데이터 정합성 이슈 발생 가능
  • 안전한 비용 최적화를 위해 검증된 워크로드 유형에만 자동 적용

1.3 동작 방식

Skuber+ Optimize는 Kubernetes VPA(Vertical Pod Autoscaler)의 Recommender가 제공하는 리소스 추천값을 기반으로 Deployment 워크로드의 CPU/Memory 리소스를 자동으로 최적화합니다.

1.4 VPA 추천값의 한계

VPA Recommender의 추천값은 과거 사용량 데이터를 기반으로 계산됩니다. 그러나 다음과 같은 상황에서는 추천값만으로 충분하지 않을 수 있습니다:

상황 원인 영향
트래픽 급증 예측 불가능한 스파이크 순간적 메모리 부족
JVM Warmup Heap 확장, JIT 컴파일 초기 메모리 급증
배치 작업 대량 데이터 로딩 일시적 메모리 스파이크
캐시 프리로딩 애플리케이션 시작 시 캐시 적재 초기 메모리 사용량 높음
Agent 최초 설치 리소스 프로파일 변경 Pod 재기동 시 Crash

이러한 한계를 보완하기 위해 Skuber+ Optimize는 안전 마진OOM 방지 메커니즘을 제공합니다.

1.5 OOM 방지 메커니즘

Skuber+ Optimize는 VPA 추천값에 안전 마진을 적용하고, OOM 발생 시 자동으로 Bump-up하여 안정성을 보장합니다.

1.6 Bump-up 단계별 상세

단계 마진 메모리 계산 예시 (추천값 1Gi 기준) 트리거 조건
기본 +30% 1Gi × 1.3 = 1.3Gi 초기 적용 시
1차 Bump-up +50% 1Gi × 1.5 = 1.5Gi OOM 1회 발생
2차 Bump-up +100% 1Gi × 2.0 = 2.0Gi OOM 2회 발생
3차 Bump-up +200% 1Gi × 3.0 = 3.0Gi OOM 3회 발생
4차 롤백 원복 원래 설정으로 복원 OOM 4회 발생

구현 세부사항

OOM 감지 방식:

# Pod 상태 모니터링
status:
  containerStatuses:
  - name: my-app
    lastState:
      terminated:
        reason: OOMKilled  # OOM 감지 트리거
        exitCode: 137

Bump-up 적용 로직:

# 의사 코드
def calculate_memory_with_margin(recommended_memory, crash_count):
    margins = {
        0: 1.30,   # 기본: +30%
        1: 1.50,   # 1차: +50%
        2: 2.00,   # 2차: +100%
        3: 3.00,   # 3차: +200%
    }
    
    if crash_count >= 4:
        return rollback_to_original()
    
    return recommended_memory * margins.get(crash_count, 1.30)

안정화 판단 기준:

  • Bump-up 적용 후 24시간 동안 OOM 미발생 시 안정화로 판단
  • 안정화 후에도 추천값이 변경되면 새로운 추천값 + 30% 마진으로 재조정

롤백 시 처리

4차 연속 OOM 발생 시:

  1. 즉시 롤백: Skuber+ Optimize 적용 전 원래 리소스 설정으로 복원
  2. 알림 발송: 관리자에게 Slack/Email 알림
  3. 자동 제외: 해당 워크로드는 Skuber+ Optimize 적용 대상에서 자동 제외
  4. 분석 요청: 수동 분석 후 재적용 필요

OOM 방지 설정 예시

# Skuber+ Optimize CRD 설정
apiVersion: skuber.io/v1
kind: OptimizePolicy
metadata:
  name: my-app-policy
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  oomProtection:
    enabled: true
    baseMargin: 30          # 기본 마진 30%
    bumpUpMargins:
      - 50                   # 1차: 50%
      - 100                  # 2차: 100%
      - 200                  # 3차: 200%
    maxBumpUpCount: 3        # 최대 Bump-up 횟수
    stabilizationPeriod: 24h # 안정화 판단 기간
    rollbackOnMaxRetry: true # 최대 재시도 후 롤백
    notifyOnRollback:
      slack: "#alerts"
      email: "ops@company.com"

워크로드별 OOM 방지 권장 설정

워크로드 유형 기본 마진 Bump-up 활성화 특별 고려사항
Stateless 웹앱 30% 권장 표준 설정 적용
JVM 애플리케이션 50% 필수 Heap 확장 고려
메모리 캐시 (Redis Client) 40% 권장 캐시 크기 변동
Batch/CronJob 50% 선택적 실행 시간 짧음
ML Inference 40% 권장 모델 로딩 시 스파이크

2. 워크로드별 호환성 매트릭스

Skuber+ Optimize는 Deployment에만 자동 적용됩니다. 다른 워크로드 유형은 추천값을 참고하여 수동으로 적용해야 합니다.

2.1 종합 호환성 요약

워크로드 유형 Optimize 자동 적용 위험도 권장 OOM 마진 비고
Deployment (Stateless) 자동 적용 낮음 30% 비용 최적화 대상
Deployment (JVM) 자동 적용 중간 50% Heap 메모리 고려
Deployment (ML Inference) 자동 적용 중간 40% 모델 로딩 고려
StatefulSet (일반) 추천값만 중간 40% 수동 적용 권장
StatefulSet (Database) 추천값만 높음 50% Operator 연동 권장
StatefulSet (Kafka Broker) 제외 매우 높음 N/A 적용 금지
DaemonSet 추천값만 중간 40% 노드별 검토 필요
Job/CronJob 추천값만 낮음 50% 실행 시간 짧음

2.2 Deployment 세부 분류

Deployment라도 애플리케이션 특성에 따라 권장 설정이 다릅니다:

Deployment 유형 권장 OOM 마진 특별 고려사항
일반 웹앱 (Node.js, Python, Go) 30% 표준 설정
JVM 애플리케이션 (Java, Kotlin) 50% Heap 확장, GC 고려
ML Inference 40% 모델 로딩 시 스파이크
메모리 캐시 클라이언트 40% 캐시 크기 변동
API Gateway 30% 트래픽 패턴 모니터링

2.3 연동 솔루션별 호환성

연동 솔루션 호환성 설정 필요 주요 이슈
ArgoCD 조건부 ignoreDifferences 필수 Sync Loop 방지
FluxCD 조건부 유사한 설정 필요 Drift Detection
Helm Operator 호환 values 충돌 주의 릴리스 관리
KEDA 조건부 메트릭 분리 필요 HPA 충돌 가능
Istio 호환 Sidecar 리소스 고려 CPU 오버헤드
Linkerd 호환 Sidecar 리소스 설정 경량화된 오버헤드
Prometheus 호환 - 메트릭 수집
Datadog 호환 - 메트릭 연동
HPA 주의 메트릭 분리 필수 충돌 위험 높음

3. Stateful 워크로드

Skuber+ Optimize 정책: StatefulSet에는 자동 최적화가 적용되지 않습니다. 추천값만 제공되며, 수동으로 검토 후 적용해야 합니다.

3.1 StatefulSet에 자동 적용하지 않는 이유

핵심 문제:

  • StatefulSet의 Pod는 순차적으로 관리되며, 임의 재시작이 어려움
  • VPA Auto 모드는 Pod를 evict하여 리소스 변경을 적용하므로 서비스 중단 위험
  • Master/Primary Pod가 먼저 재시작되면 데이터 정합성 문제 발생 가능

기술적 근거 (Kubernetes VPA 공식 문서):

"VPA does not support StatefulSets yet. The problem is scaling pods in StatefulSet is not simple. Neither starting nor restarting can be done the way it's done for a Deployment or ReplicaSet."

3.2 추천값 활용 방법

Skuber+ Optimize는 StatefulSet에 대해서도 추천값을 제공합니다. 이 추천값을 참고하여 수동으로 리소스를 조정할 수 있습니다.

# Skuber+가 제공하는 추천값 조회 (VPA Off 모드)
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: stateful-app-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: StatefulSet
    name: my-stateful-app
  updatePolicy:
    updateMode: "Off"  # 추천값만 수집, 자동 적용 안 함
  resourcePolicy:
    containerPolicies:
    - containerName: '*'
      minAllowed:
        cpu: 100m
        memory: 256Mi
      maxAllowed:
        cpu: 4
        memory: 8Gi

3.3 수동 적용 전략

단계 모드 목적
1. 모니터링 Off 7-14일간 리소스 패턴 분석
2. 검증 Off 추천값 검토 및 테스트 환경 적용
3. 점진적 적용 Initial 신규 Pod 생성 시에만 적용
4. 유지보수 시 적용 Manual 계획된 유지보수 시간에 수동 적용

4. 데이터베이스 워크로드

Skuber+ Optimize 정책: 데이터베이스 워크로드(StatefulSet)에는 자동 최적화가 적용되지 않습니다. 추천값만 제공되며, Operator와 연동하거나 수동으로 적용해야 합니다.

4.1 MySQL / PostgreSQL

위험 요소:

  • Primary/Replica 구조에서 Primary Pod 재시작 시 Failover 발생
  • 대용량 데이터베이스의 경우 재시작 시간이 길어 서비스 영향
  • Connection Pool이 끊기며 애플리케이션 에러 발생 가능

권장 구성:

# MySQL VPA - Recommend Only
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: mysql-vpa
  namespace: database
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: StatefulSet
    name: mysql
  updatePolicy:
    updateMode: "Off"
  resourcePolicy:
    containerPolicies:
    - containerName: mysql
      minAllowed:
        cpu: 500m
        memory: 1Gi
      maxAllowed:
        cpu: 8
        memory: 32Gi
      controlledResources: ["cpu", "memory"]

Database Operator 연동 시:

  • Percona Operator / Vitess: Operator의 스케일링 기능 사용 권장
  • CloudNativePG: Operator가 리소스 관리 담당
  • VPA는 Off 모드로 추천값만 참고

4.2 MongoDB

특수 고려사항:

  • Sharded Cluster의 경우 각 Shard가 별도 StatefulSet으로 운영
  • Config Server, Mongos, Shard 모두 다른 리소스 요구사항
  • 리밸런싱 중 스케일링 시 데이터 정합성 위험

MongoDB Operator (Percona/MongoDB Enterprise)와 연동:

# MongoDB VPA - 각 컴포넌트별 분리
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: mongodb-shard-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: StatefulSet
    name: mongodb-shard0
  updatePolicy:
    updateMode: "Off"

4.3 Redis

Standalone Redis:

  • 메모리 기반 데이터 저장소로 메모리 설정이 핵심
  • maxmemory 설정과 Pod memory limit 동기화 필수

Redis Cluster:

  • Cluster 모드에서 Pod 재시작 시 Slot 재분배 발생
  • Failover 시간 동안 일부 키 접근 불가

권장 설정:

# Redis Cluster - VPA 제외 권장
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: redis-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: StatefulSet
    name: redis-cluster
  updatePolicy:
    updateMode: "Off"  # 클러스터 안정성을 위해 Off 필수

4.4 Elasticsearch

핵심 이슈:

  • Shard 재분배 시 클러스터 부하 급증
  • Master 노드 재시작 시 클러스터 불안정
  • 메모리 설정(Heap)과 Pod 메모리 간 관계 복잡

ECK (Elastic Cloud on Kubernetes) 연동:

# Elasticsearch - Data 노드만 VPA 참고용 적용
# Master 노드는 절대 VPA 적용 금지
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: elasticsearch-data-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: StatefulSet
    name: elasticsearch-data
  updatePolicy:
    updateMode: "Off"
  resourcePolicy:
    containerPolicies:
    - containerName: elasticsearch
      minAllowed:
        memory: 4Gi  # ES는 최소 메모리 요구량 높음
      controlledResources: ["memory"]  # CPU만 제외하고 메모리만 추천

5. 메시지 큐 / 스트리밍

Skuber+ Optimize 정책: Kafka Broker(StatefulSet)는 적용 제외 대상입니다. Kafka Consumer가 Deployment인 경우에만 자동 최적화가 적용됩니다.

5.1 Apache Kafka

Broker (반드시 제외):

위험 시나리오 영향도 발생 조건
Broker Pod 재시작 치명적 VPA Auto 모드
파티션 Under-replicated 높음 동시 다중 Broker 재시작
데이터 손실 치명적 PV 바인딩 해제
# Kafka Broker - 반드시 제외 (StatefulSet이므로 Skuber+ 자동 적용 안 됨)
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: kafka-broker-vpa-exclude
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: StatefulSet
    name: kafka
  updatePolicy:
    updateMode: "Off"  # 추천값 수집만 (적용 절대 금지)

Consumer (Deployment인 경우 자동 적용):

Kafka Consumer가 Deployment로 배포된 경우 Skuber+ Optimize가 자동 적용됩니다. 단, Consumer 리밸런싱 문제를 완화하기 위한 설정이 필요합니다.

# Consumer 애플리케이션 설정
spec:
  containers:
  - name: kafka-consumer
    env:
    - name: KAFKA_GROUP_INSTANCE_ID
      valueFrom:
        fieldRef:
          fieldPath: metadata.name  # Static Membership
    - name: KAFKA_SESSION_TIMEOUT_MS
      value: "300000"  # 5분 - 재시작 시간 확보
    - name: KAFKA_PARTITION_ASSIGNMENT_STRATEGY
      value: "org.apache.kafka.clients.consumer.CooperativeStickyAssignor"

VPA 대신 KEDA 권장:

# KEDA ScaledObject - Kafka Lag 기반 스케일링
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: kafka-consumer-scaler
spec:
  scaleTargetRef:
    name: kafka-consumer
  minReplicaCount: 1
  maxReplicaCount: 10  # 파티션 수 이하로 제한
  triggers:
  - type: kafka
    metadata:
      bootstrapServers: kafka:9092
      consumerGroup: my-consumer-group
      topic: my-topic
      lagThreshold: "100"
  advanced:
    horizontalPodAutoscalerConfig:
      behavior:
        scaleDown:
          stabilizationWindowSeconds: 300  # 리밸런싱 최소화

5.2 RabbitMQ

위험 요소:

  • Quorum Queue의 경우 노드 재시작 시 리더 선출 발생
  • 메시지 손실 방지를 위해 graceful shutdown 필수

권장 설정:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: rabbitmq-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: StatefulSet
    name: rabbitmq
  updatePolicy:
    updateMode: "Off"

5.3 Apache Pulsar

  • Broker와 BookKeeper 모두 StatefulSet으로 운영
  • ZooKeeper 의존성으로 인해 스케일링 복잡
  • 권장: VPA Off 모드, Pulsar 자체 autoscaling 기능 활용

6. JVM 기반 애플리케이션

Skuber+ Optimize 정책: JVM 애플리케이션(Deployment)에는 자동 최적화가 적용되지만, Memory는 제외하고 CPU만 최적화합니다. 기본 OOM 마진은 **50%**로 적용됩니다.

6.1 핵심 문제점

GKE 공식 문서 경고:

"Vertical Pod autoscaling is not ready for use with JVM-based workloads due to limited visibility into actual memory usage of the workload."

기술적 이유:

  1. Heap 메모리 특성: JVM은 할당된 메모리를 즉시 반환하지 않음
  2. GC 영향: Garbage Collection 활동이 CPU 사용률에 영향
  3. JIT 컴파일: 시작 시 CPU 버스트 발생으로 잘못된 스케일링 트리거

6.2 JVM 메모리 구성 이해

┌─────────────────────────────────────────┐
│           Container Memory Limit         │
│  ┌─────────────────────────────────┐    │
│  │         JVM Heap (-Xmx)         │    │
│  │    (Application Objects)        │    │
│  └─────────────────────────────────┘    │
│  ┌─────────────────────────────────┐    │
│  │       Metaspace / PermGen       │    │
│  └─────────────────────────────────┘    │
│  ┌─────────────────────────────────┐    │
│  │    Native Memory (Threads, JNI) │    │
│  └─────────────────────────────────┘    │
│  ┌─────────────────────────────────┐    │
│  │      Code Cache / Buffers       │    │
│  └─────────────────────────────────┘    │
└─────────────────────────────────────────┘

6.3 권장 설정

# JVM 애플리케이션 - CPU만 VPA 적용, Memory는 수동 관리
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: java-app-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: java-application
  updatePolicy:
    updateMode: "Off"  # 또는 "Initial"
  resourcePolicy:
    containerPolicies:
    - containerName: java-app
      controlledResources: ["cpu"]  # Memory 제외!
      minAllowed:
        cpu: 200m
      maxAllowed:
        cpu: 4

6.4 JVM용 Skuber+ OOM 방지 설정

JVM 애플리케이션은 메모리 특성상 **기본 마진 50%**를 권장합니다:

# Skuber+ Optimize - JVM 전용 설정
apiVersion: skuber.io/v1
kind: OptimizePolicy
metadata:
  name: java-app-policy
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: java-application
  resourcePolicy:
    controlledResources: ["cpu"]  # Memory는 JVM이 직접 관리
  oomProtection:
    enabled: true
    baseMargin: 50              # JVM은 기본 50% 마진 권장
    bumpUpMargins:
      - 75                       # 1차: 75%
      - 100                      # 2차: 100%
      - 150                      # 3차: 150%
    stabilizationPeriod: 48h    # JVM은 안정화 기간 늘림

JVM OOM 방지를 위한 추가 권장사항:

  • -XX:+ExitOnOutOfMemoryError: OOM 발생 시 즉시 종료하여 Skuber+가 감지할 수 있도록 함
  • -XX:+HeapDumpOnOutOfMemoryError: 분석용 힙 덤프 생성

JVM 설정 권장사항:

env:
- name: JAVA_OPTS
  value: >-
    -XX:+UseContainerSupport
    -XX:MaxRAMPercentage=75.0
    -XX:InitialRAMPercentage=50.0
    -XX:+UseG1GC
    -XX:MaxGCPauseMillis=200
    -XX:G1PeriodicGCInterval=10000

6.5 HPA와 JVM 조합 시 주의사항

# JVM용 HPA - readinessProbe 활용 필수
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: java-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: java-application
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70  # JIT 컴파일 고려하여 여유 있게
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 120  # JVM Warmup 시간 고려
    scaleDown:
      stabilizationWindowSeconds: 300

7. GPU/ML 워크로드

7.1 GPU 워크로드의 특수성

VPA의 한계:

  • VPA는 CPU/Memory만 관리, GPU 리소스는 관리 불가
  • GPU 워크로드는 nvidia.com/gpu 같은 extended resource 사용
  • GPU Pod 재시작 시 비용이 매우 높음 (GPU 인스턴스 시간 손실)

7.2 ML Training 워크로드

권장 도구:

  • Kueue: Kubernetes-native job queueing
  • Volcano: Gang scheduling for distributed training
  • NVIDIA Run:ai: GPU 오케스트레이션
# GPU 워크로드 - VPA 적용 제한
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: ml-training-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: ml-training
  updatePolicy:
    updateMode: "Off"  # 추천값 참고만
  resourcePolicy:
    containerPolicies:
    - containerName: trainer
      controlledResources: ["cpu", "memory"]  # GPU는 VPA 관리 불가

7.3 ML Inference 워크로드

KEDA를 활용한 Queue 기반 스케일링:

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: inference-scaler
spec:
  scaleTargetRef:
    name: inference-server
  minReplicaCount: 1
  maxReplicaCount: 10
  triggers:
  - type: prometheus
    metadata:
      serverAddress: http://prometheus:9090
      metricName: inference_queue_size
      threshold: "10"
      query: sum(inference_pending_requests)

8. GitOps 연동

8.1 ArgoCD 연동

핵심 문제:

  • ArgoCD는 Git을 Source of Truth로 사용
  • VPA/Skuber+가 리소스 값을 변경하면 "OutOfSync" 상태 발생
  • Auto-Sync 설정 시 무한 루프 위험

필수 설정 요약

설정 역할
ignoreDifferences 차이 감지에서 제외 (drift 무시)
RespectIgnoreDifferences=true Sync 시에도 해당 필드를 변경하지 않음

중요: 두 설정을 함께 사용해야 Skuber+가 변경한 값이 완전히 보존됩니다.

설정별 동작 차이

ignoreDifferences만 설정한 경우:

kubectl edit → 값 변경
    ↓
ArgoCD: "차이 있지만 ignoreDifferences니까 무시" (selfHeal 안 함)
    ↓
Sync 발생 (Git 변경 또는 수동 Sync)
    ↓
ArgoCD: "Sync니까 Git 기준으로 적용!" → 원래 값으로 원복 ❌

ignoreDifferences + RespectIgnoreDifferences 설정한 경우:

kubectl edit → 값 변경
    ↓
ArgoCD: "차이 있지만 ignoreDifferences니까 무시"
    ↓
Sync 발생
    ↓
ArgoCD: "RespectIgnoreDifferences니까 이 필드는 건드리지 않음" → 변경값 유지 ✅

기본 설정 구조

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
spec:
  # ... source, destination 등

  ignoreDifferences:
    - group: <API_GROUP>
      kind: <RESOURCE_KIND>
      name: <RESOURCE_NAME> # 선택: 특정 리소스만 지정
      namespace: <NAMESPACE> # 선택: 특정 네임스페이스만 지정
      jsonPointers:
        - <JSON_POINTER_PATH>
      # 또는
      jqPathExpressions:
        - <JQ_EXPRESSION>

  syncPolicy:
    syncOptions:
      - RespectIgnoreDifferences=true # 필수!

Skuber+ 권장 설정 예시

# ArgoCD Application에 ignoreDifferences 추가
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-application
  project: default
  source:
    repoURL: https://github.com/org/repo
    path: manifests
  destination:
    server: https://kubernetes.default.svc
    namespace: production

  # Skuber+ Optimize 연동을 위한 핵심 설정
  ignoreDifferences:
    - group: apps
      kind: Deployment
      jsonPointers:
        - /spec/template/spec/containers/0/resources/requests
        - /spec/template/spec/containers/0/resources/limits
    - group: apps
      kind: StatefulSet
      jsonPointers:
        - /spec/template/spec/containers/0/resources/requests
        - /spec/template/spec/containers/0/resources/limits

  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      - RespectIgnoreDifferences=true # 필수!

System-Level 설정 (argocd-cm)

여러 Application에 동일한 설정을 적용하려면 ArgoCD ConfigMap에서 전역 설정을 사용합니다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  # 모든 Deployment의 resources 필드 무시
  resource.customizations.ignoreDifferences.apps_Deployment: |
    jqPathExpressions:
    - .spec.template.spec.containers[].resources

  # 모든 StatefulSet의 resources 필드 무시
  resource.customizations.ignoreDifferences.apps_StatefulSet: |
    jqPathExpressions:
    - .spec.template.spec.containers[].resources

  # 모든 DaemonSet의 resources 필드 무시
  resource.customizations.ignoreDifferences.apps_DaemonSet: |
    jqPathExpressions:
    - .spec.template.spec.containers[].resources

참고: System-Level 설정을 사용해도 각 Application에 RespectIgnoreDifferences=true는 개별 설정해야 합니다.

8.2 FluxCD 연동

Kustomization에서 리소스 패치 제외:

apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: my-app
  namespace: flux-system
spec:
  interval: 10m
  path: ./manifests
  prune: true
  sourceRef:
    kind: GitRepository
    name: my-repo
  patches:
  - patch: |
      - op: remove
        path: /spec/template/spec/containers/0/resources
    target:
      kind: Deployment

8.3 Helm과 VPA 연동

values.yaml에서 리소스 템플릿화:

# values.yaml
resources:
  requests:
    cpu: "100m"    # VPA에 의해 오버라이드될 수 있음
    memory: "256Mi"
  limits:
    cpu: "1"
    memory: "1Gi"

# VPA가 관리하는 경우 빈 값으로 설정 가능
# resources: {}

9. Service Mesh 연동

9.1 Istio 연동

Sidecar 리소스 오버헤드:

  • Envoy Proxy: 약 100-150m CPU, 50-100MB Memory per Pod
  • VPA 추천값 계산 시 Sidecar 리소스 포함됨

Sidecar 리소스 설정:

# Istio Sidecar 리소스 명시적 설정
apiVersion: v1
kind: ConfigMap
metadata:
  name: istio-sidecar-injector
  namespace: istio-system
data:
  values: |
    global:
      proxy:
        resources:
          requests:
            cpu: 50m
            memory: 64Mi
          limits:
            cpu: 200m
            memory: 256Mi

VPA에서 Sidecar 제외:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-app-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: my-app
  resourcePolicy:
    containerPolicies:
    - containerName: istio-proxy
      mode: "Off"  # Sidecar는 VPA 관리에서 제외
    - containerName: my-app
      mode: "Auto"

Istio 메트릭 기반 HPA (VPA와 함께 사용):

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  metrics:
  - type: External
    external:
      metric:
        name: istio_requests_per_second
        selector:
          matchLabels:
            destination_workload: my-app
      target:
        type: AverageValue
        averageValue: "100"

9.2 Linkerd 연동

Linkerd 장점:

  • 경량 Rust 기반 Proxy (약 10m CPU, 20MB Memory)
  • Istio 대비 50% 이상 낮은 리소스 사용

HPA와 Linkerd 연동 시 주의사항:

Linkerd Sidecar에 리소스 request가 없으면 HPA가 동작하지 않음:

# Linkerd Proxy 리소스 명시적 설정
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  annotations:
    linkerd.io/inject: enabled
    config.linkerd.io/proxy-cpu-request: "10m"
    config.linkerd.io/proxy-memory-request: "20Mi"
    config.linkerd.io/proxy-cpu-limit: "100m"
    config.linkerd.io/proxy-memory-limit: "50Mi"

9.3 Service Mesh 리소스 오버헤드 비교

Service Mesh CPU (request) Memory (request) VPA 호환성
Istio (Envoy) 100m 128Mi Sidecar 제외 필요
Istio Ambient Node 레벨 Node 레벨 양호
Linkerd 10m 20Mi 양호
Cilium Node 레벨 Node 레벨 양호

10. 모니터링/Observability 연동

10.1 Prometheus 연동

VPA 메트릭 수집:

# ServiceMonitor for VPA
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: vpa-recommender
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: vpa-recommender
  endpoints:
  - port: metrics
    interval: 30s

유용한 VPA 메트릭:

# VPA 추천값 vs 실제 사용량
vpa_recommender_recommendation_cpu{container="my-app"}
vpa_recommender_recommendation_memory{container="my-app"}

# 실제 리소스 사용량
container_cpu_usage_seconds_total
container_memory_working_set_bytes

10.2 Datadog 연동

# Datadog Agent에서 VPA 메트릭 수집
apiVersion: v1
kind: ConfigMap
metadata:
  name: datadog-cluster-agent
data:
  kubernetes_vpa.yaml: |
    ad_identifiers:
      - vpa-recommender
    init_config:
    instances:
      - prometheus_url: http://%%host%%:8942/metrics

10.3 Grafana 대시보드

VPA 모니터링을 위한 주요 패널:

  1. 추천값 vs 현재 설정: 리소스 낭비/부족 식별
  2. 추천값 변화 추이: 시간에 따른 패턴 분석
  3. Pod 재시작 횟수: VPA Auto 모드 영향 추적
  4. OOM Kill 이벤트: 메모리 추천값 적정성 확인

11. Operator 기반 워크로드

11.1 Database Operators

Operator VPA 연동 권장 설정
CloudNativePG 제한적 Off 모드, Operator 스케일링 사용
Percona Operator (MySQL/MongoDB/PostgreSQL) 지원 Operator의 VPA 연동 기능 활용
Strimzi (Kafka) 비호환 Cruise Control 사용 권장
Redis Operator 제한적 Off 모드
ECK (Elasticsearch) 제한적 Off 모드

Percona Operator의 VPA 통합 예시:

apiVersion: psmdb.percona.com/v1
kind: PerconaServerMongoDB
metadata:
  name: my-cluster
spec:
  replsets:
  - name: rs0
    size: 3
    resources:
      requests:
        cpu: "300m"
        memory: "0.5G"
      limits:
        cpu: "2"
        memory: "2G"
    # Percona Operator는 자체 VPA 연동 지원
    verticalAutoscaler:
      enabled: true
      updateMode: "Off"

Flink 자체 Autoscaler 사용 권장:

apiVersion: flink.apache.org/v1beta1
kind: FlinkDeployment
metadata:
  name: flink-job
spec:
  flinkConfiguration:
    # Flink Autoscaler 활성화
    job.autoscaler.enabled: "true"
    job.autoscaler.scaling.enabled: "true"
    job.autoscaler.target.utilization: "0.7"
    job.autoscaler.stabilization.interval: "5m"

VPA와의 관계:

  • Flink Autoscaler는 Task parallelism 조정
  • VPA는 TaskManager/JobManager Pod 리소스 조정 가능
  • 두 시스템 간 충돌 방지를 위해 VPA는 Off 모드 권장

11.3 Spark Operator

apiVersion: sparkoperator.k8s.io/v1beta2
kind: SparkApplication
metadata:
  name: spark-job
spec:
  driver:
    cores: 1
    memory: "1g"
  executor:
    cores: 2
    instances: 3
    memory: "2g"
  dynamicAllocation:
    enabled: true
    initialExecutors: 2
    minExecutors: 1
    maxExecutors: 10

참고: Spark의 Dynamic Allocation은 VPA와 별개로 동작하며, VPA 적용 시 충돌 가능


12. Batch/CronJob 워크로드

12.1 CronJob에서 VPA 활용

제한사항:

  • CronJob은 주기적으로 새 Pod 생성
  • VPA는 8일간의 히스토리 데이터 필요
  • 짧은 실행 시간의 Job은 데이터 수집 어려움

권장 접근법:

# CronJob - VPA Initial 모드로 초기 리소스만 설정
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: batch-job-vpa
spec:
  targetRef:
    apiVersion: "batch/v1"
    kind: CronJob
    name: daily-report
  updatePolicy:
    updateMode: "Initial"  # 새 Job 생성 시에만 적용

11.2 장기 실행 Batch Job

# 장기 실행 Job - Off 모드로 모니터링 후 수동 적용
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: long-running-job-vpa
spec:
  targetRef:
    apiVersion: "batch/v1"
    kind: Job
    name: data-migration
  updatePolicy:
    updateMode: "Off"

13. 고객 사전 점검 체크리스트

13.1 환경 정보 수집

인프라 정보

  • Kubernetes 버전: ________________
  • 클라우드 제공자: ________________ (EKS/GKE/AKS/On-Premise)
  • 노드 수: ________________
  • 노드 타입/크기: ________________

기존 Autoscaling 설정

  • HPA 사용 여부: Yes / No
  • VPA 사용 여부: Yes / No
  • Cluster Autoscaler 사용 여부: Yes / No
  • KEDA 사용 여부: Yes / No

GitOps 도구

  • ArgoCD 사용: Yes / No
    • Auto-Sync 활성화: Yes / No
    • Self-Heal 활성화: Yes / No
  • FluxCD 사용: Yes / No
  • 기타: ________________

13.2 워크로드 점검

Stateful 워크로드

워크로드 이름 유형 Namespace 현재 리소스 VPA 적용 가능

데이터베이스 워크로드

DB 종류 Operator 사용 StatefulSet 이름 권장 모드

Kafka 관련 워크로드

  • Kafka Broker:
    • Operator: Strimzi / Confluent / Bitnami / 기타
    • 브로커 수: ________________
  • Kafka Consumer:
    • Static Membership 설정: Yes / No
    • Consumer Group 수: ________________

JVM 애플리케이션

애플리케이션 JVM 버전 GC 종류 Heap 설정

13.3 연동 솔루션 점검

Service Mesh

  • Istio 사용: Yes / No
    • mTLS 모드: STRICT / PERMISSIVE
    • Sidecar 리소스 설정: Yes / No
  • Linkerd 사용: Yes / No
  • 기타: ________________

모니터링

  • Prometheus 사용: Yes / No
  • Datadog 사용: Yes / No
  • 기타: ________________

14. 권장 설정 템플릿

13.1 Namespace 레벨 기본 설정

# 일반 워크로드용 기본 VPA 설정
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: default-vpa
  namespace: my-namespace
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: my-deployment
  updatePolicy:
    updateMode: "Auto"  # Stateless 워크로드용
  resourcePolicy:
    containerPolicies:
    - containerName: '*'
      minAllowed:
        cpu: 50m
        memory: 64Mi
      maxAllowed:
        cpu: 4
        memory: 8Gi
      controlledValues: RequestsAndLimits

14.2 제외 워크로드 레이블 기반 관리

# 제외할 워크로드에 레이블 추가
metadata:
  labels:
    skuber.io/vpa-exclude: "true"  # VPA 적용 제외

14.3 ArgoCD + Skuber+ 통합 설정

# argocd-cm ConfigMap에 추가
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  # Skuber+ 호환을 위한 전역 설정
  resource.customizations.ignoreDifferences.apps_Deployment: |
    jqPathExpressions:
    - .spec.template.spec.containers[].resources
  resource.customizations.ignoreDifferences.apps_StatefulSet: |
    jqPathExpressions:
    - .spec.template.spec.containers[].resources
  resource.customizations.ignoreDifferences.apps_DaemonSet: |
    jqPathExpressions:
    - .spec.template.spec.containers[].resources

14.4 KEDA + VPA 공존 설정

VPA와 KEDA/HPA가 동일한 메트릭을 관리하면 충돌이 발생합니다. 메트릭을 분리하여 공존해야 합니다.

메트릭 분리 원칙:

  • VPA: Memory 수직 스케일링
  • KEDA/HPA: CPU 또는 Custom Metric 기반 수평 스케일링
# VPA - Memory만 관리
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-app-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: my-app
  updatePolicy:
    updateMode: "Auto"
  resourcePolicy:
    containerPolicies:
    - containerName: my-app
      controlledResources: ["memory"]  # CPU는 제외 (KEDA가 관리)
---
# KEDA - CPU/Custom Metric 기반 HPA
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: my-app-keda
spec:
  scaleTargetRef:
    name: my-app
  triggers:
  - type: cpu
    metricType: Utilization
    metadata:
      value: "70"

부록: 리스크 매트릭스

전체 리스크 요약

카테고리 항목 발생 확률 영향도 완화 방안
OOM 방지 추천값 부족으로 인한 Crash 중간 높음 기본 30% 마진 적용
OOM 방지 반복 OOM 발생 낮음 높음 Bump-up 메커니즘 (50%→100%→200%)
OOM 방지 Bump-up 실패 후 서비스 불안정 매우 낮음 치명적 4차 시 자동 롤백
StatefulSet Pod 순서 무시 재시작 높음 높음 Off/Initial 모드
Database Primary 노드 재시작 중간 치명적 VPA 제외 또는 Off
Kafka Broker Partition Under-replicated 높음 치명적 반드시 제외
Kafka Consumer Rebalancing Storm 중간 높음 Static Membership
JVM 잘못된 메모리 추천 높음 높음 CPU만 VPA 적용 + 50% 마진
GPU 리소스 낭비 낮음 중간 Kueue/Volcano 사용
ArgoCD Sync Loop 높음 높음 ignoreDifferences
HPA+VPA 충돌 높음 높음 메트릭 분리
Service Mesh Sidecar 리소스 누락 중간 중간 명시적 리소스 설정

OOM 방지 효과 지표

지표 설명 목표값
OOM 발생률 감소 Skuber+ 적용 전후 OOM Kill 비율 90% 이상 감소
1차 Bump-up 해결률 1차 Bump-up으로 안정화되는 비율 80% 이상
롤백 발생률 4차까지 도달하여 롤백되는 비율 5% 미만
평균 안정화 시간 Bump-up 후 안정화까지 소요 시간 24시간 이내

참고 문서


문서 작성: Skuber+ Technical Team