본문 바로가기
DevOps/Kubernetes

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

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

 

HPA (Horizontal Pod Autoscaler)는 Deployment나 StatefulSet 등의 워크로드의 레플리카 갯수를 수요에 맞게 자동으로 스케일링하도록 한다.

 

수평 스케일링은 레플리카를 늘리고 줄이는 것을 의미한다. 통상적으로 레플리카를 늘리는 것을 scale-out, 줄이는 것을 scale-in 이라고 부른다. 수직 스케일링이라는 것도 있는데, 이는 레플리카를 조절하는 것이 아닌 CPU 및 메모리 등 서버의 스펙을 늘리거나 줄이는 것을 의미한다. (이는 scale-up / scale-down 으로 불린다.)

HPA 동작 방식

쿠버네티스에는 HPA를 지원하기 위해 HorizontalPodAutoscaler API와 이에 대응하는 컨트롤러를 제공한다. HorizontalPodAutoscaler에서는 파드 수평 스케일링의 대한 정보를 기술할 수 있으며 대표적으로는 다음 정보를 기술한다.

  • HPA를 적용시킬 워크로드
  • HPA 적용 기준 (메트릭)
  • 최소 / 최대 레플리카 갯수
  • 오토스케일링 세부 행위

 

HorizontalPodAutoscaler에 대응하는 컨트롤러는 kube-controller-manager에 구현이 되어있으며, 컨트롤러는 주기적으로 클러스터에 선언된 HorizontalPodAutoscaler을 확인한다. HorizontalPodAutoscaler를 확인하는 주기는 kube-controller-manager--horizontal-pod-autoscaler-sync-period 파라미터에 의해 결정된다.

 

 

컨트롤러는 주기적으로 다음과 같이 HorizontalPodAutoscaler를 확인하여 파드 오토스케일링을 진행한다.

 

  1. 각 주기마다 컨트롤러는 HorizontalPodAutoscaler에 지정된 타겟을 찾는다. 타겟은 결국 파드집합이다. (spec.scaleTargetRef)
  2. HorizontalPodAutoscaler에서 지정된 메트릭을 확인하여, 타겟 파드의 리소스 사용률 평균을 구한다. (spec.metrics)
    • 여기서 리소스는 기본적으로는 CPU, Memory 가 있고, 그 외의 다른 커스텀 메트릭을 정의하여 사용할 수도 있다.
  3. 타겟 파드의 리소스 사용률에 따라 아래의 식에 따라 레플리카 갯수를 변경한다. 여기서 메트릭 값에 해당하는 것은 파드 리소스의 requests 이며 limits은 관계가 없다.
원하는 레플리카 수 = ceil[현재 레플리카 수 * ( 현재 메트릭 값 / 원하는 메트릭 값 )]
  • ex) 메모리를 기반으로 사용율을 따질 때, 파드 메모리 requests가 1Gi 이고, 실제 메모리 사용량이 512Mi 라면 사용률은 0.5이다.

 

예를 들어, 레플리카의 갯수가 3이고, CPU 사용율 기준을 80%으로 설정하였을 때 평균 CPU 사용율에 따른 레플리카 수 변화는 다음과 같다.

현재 레플리카 수 현재 CPU 사용율 원하는 CPU 사용율 원하는 레플리카 수 계산 식
3 75% 80% 3 ceil(3*75/80) = ceil(2.81)
3 90% 80% 4 (scale-out) ceil(3*90/80) = ceil(3.375)
4 67.5% 80% 4 Ceil(4*67.5/80) = ceil(3.375) (scale-out 직후)
4 65% 80% 4 Ceil(4*65/80) = ceil(3.25)
4 50% 80% 3 (scale-in) Ceil(4*50/80) = ceil(2.5)
3 66.7% 80% 3 Ceil(3*66.7/80) = ceil(2.5) (scale-in 직후)
3 45% 80% 2 (scale-in) Ceil(3*45)=ceil(1.69)
2 67.5% 80% 2 Ceil(2*67.5)=ceil(1.69) (scale-in 직후)

 

