본문 바로가기
DevOps/Kubernetes

Kubernetes HPA (파드 오토스케일링) [2] - 동작 제어

by 비어원 2025. 1. 5.
728x90

이전 장에서는 HorizontalPodAutoscaler에 대한 기본적인 내용에 대해 알아보았다. HorizontalPodAutoscaler에 대해 처음 들어보았다면 아래 글을 먼저 읽어보는 것이 좋다.

 

 

2025.01.05 - [DevOps/Kubernetes] - Kubernetes HPA (파드 오토스케일링) [1] - 기초

 

Kubernetes HPA (파드 오토스케일링) [1] - 기초

HPA (Horizontal Pod Autoscaler)는 Deployment나 StatefulSet 등의 워크로드의 레플리카 갯수를 수요에 맞게 자동으로 스케일링하도록 한다. 수평 스케일링은 레플리카를 늘리고 줄이는 것을 의미한다. 통상

beer1.tistory.com

 

 

 

autoscaling/v2 버전의 HorizontalPodAutoscaler을 사용한다면 behavior 필드를 사용하여 scale-out / scale-in의 세부 동작을 구성할 수 있다. HPA에서는 파드 수평 확장/축소를 scale-up / scale-down으로 명명하고 있다는 점을 참고하자.

  • behavior.scaleUp: 파드 수평확장 (scale-out) 에 대한 동작 구성
  • behavior.scaleDown: 파드 수평축소 (scale-in) 에 대한 동작 구성

 

Pod 갯수 기반

behavior에서는 scale-up / scale-down 시작 시 파드의 갯수를 제한시킬 수 있다.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: todo-api
  namespace: todo
spec:
  minReplicas: 1
  maxReplicas: 5
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: todo-api
  metrics:
  - resource:
      name: cpu
      target:
        averageUtilization: 50
        type: Utilization
    type: Resource
  behavior:
    scaleUp:
      policies:
        - type: Pods
          value: 1
          periodSeconds: 60
    scaleDown:
      policies:
        - type: Pods
          value: 1
          periodSeconds: 60
  • spec.behavior.scaleUp.policies: 스케일업에 대한 세부 정책을 여러개 등록할 수 있다. (scaleDown도 마찬가지)
  • spec.behavior.scaleUp.policies[].type: 스케일업 정책 시 기준이 되는 타입이며, 여기에는 Pods, Percent 등이 올 수 있다.
  • spec.behavior.scaleUp.policies[].value: 스케일업 정책 시 기준이 되는 타입에 대한 값으로, type이 Pods인 경우 스케일업이 되는 조건이 되면 최대 value 개수만큼 추가 레플리카를 생성한다.
  • spec.behavior.scaleUp.policies[].periodSeconds: 스케일업 정책 시 스케일업 시간으로, 해당 정책이 유지되어야 하는 시간을 의미한다. 한번 스케일 업이 이루어지면, periodSeconds 동안 추가적인 스케일업/다운이 진행되지 않는다.

 

위의 예시에서는 스케일업이 진행되는 경우, 파드를 최대 1개씩 1분 주기로 증가시키며, 스케일다운이 진행되는 경우, 파드를 최대 1개씩 1분 주기로 감소시킨다. 위와 같이 HPA를 적용시킨 후 부하테스트를 진행한 경과를 보여주면 다음과 같다.

 

부하테스트 (100ms)

$ while true; do; curl -XGET http://todo-api.beer1.com/todoList; sleep 0.1; done

 

부하테스트 결과

$ while true; do; kubectl get hpa; sleep 10; done

