Notice
Recent Posts
Recent Comments
Link
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
Archives
Today
Total
관리 메뉴

근묵자흑

Kubernetes Patterns : Elastic Scale 본문

k8s/kubernetes-pattern

Kubernetes Patterns : Elastic Scale

Luuuuu 2026. 2. 21. 21:34

 

Kubernetes는 선언적으로 정의된 원하는 상태(Desired State)를 유지하는 것에 그치지 않습니다. 워크로드의 부하 변화에 따라 Pod 수를 늘리거나, Pod의 리소스를 조정하거나, 클러스터 노드 자체를 확장하는 탄력적 스케일링(Elastic Scale) 을 제공합니다.

 

이 패턴을 통해 쿠버네티스는 외부 부하에 대응하여 스스로 강해지는 안티프래질(Antifragile) 시스템의 특성을 갖게 됩니다.

 

이 글에서는 책의 내용을 기반으로 수평 스케일링(HPA), 수직 스케일링(VPA), 클러스터 스케일링(CA)을 정리하고, In-Place Pod Resize, Karpenter, KEDA 등을 함께 다룹니다.

 

또한 minikube 환경에서 HPA의 동작을 직접 검증한 결과를 포함합니다.


1. 스케일링의 문제 정의

많은 워크로드는 시간에 따라 부하가 변합니다. 출퇴근 시간대, 주말, 이벤트 기간 등에 따라 서비스에 필요한 리소스가 달라집니다. 이러한 상황에서 고정된 설정으로는 다음과 같은 문제가 발생합니다.

  • 과잉 프로비저닝(Over-provisioning): 피크 부하를 기준으로 리소스를 할당하면, 평상시 대부분의 시간 동안 비용을 낭비하게 됩니다.
  • 과소 프로비저닝(Under-provisioning): 비용을 아끼기 위해 리소스를 줄이면, 트래픽 증가 시 서비스 장애로 이어집니다.
  • 수동 조정의 한계: 운영자가 직접 리소스를 조정하는 방식은 변화 속도를 따라갈 수 없으며, 대규모 시스템에서는 현실적으로 불가능합니다.

Kubernetes는 이러한 문제를 여러 차원의 자동 스케일링으로 해결합니다.


2. 스케일링 레벨 전체 구조

Elastic Scale 패턴에서 다루는 스케일링은 다음과 같이 세분화됩니다. 가장 세밀한 단위부터 넓은 단위 순서로 정리합니다.

graph TD
    A["Application Tuning<br/>(애플리케이션 레벨)"] --> B["Vertical Pod Autoscaling<br/>(Pod 리소스 조정)"]
    B --> C["Horizontal Pod Autoscaling<br/>(Pod 수 조정)"]
    C --> D["Cluster Autoscaling<br/>(노드 수 조정)"]

    style A fill:#e8f5e9,stroke:#2e7d32,color:#000
    style B fill:#e3f2fd,stroke:#1565c0,color:#000
    style C fill:#fff3e0,stroke:#e65100,color:#000
    style D fill:#fce4ec,stroke:#c62828,color:#000
레벨 대상 도구 설명
Application Tuning 컨테이너 내부 앱 자체 설정 스레드 풀, 커넥션 풀 등 앱 레벨 최적화
Vertical Scaling Pod 리소스 VPA CPU/Memory requests·limits 조정
Horizontal Scaling Pod 수 HPA, Knative, KEDA 레플리카 수 증감
Cluster Scaling Node 수 CA, Karpenter 클러스터 노드 추가·제거

3. 수동 수평 스케일링 (Manual Horizontal Scaling)

자동 스케일링을 설정하기 전에, 기본적인 수동 스케일링 방법을 이해하는 것이 중요합니다.

3.1 명령형(Imperative) 스케일링

kubectl scale deployment random-generator --replicas=4

간단하고 즉각적이지만, 이 변경은 클러스터 내부에서만 유효하며 소스 코드 관리 시스템에 반영되지 않습니다. 원본 매니페스트를 다시 적용하면 이전 값으로 되돌아갑니다.

3.2 선언형(Declarative) 스케일링

kubectl apply -f random-generator-deployment.yaml

매니페스트 파일에서 .spec.replicas 값을 변경하고 적용하는 방식입니다. GitOps 워크플로와 호환되며, 설정 드리프트(Configuration Drift)를 방지할 수 있습니다. 프로덕션 환경에서는 이 방식을 권장합니다.

참고: StatefulSet의 스케일링은 비대칭적 특성을 가집니다. .spec.volumeClaimTemplates이 정의된 경우, 스케일업 시 PVC를 생성하지만, 스케일다운 시에는 저장소 보호를 위해 PVC를 삭제하지 않습니다.


4. Horizontal Pod Autoscaler (HPA)

HPA는 쿠버네티스에 기본 내장된 수평 오토스케일링 메커니즘입니다. 별도의 설치 없이 사용할 수 있으며, 메트릭 기반으로 Pod 레플리카 수를 자동 조정합니다.