Metric과 Metric Server

 

위의 동작방식에서 컨트롤러는 HorizontalPodAutoscaler에 지정된 메트릭에 대한 타겟 파드의 리소스 사용율을 구해야 하는데, 이 메트릭은 당연히 컨트롤러가 읽을 수 있어야 한다. 쿠버네티스에서는 컨트롤러가 HPA에서 사용할 수 있는 메트릭을 가져오기 위해서 지정된 API를 사용하는데, 이 종류로는 metrics.k8s.io, custom.metrics.k8s.io, external.metrics.k8s.io가 있다. 다르게 말하면, metrics.k8s.io, custom.metrics.k8s.io, external.metrics.k8s.io API를 사용할 수 있어야지만 HPA 기능을 사용할 수 있다.

 

하지만, 기본적으로는 쿠버네티스 클러스터에 metrics.k8s.io, custom.metrics.k8s.io, external.metrics.k8s.io API는 제공되어있지 않다. 클러스터에서 지원하는 API Resource를 확인하기 위해서 아래 명령어를 사용해보자. 항목에 위의 API가 없다면 당장은 HPA 기능은 사용할 수 없을 것이다.

 

$ kubectl api-resources

# metrics가 포함된 API Resources 필터링
$ kubectl api-resources | grep metrics

 

위의 API는 애드온에 의해 제공되며, 별도로 애드온을 설치해야 한다. 가장 간단하게는 Metrics Server를 설치하면 해당 API Resource를 사용할 수 있게 된다. 아래의 명령어를 통해 간단히 설치할 수 있다.

 

$ kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

 

만약 metrics-server 설치 시 아래 에러가 발생한다면 deployment에 arguments를 하나 추가해야 한다.

E0104 09:04:26.156491       1 scraper.go:149] "Failed to scrape node" err="Get \"https://192.168.35.167:10250/metrics/resource\": tls: failed to verify certificate: x509: cannot validate certificate for 192.168.35.167 because it doesn't contain any IP SANs" node="k8s-cp1"
E0104 09:04:26.159954       1 scraper.go:149] "Failed to scrape node" err="Get \"https://192.168.35.2:10250/metrics/resource\": tls: failed to verify certificate: x509: cannot validate certificate for 192.168.35.2 because it doesn't contain any IP SANs" node="k8s-wn1"
E0104 09:04:26.160729       1 scraper.go:149] "Failed to scrape node" err="Get \"https://192.168.35.183:10250/metrics/resource\": tls: failed to verify certificate: x509: cannot validate certificate for 192.168.35.183 because it doesn't contain any IP SANs" node="k8s-wn2"
$ kubectl edit deploy metrics-server -n kube-system


spec:
  template:
    spec:
      containers:
        - args:
          - ...
          - --kubelet-insecure-tls # 이 옵션 추가

 

metrics-server를 성공적으로 설치하였다면 api-resources 항목이 추가될 것이다.

 

$ kubectl api-resources | grep metrics
nodes                                          metrics.k8s.io/v1beta1                 false        NodeMetrics
pods                                           metrics.k8s.io/v1beta1                 true         PodMetrics
  • metrics-server는 metrics.k8s.io API만 제공한다.
  • custom.metrics.k8s.io는 사용자 정의 메트릭으로, 별도의 메트릭 백엔드에 대한 어댑터 서버에서 제공한다. 대표적으로는 prometheus-adapter 가 있다. prometheus를 사용하는 경우라면 이것을 사용하여 커스텀 메트릭을 활용한 HPA도 사용할 수 있다.
  • external.metrics.k8s.io은 외부 메트릭으로 이것도 메트릭 어댑터 서버가 필요하다. prometheus-adapter는 해당 API 또한 제공한다.

 

보너스로 metrics-server를 생성하였다면 kubectl top 명령어를 사용하여 파드, 노드의 리소스 사용량을 확인할 수 있다.

$ kubectl top node
NAME      CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
k8s-cp1   108m         5%     1159Mi          61%
k8s-wn1   32m          1%     1505Mi          39%
k8s-wn2   45m          2%     1590Mi          41%