NAME       REFERENCE             TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
todo-api   Deployment/todo-api   6%/50%    1         5         1          17h  ## 부하테스트 시작
todo-api   Deployment/todo-api   5%/50%    1         5         1          17h
todo-api   Deployment/todo-api   76%/50%   1         5         1          17h
todo-api   Deployment/todo-api   76%/50%   1         5         1          17h  ## scale-up
todo-api   Deployment/todo-api   191%/50%   1         5         2          17h
todo-api   Deployment/todo-api   242%/50%   1         5         2          17h
todo-api   Deployment/todo-api   242%/50%   1         5         2          17h
todo-api   Deployment/todo-api   110%/50%   1         5         2          17h
todo-api   Deployment/todo-api   107%/50%   1         5         2          17h
todo-api   Deployment/todo-api   107%/50%   1         5         2          17h  ## scale-up
todo-api   Deployment/todo-api   61%/50%   1         5         3          17h
todo-api   Deployment/todo-api   59%/50%   1         5         3          17h
todo-api   Deployment/todo-api   59%/50%   1         5         3          17h
todo-api   Deployment/todo-api   54%/50%   1         5         3          17h
todo-api   Deployment/todo-api   79%/50%   1         5         3          17h
todo-api   Deployment/todo-api   79%/50%   1         5         3          17h  ## scale-up
todo-api   Deployment/todo-api   67%/50%   1         5         4          17h
todo-api   Deployment/todo-api   63%/50%   1         5         4          17h
todo-api   Deployment/todo-api   63%/50%   1         5         4          17h  ## 부하테스트 종료
todo-api   Deployment/todo-api   52%/50%   1         5         4          17h
todo-api   Deployment/todo-api   45%/50%   1         5         4          17h
todo-api   Deployment/todo-api   45%/50%   1         5         4          17h
todo-api   Deployment/todo-api   19%/50%   1         5         4          17h
todo-api   Deployment/todo-api   5%/50%    1         5         4          17h
todo-api   Deployment/todo-api   5%/50%    1         5         4          17h
todo-api   Deployment/todo-api   7%/50%    1         5         4          17h
todo-api   Deployment/todo-api   6%/50%    1         5         4          17h
todo-api   Deployment/todo-api   6%/50%    1         5         4          17h
todo-api   Deployment/todo-api   6%/50%    1         5         4          17h
todo-api   Deployment/todo-api   11%/50%   1         5         4          17h
todo-api   Deployment/todo-api   11%/50%   1         5         4          17h
todo-api   Deployment/todo-api   6%/50%    1         5         4          17h
todo-api   Deployment/todo-api   7%/50%    1         5         4          17h
todo-api   Deployment/todo-api   7%/50%    1         5         4          17h
todo-api   Deployment/todo-api   7%/50%    1         5         4          17h
todo-api   Deployment/todo-api   7%/50%    1         5         4          17h
todo-api   Deployment/todo-api   7%/50%    1         5         4          17h
todo-api   Deployment/todo-api   5%/50%    1         5         4          17h
todo-api   Deployment/todo-api   5%/50%    1         5         4          17h
todo-api   Deployment/todo-api   5%/50%    1         5         4          17h
todo-api   Deployment/todo-api   6%/50%    1         5         4          17h
todo-api   Deployment/todo-api   5%/50%    1         5         4          17h
todo-api   Deployment/todo-api   5%/50%    1         5         4          17h
todo-api   Deployment/todo-api   7%/50%    1         5         4          17h
todo-api   Deployment/todo-api   4%/50%    1         5         4          17h
todo-api   Deployment/todo-api   4%/50%    1         5         4          17h
todo-api   Deployment/todo-api   7%/50%    1         5         4          17h
todo-api   Deployment/todo-api   4%/50%    1         5         4          17h
todo-api   Deployment/todo-api   4%/50%    1         5         4          17h
todo-api   Deployment/todo-api   5%/50%    1         5         4          17h
todo-api   Deployment/todo-api   4%/50%    1         5         4          17h  ## scale-down
todo-api   Deployment/todo-api   8%/50%    1         5         3          17h
todo-api   Deployment/todo-api   8%/50%    1         5         3          17h
todo-api   Deployment/todo-api   5%/50%    1         5         3          17h
todo-api   Deployment/todo-api   6%/50%    1         5         3          17h
todo-api   Deployment/todo-api   6%/50%    1         5         3          17h
todo-api   Deployment/todo-api   4%/50%    1         5         3          17h  ## scale-down
todo-api   Deployment/todo-api   7%/50%    1         5         2          17h
todo-api   Deployment/todo-api   7%/50%    1         5         2          17h
todo-api   Deployment/todo-api   5%/50%    1         5         2          17h
todo-api   Deployment/todo-api   6%/50%    1         5         2          17h
todo-api   Deployment/todo-api   6%/50%    1         5         2          17h
todo-api   Deployment/todo-api   5%/50%    1         5         2          17h  ## scale-down
todo-api   Deployment/todo-api   7%/50%    1         5         1          17h
todo-api   Deployment/todo-api   7%/50%    1         5         1          17h
todo-api   Deployment/todo-api   4%/50%    1         5         1          17h
todo-api   Deployment/todo-api   4%/50%    1         5         1          17h
todo-api   Deployment/todo-api   4%/50%    1         5         1          17h
todo-api   Deployment/todo-api   5%/50%    1         5         1          17h
todo-api   Deployment/todo-api   4%/50%    1         5         1          17h
todo-api   Deployment/todo-api   4%/50%    1         5         1          17h

 

 

 

 

  • 첫 번째 scale-up이 일어났을 때는 평균 CPU 사용율이 76%이고, 계산하면 ceil(76/50) = ceil(1.52) 이다. 이 때 레플리카는 2가 된다.
  • 실제로 두 번째 scale-up이 일어나기 전에도 평균 CPU 사용율이 50%가 넘어가지만 behavior에 의해 1분동안 파드 스케일업이 진행되지 않는다.
  • 두 번째 scale-up이 일어났을 때의 평균 CPU 사용율이 107%이고, 계산하면 ceil(2*107 / 50) = ceil(4.28) 으로 레플리카는 5가 되어 3개의 레플리카가 추가로 증설이 되어야 하지만 behavior에 의해 레플리카는 1개만 추가된다. 즉, 여기서 레플리카 갯수는 3이 된다.
  • 부하테스트가 종료된 후 5분동안은 scale-down 조건을 만족하지만 컨트롤러의 --horizontal-pod-autoscaler-downscale-stabilization 설정에 의해 scale-down이 일어나지 않는다.
  • 첫 번째 scale-down이 일어났을 때는 5분동안은 scale-down 조건을 만족하는 경우 발생하는데, 이 때 CPU 평균 사용율이 4%이고, 계산하면 ceil(4*4 / 50) = ceil(0.32) 으로 레플리카는 1이 되어야 하지만 behavior에 의해 레플리카는 1개만 줄어든다. 즉, 여기서 레플리카 갯수는 3이 된다.
  • 실제로 두 번째 scale-down이 일어나기 전에도 평균 CPU 사용율이 한참 낮지만 behavior에 의해 1분동안 파드 스케일다운이 진행되지 않는다.

 