4.1 HPA 기본 동작 원리

flowchart LR
    A["Metrics Server<br/>(메트릭 수집)"] --> B["HPA Controller<br/>(15초 주기 확인)"]
    B --> C{"현재 메트릭 vs<br/>목표 메트릭"}
    C -->|"메트릭 초과"| D["Scale Up<br/>(레플리카 증가)"]
    C -->|"메트릭 미달"| E["Scale Down<br/>(레플리카 감소)"]
    C -->|"허용 범위 내"| F["유지"]
    D --> G["Deployment /<br/>ReplicaSet"]
    E --> G
    F --> G

HPA의 스케일링 공식은 다음과 같습니다.

desiredReplicas = ceil[currentReplicas × (currentMetricValue / desiredMetricValue)]

 

예를 들어, 현재 2개의 Pod가 CPU 사용률 80%이고 목표가 50%라면, ceil[2 × (80/50)] = ceil[3.2] = 4개의 Pod가 필요하다고 판단합니다.

 

실제 테스트에서도 이 공식의 동작을 확인할 수 있었습니다. 1개 Pod가 CPU 250%를 기록했을 때, ceil[1 × (250/50)] = ceil[5] = 5에 따라 먼저 4개로 스케일업한 뒤 재평가를 거쳐 5개로 증가하는 과정을 관찰했습니다. 

4.2 HPA 정의 예시

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: random-generator
spec:
  minReplicas: 1       # 최소 Pod 수
  maxReplicas: 5       # 최대 Pod 수
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: random-generator
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50  # CPU requests 대비 평균 사용률 50% 유지

CLI로도 동일하게 생성할 수 있습니다.

kubectl autoscale deployment random-generator --cpu-percent=50 --min=1 --max=5

주의사항: HPA가 동작하려면 반드시 대상 Deployment의 Pod에 .spec.resources.requests가 정의되어 있어야 하며, 클러스터에 Metrics Server가 설치되어 있어야 합니다. minikube에서는 minikube addons enable metrics-server로 활성화하고, 활성화 후 약 45초간 안정화 시간이 필요합니다.

4.3 메트릭 유형

HPA에서 사용할 수 있는 메트릭 유형은 세 가지입니다.

유형 type 값 설명 제공자
표준 메트릭 Resource CPU, Memory 등 기본 리소스 Metrics Server
커스텀 메트릭 Object, Pod Pod 또는 Object 관련 사용자 정의 메트릭 Prometheus Adapter, Datadog 등
외부 메트릭 External 클러스터 외부 시스템의 메트릭 (예: 큐 깊이) 외부 메트릭 플러그인, KEDA

4.4 스케일링 동작 세부 제어 (behavior)

HPA의 .spec.behavior 필드를 사용하면 스케일업·스케일다운의 속도와 안정성을 세밀하게 제어할 수 있습니다.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: random-generator-with-behavior
spec:
  minReplicas: 1
  maxReplicas: 10
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: random-generator
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 0       # 스케일업은 즉시 반응
      policies:
      - type: Percent
        value: 100           # 현재 레플리카의 100%까지 한번에 증가 가능
        periodSeconds: 15
    scaleDown:
      stabilizationWindowSeconds: 300     # 5분간 안정화 기간 (Flapping 방지)
      policies:
      - type: Percent
        value: 10            # 60초마다 현재 레플리카의 최대 10%만 감소
        periodSeconds: 60

이 설정이 구현하는 비대칭 스케일링 패턴은 프로덕션 환경에서 가장 일반적으로 권장되는 방식입니다.

  • 스케일업: stabilizationWindowSeconds: 0으로 즉시 반응합니다. 부하 급증 시 서비스 품질 저하를 최소화합니다.
  • 스케일다운: stabilizationWindowSeconds: 300으로 5분간 안정화 기간을 둡니다. 부하가 간헐적으로 변동할 때 반복적인 축소·확장(Flapping/Thrashing)을 방지합니다.

4.5 HPA 튜닝 시 고려사항

HPA를 설정할 때 다음 사항들을 주의 깊게 고려해야 합니다.

메트릭 선택: HPA의 성패를 결정하는 가장 중요한 요소입니다. 선택한 메트릭이 레플리카 수와 직접적 상관관계를 가져야 합니다. 예를 들어 HTTP RPS를 메트릭으로 사용하면, Pod를 추가할수록 Pod당 평균 RPS가 줄어들어 원하는 동작을 합니다.

스케일링 지연: 실제 테스트에서 측정한 HPA 반응 시간을 정리하면 다음과 같습니다.

메트릭 수집 시작:  ~25~30초 (Pod Ready 후)
스케일업 판단:     ~15초 (HPA 체크 주기)
Pod 생성·시작:     ~10~15초
────────────────────────────────
총 스케일업 지연:  약 50~100초

이 지연을 고려하여, 갑작스러운 트래픽 급증에 대비하려면 minReplicas를 적절히 설정하거나 Knative/KEDA 같은 Push 기반 솔루션을 함께 사용하는 것이 좋습니다.