$ kubectl top pod
NAME                       CPU(cores)   MEMORY(bytes)
todo-api-f75444874-hhzvd   5m           292Mi

 

HPA 적용하기

metrics-server 까지 설치하였다면 HPA를 사용할 준비는 완료되었다. 이제 실제로 HPA를 적용해보자. 아래 명령어를 통해 간단히 HorizontalPodAutoscaler를 생성할 수 있다.

$ kubectl autoscale deploy/todo-api --cpu-percent=50 --min=1 --max=5
horizontalpodautoscaler.autoscaling/todo-api autoscaled
  • CPU 기반 HPA를 적용하였으며, 평균 CPU 사용율 50%을 기준으로 오토스케일이 이루어진다.
  • 오토스케일링에 의해 결정되는 최소 레플리카는 1개, 최대 레플리카는 5대로 설정하였다.
  • 적용시킬 대상은 todo-api Deployment이며, 해당 파드의 CPU Requests는 정의되어 있어야 한다.

 

HPA 추가 후에 아래 명령어로 HPA를 확인할 수 있다.

$ kubectl get hpa
NAME       REFERENCE             TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
todo-api   Deployment/todo-api   1%/50%    1         5         1          114s

 

 

HPA를 생성한 후 해당 파드에 100ms 주기로 계속 요청하여 부하테스트를 간단히 진행해보자.

$ while true; do; curl -XGET http://todo-api.beer1.com/todoList; sleep 0.1; done
  • ingress를 만들어서 todo-api.beer1.com 도메인으로 요청오는 경우 todo-api 서비스로 라우팅하도록 구성하였다.
  • 물론 port-forward 명령어를 통해 파드에 요청을 날리는 것도 가능하지만, 레플리카가 여러개로 늘어나더라도 하나의 파드에만 부하가 가기 떄문에 HPA 부하 테스트로는 적합하지 않을 수 있다. (port-forward svc도 마찬가지다.)

 

아래 명령어를 사용하여 hpa의 변화를 관찰해보자.

$ kubectl get hpa -w
NAME       REFERENCE             TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
todo-api   Deployment/todo-api   5%/50%    1         5         1          50m
todo-api   Deployment/todo-api   37%/50%   1         5         1          50m
todo-api   Deployment/todo-api   86%/50%   1         5         1          50m # scale-out 시작
todo-api   Deployment/todo-api   44%/50%   1         5         2          50m
todo-api   Deployment/todo-api   26%/50%   1         5         2          51m 
todo-api   Deployment/todo-api   80%/50%   1         5         2          51m # scale-out 시작
todo-api   Deployment/todo-api   51%/50%   1         5         4          51m
todo-api   Deployment/todo-api   28%/50%   1         5         4          51m # 부하테스트 종료
todo-api   Deployment/todo-api   5%/50%    1         5         4          52m
todo-api   Deployment/todo-api   7%/50%    1         5         4          52m
todo-api   Deployment/todo-api   6%/50%    1         5         4          52m
todo-api   Deployment/todo-api   5%/50%    1         5         4          53m
todo-api   Deployment/todo-api   4%/50%    1         5         4          53m
todo-api   Deployment/todo-api   6%/50%    1         5         4          53m
todo-api   Deployment/todo-api   5%/50%    1         5         4          53m
todo-api   Deployment/todo-api   8%/50%    1         5         4          54m
todo-api   Deployment/todo-api   6%/50%    1         5         4          54m
todo-api   Deployment/todo-api   15%/50%   1         5         4          55m
todo-api   Deployment/todo-api   5%/50%    1         5         4          55m
todo-api   Deployment/todo-api   7%/50%    1         5         4          55m
todo-api   Deployment/todo-api   5%/50%    1         5         4          55m
todo-api   Deployment/todo-api   6%/50%    1         5         4          56m
todo-api   Deployment/todo-api   5%/50%    1         5         4          56m # scale-in 시작
todo-api   Deployment/todo-api   7%/50%    1         5         2          56m
todo-api   Deployment/todo-api   6%/50%    1         5         2          57m
todo-api   Deployment/todo-api   5%/50%    1         5         2          57m
todo-api   Deployment/todo-api   12%/50%   1         5         2          57m
todo-api   Deployment/todo-api   5%/50%    1         5         2          58m
todo-api   Deployment/todo-api   7%/50%    1         5         2          59m
todo-api   Deployment/todo-api   5%/50%    1         5         2          59m
todo-api   Deployment/todo-api   4%/50%    1         5         2          59m
todo-api   Deployment/todo-api   5%/50%    1         5         2          60m # scale-in 시작
todo-api   Deployment/todo-api   6%/50%    1         5         1          60m

 

  • 첫 번째 scale-out이 시작되는 시점은 리소스 사용율이 86%가 되는 시점이다. 이 때는 ceil(1*86/50) = ceil(1.72) 이기 때문에 레플리카가 2대로 조정된다.
  • 두 번째 scale-out이 시작되는 시점은 레플리카 2일 때 리소스 사용율이 80%가 되는 시점이다. 이 때는 ceil(2*80/50) = ceil(3.2) 이기 때문에 레플리카가 4대로 조정된다.
  • 첫 번째로 scale-in이 시작되는 시점은 부하테스트가 종료되고 약 5분 뒤에 시작이 된다. 이 때는 ceil(4*5/50) = ceil(0.4) 여서 레플리카가 1대여야 하는데 2대로 조정된다. 그리고 이미 부하테스트가 종료된 후에 CPU 사용율이 줄어들었기 때문에 더 빨리 레플리카가 줄어들어야 하는데 그렇지 않았다.
  • 두 번째로 scale-in이 시작되는 시점은 첫 번째 scale-in이 시작된 후 약 4분 뒤에 시작되었다.

 