Percent 기반 및 stabilizationWindowSeconds

behavior에서는 scale-up / scale-down 시작 시 현재 레플리카에 대한 비율로 파드를 늘리고 줄일 수도 있다. 그리고 scale-up / down에 대해 각각 stabilizationWindowSeconds을 지정할 수 있는데, 이는 스케일 업/다운 조건이 만족하는 경우에 해당 시간동안 계속 스케일 업/다운 조건이 만족하면 실제로 스케일 다운이 일어나도록 하는 설정이다. --horizontal-pod-autoscaler-downscale-stabilization의 HPA별 개별 설정으로 이해하면 된다.

 

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: todo-api
  namespace: todo
spec:
  minReplicas: 1
  maxReplicas: 10
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: todo-api
  metrics:
  - resource:
      name: cpu
      target:
        averageUtilization: 50
        type: Utilization
    type: Resource
  behavior:
    scaleUp:
      policies:
        - type: Percent
          value: 100
          periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 60
      policies:
        - type: Percent
          value: 50
          periodSeconds: 60
  • spec.behavior.scaleUp.policies[].value: 스케일업 정책 시 기준이 되는 타입에 대한 값으로, type이 Percent인 경우 스케일업이 되는 조건이 되면 최대 현재 레플리카 수 * value / 100 개수만큼 추가 레플리카를 생성한다.

 

위의 설정으로 HPA를 변경한 후 똑같이 부하 테스트를 해보면 다음과 같다.