HPA와 Deployment 관계: HPA는 반드시 Deployment에 적용해야 합니다. ReplicaSet에 직접 적용하면, 롤링 업데이트 시 새 ReplicaSet으로 HPA가 복사되지 않아 유실됩니다.

4.6 Kubernetes v1.35: HPA Configurable Tolerance (최신)

Kubernetes v1.35에서 HPA Configurable Tolerance 기능이 Beta로 승격되어 기본 활성화되었습니다.

기존에는 전역적으로 고정된 10% 허용 오차(tolerance)가 적용되어, 메트릭 변화가 10% 이내이면 스케일링이 트리거되지 않았습니다. 이는 실제 테스트에서도 확인할 수 있었는데, CPU 사용률이 51%로 목표(50%) 대비 10% 이내였을 때 HPA가 스케일업을 트리거하지 않았습니다. 이제 Kubernetes v1.35부터는 HPA별로 스케일업과 스케일다운에 각각 다른 tolerance 값을 설정할 수 있게 되었습니다. 예를 들어 5% 부하 증가에도 민감하게 반응해야 하는 워크로드에 tolerance를 0.05로 설정할 수 있습니다.


5. Scale-to-Zero 솔루션: Knative와 KEDA

HPA의 중요한 한계는 최소 1개의 Pod를 유지해야 한다는 점입니다. 아무도 사용하지 않는 서비스에도 리소스가 소비됩니다. Knative와 KEDA는 이 한계를 보완하는 대표적인 Scale-to-Zero 솔루션입니다.

5.1 Knative

Knative는 HTTP 기반 트래픽에 특화된 서버리스 오토스케일링 플랫폼입니다. 자체 Knative Pod Autoscaler (KPA) 를 통해 HPA보다 정교한 스케일링 알고리즘을 제공합니다.

flowchart LR
    subgraph "Knative Autoscaling Architecture"
        A["Client Request"] --> B["Activator<br/>(프록시/버퍼)"]
        B --> C["Queue Proxy<br/>(사이드카)"]
        C --> D["Application Pod"]
        C -->|"동시 요청 메트릭"| E["Autoscaler"]
        B -->|"메트릭 Push"| E
        E -->|"레플리카 수 조정"| F["ReplicaSet"]
    end

핵심 컴포넌트:

  • Activator: 항상 동작하는 프록시로, Pod가 0개일 때 들어오는 요청을 버퍼링하고 스케일업을 트리거합니다. Cold start 중 요청 유실을 방지합니다.
  • Queue Proxy: 각 Pod에 사이드카로 주입되어, 동시 요청 수 등 오토스케일링에 필요한 메트릭을 수집합니다.
  • Autoscaler: Activator와 Queue Proxy로부터 받은 메트릭을 기반으로 스케일링 결정을 내립니다.

Knative Service 예시:

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: random
  annotations:
    autoscaling.knative.dev/target: "80"         # 동시 요청 수 목표
    autoscaling.knative.dev/window: "120s"       # 메트릭 평균 계산 윈도우
    autoscaling.knative.dev/min-scale: "0"       # 최소 0까지 축소
    autoscaling.knative.dev/max-scale: "10"      # 최대 10까지 확장
    autoscaling.knative.dev/scale-down-delay: "30s"  # 축소 전 대기
spec:
  template:
    spec:
      containers:
      - image: k8spatterns/random
주요 파라미터 설명 기본값
target 레플리카당 처리 가능한 동시 요청 수 (소프트 리밋) 100
target-utilization-percentage 이 비율에 도달하면 새 레플리카 생성 시작 70
min-scale 최소 레플리카 수 (0이면 Scale-to-Zero) 0
max-scale 최대 레플리카 수 (0은 무제한) 0
scale-down-delay 축소 조건 유지 기간 (Cold Start 회피용) 0s
window 메트릭 평균 계산 시간 윈도우 60s

5.2 KEDA (Kubernetes Event-Driven Autoscaling)

KEDA는 외부 이벤트 소스 기반 오토스케일링 플랫폼입니다. Knative가 HTTP 트래픽에 특화되어 있다면, KEDA는 Kafka, RabbitMQ, AWS SQS 등 다양한 외부 시스템의 메트릭을 기반으로 스케일링합니다.

flowchart TD
    subgraph "KEDA Architecture"
        A["External System<br/>(Kafka, SQS, Redis 등)"] -->|"메트릭 Pull"| B["KEDA Operator"]
        B -->|"0↔1 활성화"| C["Workload<br/>(Deployment)"]
        B -->|"ScaledObject 감지"| D["HPA 자동 생성"]
        D -->|"1↔N 스케일링"| C
        E["KEDA Metrics Service"] -->|"외부 메트릭 제공"| D
        A -->|"메트릭"| E
    end

