[Kubernetes] HPA(HorizontalPodAutoscaler) 개념 정리 및 실습
쿠버네티스로 서비스를 운영하다 보면 트래픽이 갑자기 몰리는 순간이 반드시 온다. 이럴 때마다 사람이 직접 파드 개수를 늘렸다 줄였다 하는 건 사실상 불가능하다. 이번 글에서는 이 문제를 자동으로 해결해주는 쿠버네티스 리소스인 HPA(Horizontal Pod Autoscaler) 를 개념부터 실습까지 정리해본다. HPA란? HPA는 CPU, 메모리 사용량 혹은 사용자 정의 메트릭(Custom Metrics)의 부하에 따라 파드의 개수를 자동으로 늘리거나 줄여주는(Scaling) 쿠버네티스 리소스다. 트래픽이 갑자기 늘어나면 파드를 추가로 띄워서 대응하고 (Scaleout) 트래픽이 줄어들면 불필요한 파드를 줄여서 자원 낭비를 막는다 (Scalein) 즉, 사람이 개입하지 않아도 부하에 맞춰 자원을 효율적으로 관리해주는 것이 HPA의 목적이다. Vertical Scaling vs Horizontal Scaling 오토스케일링은 크게 두 가지 방향으로 나눌 수 있다. Vertical (Scale up/down): 파드 개수는 그대로 두고, 파드 하나가 쓸 수 있는 자원(CPU, 메모리)을 늘리는 방식 Horizontal (Scale out/in): 파드 자체의 개수를 늘리거나 줄이는 방식 HPA는 이름 그대로 후자, Horizontal 방식이다. Vertical 방식은 파드를 재시작해야 하는 등 비활성화 구간이 생기기 쉬운 반면, Horizontal 방식은 파드를 추가/제거하는 방식이라 무중단으로 대응하기 좋다는 장점이 있다. 다만 DB처럼 상태를 갖는(stateful) 워크로드는 여러 개로 늘려도 유의미하지 않은 경우가 많아서, 상태 없는(stateless) 서비스에 주로 적합하다. 실습 환경 준비 먼저 실습용 디렉터리를 하나 만들어준다. bash mkdir hpa cd hpa 1. 리소스를 제한하는 파드 생성 HPA가 CPU 사용률을 기준으로 스케일링 여부를 판단하려면, 먼저 파드에 CPU/메모리 자원을 얼마나 할당할지(requests)와 최대 얼마까지 쓸 수 있는지(limits)를 정의해줘야 한다. bash vi res.yml yaml spec: containers: name: nginx image: nginx:latest resources: requests: memory: "64Mi" cpu: "250m" limits: memory: "128Mi" cpu: "500m" requests: 컨테이너 생성 시 최소한 보장받는 자원. 스케줄러가 파드를 배치할 노드를 고를 때 이 값을 기준으로 판단한다. limits: 컨테이너가 최대로 사용할 수 있는 자원. 이 값을 넘기면 제한이 걸린다. 이렇게 파드에 자원을 할당해두면, 파드에 부여된 리소스(CPU, RAM) 사용률이 특정 임계값 이상이거나 이하일 때 파드 개수를 자동으로 늘리거나 줄일 수 있게 된다. 다만 이걸 하려면 대상 파드의 자원 사용량을 실시간으로 모니터링해줄 메트릭 서버가 반드시 필요하다. 2. 메트릭 서버(Metrics Server) 설치 HPA는 파드의 CPU/메모리 사용량을 직접 측정하지 않는다. 클러스터 내에 별도로 떠 있는 메트릭 서버로부터 이 값을 가져와서 판단한다. 그래서 HPA를 쓰기 전에 메트릭 서버부터 설치해야 한다. 메트릭서버 매니페스트는 아래 깃허브에서 받을 수 있다. https://github.com/kubernetessigs/metricsserver bash curl Ls https://github.com/kubernetessigs/metricsserver/releases/latest/download/components.yaml o metric.yml 다운로드한 매니페스트를 열어서 몇 가지를 수정해줘야 한다. bash vi metric.yml 수정이 필요한 부분은 containers.args 쪽이다. yaml spec: containers: args: kubeletinsecuretls 추가 certdir=/tmp secureport=10250 kubeletpreferredaddresstypes=InternalIP 수정 kubeletusenodestatusport metricresolution=15s kubeletinsecuretls 옵션을 추가해서 kubelet과의 통신 시 TLS 인증서 검증을 생략하도록 한다. (사설/테스트 환경에서 인증서 문제로 메트릭 서버가 뜨지 않는 걸 방지하기 위함) kubeletpreferredaddresstypes 값에서 ,ExternalIP,Hostname을 삭제하고 InternalIP만 남겨서, 노드의 내부 IP로만 kubelet에 접근하도록 해준다. 수정이 끝났으면 클러스터에 적용한다. bash kubectl apply f metric.yml 3. 테스트용 Deployment / Service 배포 HPA로 스케일링을 테스트해볼 대상이 필요하다. nginx 기반의 간단한 Deployment와 Service를 하나 만들어준다. bash vi dep.yml yaml apiVersion: v1 kind: Service metadata: name: mysvc spec: selector: app: myweb ports: port: 80 targetPort: 80 apiVersion: apps/v1 kind: Deployment metadata: name: mydep spec: replicas: 3 selector: matchLabels: app: myweb template: metadata: labels: app: myweb spec: containers: image: 61.254.18.30:5000/ipnginx name: mywebcon resources: requests: cpu: "10m" limits: cpu: "20m" CPU 사용률을 기준으로 스케일링을 확인할 것이기 때문에, 일부러 requests.cpu, limits.cpu 값을 아주 작게(10m, 20m) 잡았다. 이렇게 해야 약간의 부하만 줘도 사용률(%)이 쉽게 임계치를 넘어서 스케일링 동작을 눈으로 빠르게 확인할 수 있다. bash kubectl apply f dep.yml 배포 후 kubectl top pod로 각 파드의 실제 자원 사용량을 확인할 수 있다. 4. HPA 생성하기 — 명령어로 바로 생성 가장 간단하게는 kubectl autoscale 명령어로 바로 HPA를 만들 수 있다. bash kubectl autoscale deploy mydep min=1 max=5 cpupercent=50 CPU 사용량 임계치를 50%로 설정해서, 최소 1개 최대 5개 사이에서 파드 개수를 자동으로 조절하겠다는 의미다. 5. HPA를 매니페스트로 작성하기 위에서 명령어 한 줄로 만든 것과 동일한 설정을 매니페스트(YAML) 파일로도 작성할 수 있다. 실제 운영 환경에서는 이렇게 선언적으로 관리하는 걸 선호한다. bash vi as.yml yaml apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: hpanginx spec: maxReplicas: 5 minReplicas: 1 scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: mydep 오토스케일링 대상 Deployment 이름 명시 targetCPUUtilizationPercentage: 50 scaleTargetRef에 스케일링 대상이 되는 Deployment를 지정해주고, targetCPUUtilizationPercentage로 임계치를, minReplicas/maxReplicas로 파드 개수의 하한선과 상한선을 정해주는 구조다. 6. 부하를 줘서 스케일 아웃 확인하기 이제 실제로 트래픽을 흉내 내서 HPA가 정말 동작하는지 확인해볼 차례다. 아래 명령어로 0.1초 간격으로 서비스에 계속 curl 요청을 날려서 부하를 준다. bash i=1; while true; do sleep 0.001; echo $((i++)) curl s ; done 여기서 IP는 kubectl get svc로 확인한 대상 서비스(예: mysvc)의 ClusterIP를 넣어주면 된다. 7. 결과 확인 부하를 주는 동안 다른 터미널에서 HPA와 파드 상태를 실시간으로 지켜보면 스케일 아웃이 일어나는 걸 확인할 수 있다. bash kubectl get hpa 현재 오토스케일링 설정이 어떻게 되어 있는지, 그리고 CPU 사용률이 임계치 대비 몇 %인지 확인할 수 있다. bash kubectl top pod watch 명령어와 함께 사용하면 파드 개수가 늘어나는 과정을 실시간으로 관찰할 수 있다. bash watch kubectl get hpa watch kubectl top pod 부하를 주기 시작하면 CPU 사용률이 임계치(50%)를 넘으면서, 처음 3개였던 파드가 최대 5개까지 늘어나는 것을 볼 수 있다. 8. 부하가 사라지면 다시 Scalein 반대로 부하 명령을 멈추면 어떻게 될까? CPU 사용률이 떨어지면서 HPA가 자동으로 파드 개수를 줄이기 시작한다. [이미지 삽입: 부하 종료 후 REPLICAS가 줄어드는 kubectl get hpa / kubectl top pod 캡처] 흥미로운 점은, 처음 Deployment 매니페스트에서 지정했던 replicas: 3과는 상관없이 HPA가 설정한 minReplicas 값인 1개까지 파드 수가 줄어든다는 것이다. HPA가 붙는 순간, 파드 개수의 기준은 Deployment의 replicas가 아니라 HPA의 minReplicas / maxReplicas가 된다는 걸 실습을 통해 확인할 수 있었다. 마무리 이번 실습으로 정리한 흐름을 요약하면 다음과 같다. 1. 파드에 requests/limits로 CPU·메모리 자원을 할당한다. 2. 메트릭 서버를 설치해서 파드의 실시간 자원 사용량을 수집할 수 있게 한다. 3. 스케일링 대상이 될 Deployment/Service를 배포한다. 4. kubectl autoscale 명령 또는 HPA 매니페스트로 오토스케일링 정책(최소/최대 개수, CPU 임계치)을 설정한다. 5. 부하를 줘서 Scaleout을, 부하를 멈춰서 Scalein을 눈으로 확인한다. HPA는 결국 "메트릭 서버가 수집한 지표"와 "내가 설정한 임계치"를 비교해서 파드 개수를 알아서 조절해주는 도구다. Deployment의 replicas는 초기값일 뿐, HPA가 붙는 순간부터는 HPA의 설정값이 우선한다는 점만 기억해두면 실무에서 헷갈릴 일이 없을 것 같다.
![[Kubernetes] HPA(HorizontalPodAutoscaler) 개념 정리 및 실습](/_next/image?url=https%3A%2F%2Fres.cloudinary.com%2Fdf4g2myjt%2Fimage%2Fupload%2Ff_auto%2Cq_auto%2Fv1788883013%2Fblog%2Fpttgjvtr7fichpbvoahg.png&w=3840&q=75)