$ while true; do; kubectl get hpa; sleep 10; done

todo-api   Deployment/todo-api   8%/50%    1         10        1          18h  ## 부하테스트 시작
todo-api   Deployment/todo-api   5%/50%    1         10        1          18h
todo-api   Deployment/todo-api   87%/50%   1         10        1          18h  ## scale-up
todo-api   Deployment/todo-api   131%/50%   1         10        2          18h
todo-api   Deployment/todo-api   131%/50%   1         10        2          18h
todo-api   Deployment/todo-api   75%/50%   1         10        2          18h
todo-api   Deployment/todo-api   126%/50%   1         10        2          18h
todo-api   Deployment/todo-api   126%/50%   1         10        2          18h
todo-api   Deployment/todo-api   120%/50%   1         10        2          18h  ## scale-up
todo-api   Deployment/todo-api   94%/50%   1         10        4          18h
todo-api   Deployment/todo-api   94%/50%   1         10        4          18h
todo-api   Deployment/todo-api   55%/50%   1         10        4          18h
todo-api   Deployment/todo-api   69%/50%   1         10        4          18h
todo-api   Deployment/todo-api   69%/50%   1         10        4          18h
todo-api   Deployment/todo-api   66%/50%   1         10        4          18h  ## scale-up
todo-api   Deployment/todo-api   60%/50%   1         10        6          18h
todo-api   Deployment/todo-api   60%/50%   1         10        6          18h
todo-api   Deployment/todo-api   51%/50%   1         10        6          18h  ## 부하테스트 종료
todo-api   Deployment/todo-api   9%/50%    1         10        6          18h
todo-api   Deployment/todo-api   9%/50%    1         10        6          18h
todo-api   Deployment/todo-api   5%/50%    1         10        6          18h
todo-api   Deployment/todo-api   6%/50%    1         10        6          18h
todo-api   Deployment/todo-api   6%/50%    1         10        6          18h
todo-api   Deployment/todo-api   5%/50%    1         10        6          18h  ## scale-down
todo-api   Deployment/todo-api   11%/50%   1         10        3          18h
todo-api   Deployment/todo-api   11%/50%   1         10        3          18h
todo-api   Deployment/todo-api   5%/50%    1         10        3          18h
todo-api   Deployment/todo-api   5%/50%    1         10        3          18h
todo-api   Deployment/todo-api   5%/50%    1         10        3          18h
todo-api   Deployment/todo-api   5%/50%    1         10        3          18h  ## scale-down
todo-api   Deployment/todo-api   7%/50%    1         10        1          18h
todo-api   Deployment/todo-api   7%/50%    1         10        1          18h

 

 

  • 첫 번째 scale-up이 일어났을 때 평균 CPU 사용률은 87%이며, 계산하면 ceil(87/50) = ceil(1.74) 이며 레플리카 수는 2가 된다.
  • 실제로 두 번째 scale-up이 일어나기 전에도 평균 CPU 사용율이 50%가 넘어가지만 behavior에 의해 1분동안 파드 스케일업이 진행되지 않는다.
  • 두 번째 scale-up이 일어났을 때의 평균 CPU 사용율이 120%이고, 계산하면 ceil(2*120 / 50) = ceil(4.8) 으로 레플리카는 5가 되어 3개의 레플리카가 추가로 증설이 되어야 하지만 behavior에 의해 레플리카는 2개(2 * 1.0) 만 추가된다. 즉, 여기서 레플리카 갯수는 4이 된다.
  • 세 번째 scale-up이 일어났을 때의 평균 CPU 사용율이 66%이고, 계산하면 ceil(4*66 / 50) = ceil(5.28) 으로 레플리카는 6가 되어 2개의 레플리카가 추가로 증설이 되어야 한다. behavior에 의해 레플리카는 2개(4 * 1.0) 까지 추가되기 때문에 2개의 레플리카가 정상적으로 증설이 된다.
  • 부하테스트가 종료된 후 CPU 사용율이 현저히 줄어들어 스케일다운 조건을 만족하지만 stabilizationWindowSeconds에 의해 약 1분동안 스케일다운 조건을 만족하는지 평가한다.
  • 1분동안 스케일 다운 조건이 만족하여 첫 번째 스케일다운 작업이 진행되며, 여기서 평균 CPU 사용율은 5%이고, 계산하면 ceil(6*5/50) = ceil(0.6) 이며 레플리카는 1이 되어야하지만 behavior에 의해 레플리카는 3개 (6 * 0.5) 까지만 줄어들기 때문에 3개의 파드만 줄어든다. 여기서 레플리카 갯수는 3이 된다.
  • 두 번째 스케일다운 작업이 진행되며, 여기서 평균 CPU 사용율은 5%이고, 계산하면 ceil(6*5/50) = ceil(0.6) 이며 레플리카는 1이 되어야한다. behavior에 의해 레플리카는 1.5개 (3 * 0.5) 까지만 줄어드는데 실제로 2개가 줄어들었기 때문에 퍼센트 기반은 ceil으로 평가되는 것 같다.

 