KEDA의 2단계 스케일링:

  • 0↔1 (Activation): KEDA Operator가 직접 수행합니다. 외부 스케일러의 메트릭이 임계값을 초과하면 레플리카를 0에서 1로 확장합니다.
  • 1↔N (Scaling): HPA가 담당합니다. KEDA가 자동 생성한 HPA가 외부 메트릭을 기반으로 레플리카 수를 조정합니다.

ScaledObject 예시 (Kafka 기반 스케일링):

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: kafka-scaledobject
spec:
  scaleTargetRef:
    name: kafka-consumer              # 스케일링 대상 Deployment
  pollingInterval: 30                  # 30초 간격으로 메트릭 폴링
  triggers:
  - type: kafka                        # Apache Kafka 스케일러
    metadata:
      bootstrapServers: bootstrap.kafka.svc:9092
      consumerGroup: my-group
      topic: my-topic

KEDA는 60개 이상의 내장 스케일러를 제공하며, gRPC 기반 API를 통해 커스텀 스케일러를 쉽게 통합할 수 있습니다. 또한 ScaledJob 리소스를 통해 외부 이벤트에 따라 Kubernetes Job을 자동 생성하는 것도 가능합니다.

5.3 Push vs Pull 오토스케일러

구분 HPA Knative KEDA
스케일 메트릭 리소스 사용량 HTTP 요청(동시 요청) 외부 메트릭 (큐 깊이 등)
Scale-to-Zero 불가 가능 가능
방식 Pull Push Pull
적합한 사용 사례 안정적 트래픽의 웹 앱, 배치 처리 서버리스 앱, 서버리스 함수 메시지 드리븐 마이크로서비스

Knative와 KEDA는 대체 관계가 아니라 보완 관계입니다. Knative는 HTTP 기반 워크로드, KEDA는 이벤트/큐 기반 워크로드에 적합하며, 두 솔루션을 함께 사용하는 것이 가능합니다.


6. Vertical Pod Autoscaler (VPA)

수직 스케일링은 Pod의 수를 늘리는 것이 아니라, 개별 Pod에 할당된 CPU와 Memory의 requests/limits를 조정하는 방식입니다. Stateful 서비스나 리소스 튜닝이 필요한 경우에 유용합니다.

6.1 VPA 컴포넌트

VPA는 세 가지 컴포넌트로 구성됩니다.

flowchart LR
    A["VPA Recommender<br/>(메트릭 분석 → 추천)"] --> B["VPA Updater<br/>(Pod 재생성 트리거)"]
    A --> C["VPA Admission Controller<br/>(새 Pod에 추천값 적용)"]
    B -->|"Pod 퇴거"| D["Pod"]
    C -->|"리소스 Mutate"| E["새 Pod"]
  • Recommender: 리소스 사용 이력을 분석하여 최적의 CPU/Memory 값을 추천합니다.
  • Updater: 현재 Pod의 리소스 설정과 추천 값을 비교하여, 차이가 크면 Pod를 퇴거(Evict)시킵니다.
  • Admission Controller: 새로 생성되는 Pod에 추천 리소스 값을 주입하는 Mutating Webhook입니다.

6.2 VPA Update 모드

모드 동작 중단 여부
Off 추천만 제공, 적용하지 않음 없음
Initial 새로 생성되는 Pod에만 추천값 적용 부분적
Recreate Pod를 강제 퇴거 후 재생성하여 적용 있음
Auto 향후 In-Place 업데이트 지원 예정 (현재는 Recreate와 동일) 있음

6.3 VPA 설정 예시

프로덕션 초기 도입 시에는 Off 모드가 권장됩니다. Off 모드에서는 VPA가 추천값만 제공하고, 실제 리소스 변경은 수행하지 않으므로 기존 서비스에 영향 없이 적정 리소스 수준을 파악할 수 있습니다.

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: random-generator
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: random-generator
  updatePolicy:
    updateMode: "Off"        # 추천만 제공, 자동 적용하지 않음
  resourcePolicy:
    containerPolicies:
    - containerName: random-generator
      minAllowed:
        cpu: "100m"
        memory: "128Mi"
      maxAllowed:
        cpu: "2"
        memory: "4Gi"

추천값은 다음 명령으로 확인할 수 있습니다.

kubectl describe vpa random-generator
# Status → Recommendation → Container Recommendations 섹션에서
# Lower Bound, Target, Uncapped Target, Upper Bound 값 확인

6.4 VPA 사용 시 주의사항

  • HPA와의 충돌: VPA와 HPA가 동일한 메트릭(CPU, Memory)을 기반으로 동작하면, 이중 스케일링이 발생할 수 있습니다. VPA를 Off 모드로 사용하거나, HPA는 커스텀 메트릭을 사용하도록 분리하면 충돌을 방지할 수 있습니다.
  • Pod 재생성의 부작용: Recreate/Auto 모드에서는 Pod가 퇴거 후 재생성되므로, 스케줄링 위치가 달라질 수 있고, 노드 용량이 부족하면 Pod가 Pending 상태에 빠질 수 있습니다.
  • Immutable Pod Spec 설계와의 충돌: Kubernetes의 Pod spec은 기본적으로 불변(Immutable)으로 설계되어 있어, VPA가 리소스를 변경하려면 Pod를 삭제하고 재생성해야 했습니다. 이는 오랫동안 VPA의 프로덕션 활용을 제한하는 주요 원인이었습니다.