테스트를 통해 알 수 있었던 것은 계산 식 결과 scale-out이 되는 경우는 즉각 반영되지만 scale-in이 되는 경우는 즉각적으로 반영이 되지 않는다. 이유는 scale-in의 경우에는 약간의 보정이 들어가는데, kube-controller-manager의 --horizontal-pod-autoscaler-downscale-stabilization 옵션 떄문이다.

 

리소스 사용률이 scale-in 조건에 만족하는 경우 해당 옵션의 값만큼 시간이 지난 후에도 여전히 scale-in 조건에 만족한다면 그 때 실제로 scale-in을 진행한다. 기본값으로는 5분(5m) 이며 scale-in이 점진적으로 발생하여 급격히 변동하는 메트릭 값의 영향을 완만하게 해준다.

  • 여기서 생각해봐야 할 점은 scale-out은 즉시이고, scale-in은 평가시간을 길게 잡는것으로 되어있으며 두 행위에 대한 차이가 있다.
  • scale-out을 하는 경우, 실질적으로 가용 레플리카가 늘어나는 시점은 추가 레플리카가 모두 ready 상태가 되는 시점이다. 즉, scale-out이 즉시 되는 것이 아니기 때문에 부하가 많이 발생하면 즉시 레플리카를 요청하는게 유리하기 때문이 아닐까 생각한다.
  • scale-in 조건을 만족하는 경우, 아주 운좋게 평가 시점에만 리소스 사용량이 감소했다면 scale-in이 즉시 일어난 이후에는 여전히 요청이 많을 것이며 다시 scale-out을 해야하는 경우가 발생할 수 있다. scale-out -> ready 상태로 가는 시간적 비용이 따르기 떄문에 scale-in에 대한 평가는 오래하는 것이 유리할 것으로 보고 있다.

 

마무리

지금까지 쿠버네티스 파드 오토 스케일링 기능에 대해 알아보았다. 이번 장에서 알아본 내용은 아주 기본적인 내용이며, 추후에는 HPA 각각에 대한 scale-out 및 scale-in에 대한 세부 동작을 정의하는 방법과, 커스텀 리소스를 사용하여 오토스케일링을 하는 방식을 다뤄볼 예정이다.

 

 

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

 

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

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

beer1.tistory.com

 

 

728x90

댓글