혼합

policies는 배열타입이기 때문에 여러 정책을 넣을 수 있다. 다음과 같이 Pod, Percent 기반을 동시에 사용할 수도 있다.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: todo-api
  namespace: todo
spec:
  minReplicas: 1
  maxReplicas: 10
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: todo-api
  metrics:
  - resource:
      name: cpu
      target:
        averageUtilization: 50
        type: Utilization
    type: Resource
  behavior:
    scaleUp:
      policies:
        - type: Percent
          value: 100
          periodSeconds: 60
        - type: Pods
          value: 3
          periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 60
      policies:
        - type: Percent
          value: 50
          periodSeconds: 60

 

여기서 주목해야 할 점은 두 개 이상의 policies가 있다면, 기본적으로 두 개 모두 평가한 다음 둘 중 큰 것이 우선으로 작용한다. 예를 들어, 현재 레플리카가 5개 있고 평균 CPU 사용율이 90%라면 Percent 기반은 5개, 파드 갯수 기반은 3개이며 실제로 적용되는 것은 Percent 기반이고, 현재 레플리카가 1개 있고 평균 CPU 사용율이 90%라면 Percent 기반은 2개, 파드 갯수 기반은 3개이며 실제로 적용되는 것은 파드 갯수 기반이다.

 

작은 것이 우선이 될 수도 있는데. 이에 대한 설정은 behavior.scaleUp(scaleDown).selectPolicy 필드에서 설정할 수 있으며 Min / Max 둘 중 하나로 설정하면 된다. (default: Max)

 

실제로 어떻게 적용되는지 확인하기 위해 마찬가지로 부하테스트를 진행한 결과는 다음과 같다.

$ while true; do; kubectl get hpa; sleep 10; done