7. In-Place Pod Resize (최신 — Kubernetes v1.35 GA)

쿠버네티스 커뮤니티에서 6년 이상 개발된 In-Place Pod Resize (KEP-1287) 기능이 v1.27에서 Alpha, v1.33에서 Beta, 그리고 v1.35(2025년 12월)에서 GA(Stable) 로 졸업했습니다. 이는 앞서 설명한 VPA의 Pod 재생성 한계를 근본적으로 해결하는 기능입니다.

7.1 핵심 변화

기존에는 Pod의 CPU/Memory requests와 limits를 변경하려면 반드시 Pod를 삭제하고 재생성해야 했습니다. In-Place Pod Resize를 통해 실행 중인 Pod의 리소스를 재시작 없이 변경할 수 있게 되었습니다.

flowchart LR
    subgraph "기존 방식 (Recreate)"
        A1["리소스 변경 요청"] --> B1["Pod 삭제"]
        B1 --> C1["새 Pod 생성<br/>(변경된 리소스)"]
        C1 --> D1["스케줄링 → 시작"]
    end

    subgraph "In-Place Resize (v1.35 GA)"
        A2["리소스 변경 요청"] --> B2["Kubelet이<br/>cgroup 직접 업데이트"]
        B2 --> C2["Pod 계속 실행<br/>(무중단)"]
    end

7.2 사용 방법

/resize 서브리소스를 통해 Pod의 리소스를 변경할 수 있습니다.

# kubectl 1.32 이상에서 사용 가능
kubectl patch pod my-pod --subresource resize --patch \
  '{"spec":{"containers":[{"name":"app","resources":{"requests":{"cpu":"500m","memory":"512Mi"},"limits":{"cpu":"1","memory":"1Gi"}}}]}}'

리사이즈 상태는 Pod의 conditions에서 확인할 수 있습니다.

kubectl get pod my-pod -o jsonpath='{.status.conditions}' | jq
  • PodResizePending: 리사이즈 요청이 아직 처리되지 않은 상태
    • reason: Infeasible — 현재 노드에서 요청한 리소스를 충족할 수 없음
    • reason: Deferred — 현재는 불가하지만 향후 가능할 수 있음
  • PodResizeInProgress: 리사이즈가 진행 중

7.3 v1.35 GA에서 추가된 개선사항

  • Memory Limit 감소 허용: 이전에는 메모리 리밋 감소가 금지되었지만, v1.35에서 허용되었습니다. Kubelet이 현재 메모리 사용량이 새로운 리밋 이하인지 best-effort로 확인한 후 리사이즈를 수행합니다.
  • 우선순위 기반 리사이즈: 노드에 여러 리사이즈 요청이 대기 중일 때, Deferred 상태가 오래된 요청을 우선 처리합니다.
  • VPA InPlaceOrRecreate 모드: VPA v1.4+에서 InPlaceOrRecreate 모드가 지원되어, 가능하면 In-Place로, 불가능하면 Recreate로 폴백합니다. GKE에서는 Public Preview로 제공되고 있습니다.

7.4 제한사항

  • Linux 전용 (Windows 미지원)
  • Static CPU/Memory Manager를 사용하는 Pod는 제외
  • Pod의 QoS 클래스(Guaranteed / Burstable / BestEffort)는 생성 시 결정되며 리사이즈로 변경 불가
  • containerd v1.6+ 또는 CRI-O v1.24+ 필요

7.5 향후 로드맵

In-Place Pod Resize GA를 기반으로 다음과 같은 통합이 진행 중입니다.

  • VPA CPU Startup Boost: 앱 시작 시 높은 CPU를 할당하고 이후 자동으로 낮추는 기능
  • VPA InPlace 모드: InPlaceOrRecreate를 넘어, 순수 In-Place 전용 모드 개발 중
  • 워크로드 선점(Preemption): 고우선순위 Pod의 리사이즈를 위해 저우선순위 Pod를 자동 퇴거하는 정책 개발 중

8. Cluster Autoscaler (CA)

Pod 레벨 스케일링이 충분하지 않을 때, 클러스터 자체의 노드 수를 조정하는 것이 Cluster Autoscaler입니다. 클라우드 환경에서 Pay-as-you-go 모델에 맞춰 인프라 비용을 최적화할 수 있습니다.

8.1 CA 동작 원리

flowchart TD
    subgraph "Scale Up"
        A1["Pod Pending<br/>(스케줄링 불가)"] --> B1["CA가 시뮬레이션<br/>(어떤 노드 그룹에<br/>노드 추가 시 해결?)"]
        B1 --> C1["Cloud Provider API<br/>새 노드 요청"]
        C1 --> D1["새 노드 Ready<br/>→ Pod 스케줄링"]
    end

    subgraph "Scale Down"
        A2["노드 용량 50% 이상<br/>미사용 감지"] --> B2["이동 가능한 Pod를<br/>다른 노드에 배치<br/>시뮬레이션"]
        B2 --> C2["10분간 조건 유지"]
        C2 --> D2["노드를<br/>Unschedulable 설정<br/>→ Pod 이동<br/>→ 노드 삭제"]
    end

스케일다운 조건:

  • 노드 용량의 50% 이상이 미사용 상태 (모든 Pod의 CPU/Memory requests 합계 기준)
  • 해당 노드의 모든 이동 가능한 Pod가 다른 노드에 배치될 수 있어야 합니다
  • PodDisruptionBudget을 만족할 수 없는 Pod가 없어야 합니다
  • 로컬 스토리지를 사용하는 Pod, 퇴거 방지 annotation이 있는 Pod가 없어야 합니다
  • 위 조건이 기본 10분간 지속되어야 합니다

8.2 Cluster API

기존에는 각 클라우드 프로바이더별로 CA 플러그인이 별도로 작성되어 있어 일관성이 부족했습니다. Cluster API 프로젝트는 클러스터 생성·설정·관리를 위한 표준 API를 제공하며, AWS, Azure, GCE, vSphere, OpenStack 등 주요 클라우드를 지원합니다. 이를 통해 on-premises 환경에서도 CA를 활용할 수 있는 길이 열렸습니다.


9. Karpenter — 차세대 노드 오토스케일러 (최신)

Karpenter는 AWS에서 시작되어 CNCF에 기증된 오픈소스 프로젝트로, 기존 Cluster Autoscaler의 한계를 극복하기 위해 설계된 차세대 노드 오토스케일러입니다.

9.1 CA vs Karpenter 비교

항목 Cluster Autoscaler Karpenter
노드 그룹 사전 정의된 노드 그룹(ASG) 필수 노드 그룹 불필요, Pod 요구사항 기반 동적 프로비저닝
인스턴스 선택 노드 그룹 내 동일 타입 Pod 요구사항에 맞는 최적 인스턴스 자동 선택
스케일업 속도 3~4분 (ASG 스핀업 시간 포함) 약 55초
비용 최적화 제한적 Spot 인스턴스, 다중 아키텍처(ARM/x86), 능동적 통합(Consolidation)
통합(Consolidation) 유휴 노드만 제거 미활용 노드를 적극적으로 감지하여 Pod 이동 후 노드 제거
멀티클라우드 모든 주요 클라우드 지원 AWS 중심이며 다른 클라우드 프로바이더도 확장 중

Karpenter가 빠른 이유는 구조적 차이에 있습니다. CA는 "노드 그룹 → ASG → EC2 인스턴스"라는 간접 경로를 거치지만, Karpenter는 unschedulable Pod를 감지하면 즉시 최적의 EC2 인스턴스를 직접 프로비저닝합니다.

9.2 Karpenter NodePool 예시

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: default
spec:
  template:
    spec:
      requirements:
      - key: kubernetes.io/arch
        operator: In
        values: ["amd64", "arm64"]        # 멀티 아키텍처 지원
      - key: karpenter.sh/capacity-type
        operator: In
        values: ["spot", "on-demand"]      # Spot 인스턴스 활용
      - key: karpenter.k8s.aws/instance-category
        operator: In
        values: ["c", "m", "r"]
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: default
      expireAfter: 720h                    # 30일 후 노드 교체
  limits:
    cpu: 1000                              # 총 CPU 제한
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 1m                   # 1분 미활용 시 통합

9.3 Karpenter 적용이 효과적인 경우

  • 트래픽 급증이 빈번한 웹 서비스 (빠른 스케일업이 필요한 경우)
  • 다양한 인스턴스 타입이 필요한 워크로드 (GPU, ARM, Spot 혼합)
  • 비용 최적화가 중요한 환경 (능동적 Consolidation 기능 활용)
  • EKS 기반 환경 (AWS EKS Auto Mode와 기본 통합)

참고: GPU 기반 ML 워크로드처럼 GPU 노드를 warm하게 유지해야 하는 경우에는, Karpenter가 유휴 GPU 인스턴스를 적극적으로 종료할 수 있으므로 CA의 명시적 노드 그룹 예약 방식이 더 적합할 수 있습니다.


10. 실습: HPA를 활용한 수평 오토스케일링

10.1 사전 준비

# minikube 시작 (4GB 메모리 권장)
minikube start --memory=4096
minikube addons enable metrics-server

# Metrics Server 동작 확인 (활성화 후 약 45초 대기 필요)
kubectl top nodes

10.2 테스트 매니페스트

부하 테스트에 최적화된 registry.k8s.io/hpa-example 이미지를 사용합니다. 이 이미지는 HTTP 요청을 받으면 CPU 집약적인 연산을 수행하여 HPA 테스트에 적합합니다. Deployment, Service, HPA를 하나의 파일로 관리합니다.