NAME       REFERENCE             TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
todo-api   Deployment/todo-api   6%/50%    1         10        1          18h  ## 부하테스트 시작
todo-api   Deployment/todo-api   6%/50%    1         10        1          18h
todo-api   Deployment/todo-api   187%/50%   1         10        1          18h
todo-api   Deployment/todo-api   187%/50%   1         10        1          18h  ## scale-up
todo-api   Deployment/todo-api   236%/50%   1         10        4          18h
todo-api   Deployment/todo-api   218%/50%   1         10        4          18h
todo-api   Deployment/todo-api   218%/50%   1         10        4          18h
todo-api   Deployment/todo-api   85%/50%   1         10        4          18h
todo-api   Deployment/todo-api   88%/50%   1         10        4          18h
todo-api   Deployment/todo-api   88%/50%   1         10        4          18h  ## scale-up
todo-api   Deployment/todo-api   82%/50%   1         10        8          19h
todo-api   Deployment/todo-api   54%/50%   1         10        8          19h
todo-api   Deployment/todo-api   54%/50%   1         10        8          19h  ## 부하테스트 종료
todo-api   Deployment/todo-api   41%/50%   1         10        8          19h
todo-api   Deployment/todo-api   33%/50%   1         10        8          19h
todo-api   Deployment/todo-api   33%/50%   1         10        8          19h
todo-api   Deployment/todo-api   11%/50%   1         10        8          19h
todo-api   Deployment/todo-api   6%/50%    1         10        8          19h
todo-api   Deployment/todo-api   6%/50%    1         10        8          19h  ## scale-down
todo-api   Deployment/todo-api   7%/50%    1         10        6          19h
todo-api   Deployment/todo-api   6%/50%    1         10        6          19h
todo-api   Deployment/todo-api   6%/50%    1         10        6          19h  ## scale-down
todo-api   Deployment/todo-api   6%/50%    1         10        4          19h
todo-api   Deployment/todo-api   8%/50%    1         10        4          19h
todo-api   Deployment/todo-api   8%/50%    1         10        4          19h  ## scale-down
todo-api   Deployment/todo-api   15%/50%   1         10        3          19h
todo-api   Deployment/todo-api   8%/50%    1         10        3          19h
todo-api   Deployment/todo-api   8%/50%    1         10        3          19h  ## scale-down
todo-api   Deployment/todo-api   6%/50%    1         10        2          19h
todo-api   Deployment/todo-api   6%/50%    1         10        2          19h
todo-api   Deployment/todo-api   6%/50%    1         10        2          19h  ## scale-down
todo-api   Deployment/todo-api   6%/50%    1         10        1          19h

 

 

 

  • 첫 번째 scale-up이 일어났을 때 평균 CPU 사용률은 187%이며, 계산하면 ceil(187/50) = ceil(3.74) 이며 레플리카 수는 4가 된다. 그런데 behavior에 의해 실제로 늘어나는 레플리카가 조절되는데, Pods 기반은 3, Percent 기반은 2이기 때문에 여기서는 Pods 기반이 채택된다. 스케일업에 의해 레플리카 수는 4개가 된다.
  • 두 번째 scale-up이 일어났을 때 평균 CPU 사용률은 88%이며, 계산하면 ceil(4*88/50) = ceil(7.04) 이며 레플리카 수는 8이 된다. 그런데 behavior에 의해 실제로 늘어나는 레플리카가 조절되는데, Pods 기반은 3, Percent 기반은 4이기 때문에 여기서는 Percent 기반이 채택된다. 스케일업에 의해 레플리카 수는 8개가 된다.
  • 첫 번째 scale-down이 일어났을 때 평균 CPU 사용률은 6%이며, 계산하면 ceil(8*6/50) = ceil(0.96) 이며 레플리카 수는 1이 된다. 그런데 behavior에 의해 줄어드는 파드 갯수는 4개(8*0.5) 여야하는데 실제로는 2개가 줄어든다. (의문 1)
  • 두 번째 scale-down이 일어나는 시점은 첫 번째 scale-down이 일어나는 시점으로부터 30초 후이다. 그런데 stabilizationWindowSeconds 에 의해 1분이어야 하는데 30초가 된다. (의문 2)

 

scale-up / down 비활성화

HPA에 해당 필드를 추가함으로써 의도적으로 scale-up 및 down을 비활성화 시킬 수 있다.

behavior:
  scaleDown:
    selectPolicy: Disabled

 

기본 동작

HPA에 behavior를 설정하지 않는 경우에는 다음과 같이 기본동작이 적용된다고 한다.

behavior:
  scaleDown:
    stabilizationWindowSeconds: 300
    policies:
    - type: Percent
      value: 100
      periodSeconds: 15
  scaleUp:
    stabilizationWindowSeconds: 0
    policies:
    - type: Percent
      value: 100
      periodSeconds: 15
    - type: Pods
      value: 4
      periodSeconds: 15
    selectPolicy: Max

 

마무리

이번 장에서는 HPA에서의 scale-up / down 시 세부 정책에 대해 알아보았다. 마지막 혼합 설정에서 scale-down 시 의도대로 되지 않는다는 점에서 약간의 의문점은 있지만 behavior를 통해 실제로 스케일업이나 다운이 발생할 때 세부적으로 제어할 수 있다는 점에서 오토스케일을 좀 더 전략적으로 잘 사용할 수 있을 것으로 보인다.

 

 

728x90

댓글