# stress-app.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: stress-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: stress-app
  template:
    metadata:
      labels:
        app: stress-app
    spec:
      containers:
      - name: stress
        image: registry.k8s.io/hpa-example
        resources:
          requests:
            cpu: "200m"        # HPA 동작의 기준점
          limits:
            cpu: "500m"
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: stress-app
spec:
  selector:
    app: stress-app
  ports:
  - port: 80
    targetPort: 80
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: stress-app
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: stress-app
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50
kubectl apply -f stress-app.yml

10.3 부하 생성 및 모니터링

터미널 1 — HPA 상태 모니터링:

kubectl get hpa stress-app --watch

터미널 2 — 부하 생성:

kubectl run load-generator --image=busybox:1.36 --restart=Never -- \
  /bin/sh -c "while true; do wget -q -O- http://stress-app; done"

10.4 실제 테스트 결과

minikube 환경에서 수행한 테스트 결과입니다.

스케일업 과정:

시간(초)  레플리카  CPU 사용률  이벤트
──────── ──────── ────────── ────────────────────────
0        1        <unknown>   HPA 메트릭 수집 대기
~30      1        51%         첫 메트릭 수집, 목표 근접
~60      1        51%         HPA 허용 오차(10%) 내 — 유지
~90      1        250%        부하 누적으로 CPU 급등
~105     4        250%        HPA 스케일업: 1 → 4
~120     5        250%        HPA 스케일업: 4 → 5

이 결과에서 주목할 포인트가 두 가지 있습니다.

 

첫째, CPU 51% 시점에서 HPA가 스케일업을 트리거하지 않았습니다. 목표가 50%이므로 초과한 상태이지만, HPA의 기본 허용 오차(tolerance) 10% 이내이기 때문입니다. (51 - 50) / 50 = 2%로, 10% 미만이므로 일시적 변동으로 간주하고 유지했습니다. 이 동작은 앞서 4.6절에서 설명한 Configurable Tolerance 기능과 직접 연관됩니다.

 

둘째, CPU 250%에 도달했을 때 HPA 공식이 정확히 동작했습니다. ceil[1 × (250/50)] = 5이므로 5개의 레플리카가 필요합니다. HPA는 한 번에 5개까지 바로 올리지 않고, 먼저 4개로 스케일업한 후 재평가하여 5개로 조정했습니다.

 

HPA 이벤트 로그:

Normal  SuccessfulRescale  New size: 4; reason: cpu resource utilization
                           (percentage of request) above target
Normal  SuccessfulRescale  New size: 5; reason: cpu resource utilization
                           (percentage of request) above target

스케일다운 과정:

# 부하 생성기 제거
kubectl delete pod load-generator
시간(초)  레플리카  CPU 사용률  이벤트
──────── ──────── ────────── ────────────────────────
0        5        250%        부하 생성기 제거
~20      5        122%        부하 감소 시작
~80      5        0%          CPU 사용률 정상화
~380     ↓        0%          5분 안정화 기간 후 스케일다운 시작

스케일다운은 기본 stabilizationWindowSeconds: 300 (5분) 이후에 시작됩니다. 이는 부하가 간헐적으로 변동할 때 불필요한 축소·확장 반복(Flapping)을 방지하기 위한 설계입니다.

flowchart LR
    subgraph "스케일업 (부하 증가)"
        A1["1 Pod<br/>CPU: 51%"] -->|"부하 누적"| B1["1 Pod<br/>CPU: 250%"]
        B1 -->|"HPA 스케일업"| C1["4 Pods"]
        C1 -->|"재평가"| D1["5 Pods"]
    end

    subgraph "스케일다운 (부하 제거)"
        A2["5 Pods<br/>CPU: 250%"] -->|"부하 제거"| B2["5 Pods<br/>CPU: 0%"]
        B2 -->|"5분 안정화"| C2["스케일다운<br/>시작"]
    end

10.5 최종 리소스 상태

테스트 중 관찰된 클러스터 리소스 상태입니다.

NAME                              READY   STATUS    RESTARTS   AGE
pod/stress-app-655d4b95b5-8bj6z   1/1     Running   0          2m4s
pod/stress-app-655d4b95b5-n46kp   1/1     Running   0          4m49s
pod/stress-app-655d4b95b5-tz8z5   1/1     Running   0          109s
pod/stress-app-655d4b95b5-xfx5x   1/1     Running   0          2m4s
pod/stress-app-655d4b95b5-xm28q   1/1     Running   0          2m4s

NAME                                             REFERENCE               TARGETS
horizontalpodautoscaler.autoscaling/stress-app   Deployment/stress-app   cpu: 0%/50%

5개의 Pod가 정상 Running 상태이며, 부하 제거 후 CPU 사용률이 0%로 안정화된 것을 확인할 수 있습니다. 이 시점에서 5분 안정화 기간이 경과하면 HPA가 스케일다운을 시작합니다.


11. 실무 활용 포인트

11.1 스케일링 전략 선택 가이드

flowchart TD
    A["워크로드 특성 파악"] --> B{"Stateless?"}
    B -->|"Yes"| C{"부하 유형?"}
    B -->|"No (Stateful)"| D["VPA 우선 검토<br/>(In-Place Resize 활용)"]
    C -->|"HTTP 트래픽"| E["HPA + Knative"]
    C -->|"이벤트/큐 기반"| F["HPA + KEDA"]
    C -->|"안정적 트래픽"| G["HPA (CPU/Memory)"]

    D --> H["클러스터 용량 부족?"]
    E --> H
    F --> H
    G --> H
    H -->|"Yes"| I["CA 또는 Karpenter"]
    H -->|"No"| J["현재 설정 유지"]

11.2 프로덕션 체크리스트

HPA 설정 시:

  • 반드시 리소스 requests를 정의합니다 (requests 미정의 시 HPA 동작 불가)
  • 메트릭과 레플리카 수의 상관관계를 확인합니다
  • behavior 필드로 비대칭 스케일링을 구성합니다 (스케일업은 빠르게, 스케일다운은 보수적으로)
  • PodDisruptionBudget(PDB)을 함께 설정하여 스케일다운 시 가용성을 보호합니다

VPA 설정 시:

  • 프로덕션에서는 Off 또는 Initial 모드로 시작하여 추천값을 먼저 관찰합니다
  • HPA와 동일 메트릭(CPU, Memory)을 사용하지 않도록 주의합니다
  • Kubernetes v1.33 이상이라면 InPlaceOrRecreate 모드를 검토합니다

CA/Karpenter 설정 시:

  • 최소·최대 노드 수(또는 limits)를 반드시 설정합니다
  • 비용 알람을 함께 구성합니다
  • PodDisruptionBudget을 통해 스케일다운 시 서비스 가용성을 보호합니다
  • Karpenter를 사용할 경우, limits에 총 CPU/Memory 상한을 설정하여 비용 폭주를 방지합니다

11.3 HPA + CA/Karpenter 연동 흐름

HPA와 CA(또는 Karpenter)는 결합하여 사용하면 효과적입니다. 두 오토스케일러는 서로 독립적으로 동작하지만, 다음과 같이 자연스럽게 연동됩니다.

flowchart TD
    A["부하 증가"] --> B["HPA: Pod 레플리카 증가"]
    B --> C{"노드 용량 충분?"}
    C -->|"Yes"| D["Pod 스케줄링 성공"]
    C -->|"No"| E["Pod Pending 상태"]
    E --> F["CA/Karpenter: 새 노드 추가"]
    F --> D

    G["부하 감소"] --> H["HPA: Pod 레플리카 감소"]
    H --> I["노드 미활용 감지"]
    I --> J["CA/Karpenter: 노드 축소"]

HPA가 Pod 수를 증가시키다가 노드 용량이 부족해지면 CA/Karpenter가 자동으로 노드를 추가하고, 부하가 줄어들면 역순으로 축소됩니다. 이 과정에서 Karpenter의 Consolidation 기능은 미활용 노드를 적극적으로 제거하여 비용을 절감합니다.


 

12. 정리

Elastic Scale 패턴은 쿠버네티스가 단순한 컨테이너 오케스트레이터를 넘어, 부하에 스스로 적응하는 지능형 플랫폼으로 기능할 수 있도록 하는 핵심 패턴입니다.

스케일링 도구 조정 대상 Scale-to-Zero 주요 사용 사례
HPA Pod 레플리카 수 불가 범용 수평 스케일링
Knative Pod 레플리카 수 가능 HTTP 서버리스 워크로드
KEDA Pod 레플리카 수 / Job 가능 이벤트 드리븐 워크로드
VPA Pod 리소스 (CPU/Mem) 해당 없음 리소스 최적화, Stateful 서비스
CA 클러스터 노드 수 해당 없음 클러스터 용량 탄력성
Karpenter 클러스터 노드 수 해당 없음 빠른 프로비저닝, 비용 최적화

 

실제 테스트를 통해 HPA의 스케일링 공식(ceil[currentReplicas × (currentMetricValue / desiredMetricValue)])이 정확히 동작하는 것을 확인했습니다. 부하 증가 시 1→4→5 Pod로 약 100초 만에 확장되었고, 부하 제거 후 5분 안정화 기간을 거쳐 축소가 시작되는 것도 관찰했습니다. 또한 HPA의 기본 tolerance(10%)로 인해 목표 대비 소폭 초과(51%)에서는 스케일업이 트리거되지 않는 것도 확인했습니다.

 

2025년 기준으로 In-Place Pod Resize의 GA 졸업, Karpenter의 성숙, HPA Configurable Tolerance 등이 함께 발전하면서, 쿠버네티스의 오토스케일링 생태계는 더욱 정교하고 실용적인 방향으로 진화하고 있습니다.

각 도구의 특성을 이해하고, 워크로드 특성에 맞게 조합하는 것이 중요합니다.


참고 자료