본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 10. 29. · 23 Views
Kubernetes 오토스케일링 완벽 가이드
Kubernetes에서 애플리케이션의 부하에 따라 자동으로 리소스를 조절하는 오토스케일링 기술을 완벽하게 마스터합니다. HPA, VPA, Cluster Autoscaler의 개념부터 실전 활용까지 초급 개발자도 쉽게 이해할 수 있도록 구성했습니다.
목차
- HPA 기본 개념
- HPA 메트릭 설정
- VPA 개념과 활용
- Cluster Autoscaler
- Custom Metrics 오토스케일링
- 오토스케일링 모니터링
- 오토스케일링 최적화 전략
- 멀티 클러스터 오토스케일링
1. HPA 기본 개념
시작하며
여러분이 쇼핑몰 서비스를 운영하는데, 평소에는 접속자가 적다가 특정 시간대나 프로모션 기간에 갑자기 트래픽이 몰리는 상황을 겪어본 적 있나요? 이럴 때 수동으로 Pod 개수를 늘리고 줄이는 작업은 굉장히 번거롭고, 타이밍을 놓치면 서비스 장애로 이어질 수 있습니다.
이런 문제는 실제 개발 현장에서 매우 자주 발생합니다. 트래픽 패턴을 완벽하게 예측하기는 불가능하고, 24시간 모니터링하면서 수동으로 스케일링하는 것도 현실적이지 않습니다.
게다가 리소스를 과도하게 할당하면 비용이 낭비되고, 부족하게 할당하면 사용자 경험이 저하됩니다. 바로 이럴 때 필요한 것이 HPA(Horizontal Pod Autoscaler)입니다.
HPA는 실시간으로 메트릭을 모니터링하면서 자동으로 Pod 개수를 조절하여, 여러분이 잠들어 있을 때도 서비스를 안정적으로 유지해줍니다.
개요
간단히 말해서, HPA는 CPU 사용률이나 메모리 같은 메트릭을 기반으로 Pod의 복제본 개수를 자동으로 늘리거나 줄이는 Kubernetes의 핵심 기능입니다. 왜 이 개념이 필요한지 실무 관점에서 설명하자면, 현대의 클라우드 네이티브 애플리케이션은 트래픽이 시간대별로, 이벤트별로 급격하게 변합니다.
예를 들어, 배달 앱은 점심시간과 저녁시간에 트래픽이 집중되고, 이커머스는 특가 세일 시작 시점에 폭발적인 접속이 발생합니다. 이런 경우에 HPA는 자동으로 대응하여 서비스 품질을 유지하면서도 비용을 최적화합니다.
기존에는 개발자가 직접 kubectl scale 명령어로 Pod 개수를 조절하거나, 예상 트래픽에 맞춰 미리 많은 Pod을 띄워놓았다면, 이제는 HPA가 실시간 부하에 맞춰 자동으로 최적의 Pod 개수를 유지합니다. HPA의 핵심 특징은 크게 세 가지입니다.
첫째, 반응형 스케일링으로 메트릭 임계값에 도달하면 즉시 반응합니다. 둘째, 양방향 스케일링으로 늘리는 것뿐만 아니라 줄이는 것도 자동으로 처리합니다.
셋째, 다양한 메트릭 지원으로 CPU, 메모리뿐만 아니라 커스텀 메트릭까지 사용할 수 있습니다. 이러한 특징들이 중요한 이유는 수동 개입 없이도 애플리케이션이 항상 최적의 상태를 유지할 수 있기 때문입니다.
코드 예제
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-app-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web-app
minReplicas: 2 # 최소 Pod 개수
maxReplicas: 10 # 최대 Pod 개수
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # CPU 사용률 70% 목표
설명
이것이 하는 일: HPA는 지정된 Deployment의 Pod 개수를 CPU 사용률에 따라 자동으로 조절합니다. 기본적으로 30초마다 메트릭을 확인하고, 목표 값과 비교하여 스케일링 여부를 결정합니다.
첫 번째로, scaleTargetRef 섹션이 어떤 Deployment를 모니터링할지 지정합니다. 여기서는 'web-app'이라는 Deployment를 대상으로 합니다.
이렇게 하는 이유는 HPA가 여러 리소스를 동시에 관리할 수 있지만, 각 HPA는 하나의 특정 대상에 집중하여 정확한 스케일링을 수행하기 위함입니다. 두 번째로, minReplicas와 maxReplicas가 스케일링의 범위를 정의합니다.
최소 2개로 설정한 이유는 고가용성을 보장하기 위함이고, 최대 10개로 제한한 이유는 무한정 확장되어 비용이 폭발하는 것을 방지하기 위함입니다. 내부적으로 HPA 컨트롤러는 이 범위 내에서만 스케일링을 수행합니다.
세 번째로, metrics 섹션에서 CPU 사용률 70%를 목표로 설정했습니다. HPA는 모든 Pod의 평균 CPU 사용률을 계산하고, 이 값이 70%에 최대한 가까워지도록 Pod 개수를 조절합니다.
예를 들어 현재 CPU 사용률이 90%라면 Pod을 추가하고, 40%라면 Pod을 줄입니다. 마지막으로, HPA는 스케일 업과 스케일 다운에 서로 다른 쿨다운 시간을 적용합니다.
기본적으로 스케일 업은 빠르게(3분), 스케일 다운은 천천히(5분) 진행되어 급격한 부하 변화에는 빠르게 대응하면서도 불필요한 Pod 재시작을 방지합니다. 여러분이 이 코드를 사용하면 수동 개입 없이 자동으로 최적의 Pod 개수를 유지할 수 있습니다.
이는 개발자의 운영 부담을 크게 줄여주고, 야간이나 주말에도 안정적인 서비스 운영을 보장하며, 불필요한 리소스 낭비를 막아 클라우드 비용을 최적화하는 효과를 가져옵니다.
실전 팁
💡 minReplicas를 최소 2 이상으로 설정하세요. 1로 설정하면 해당 Pod에 문제가 생겼을 때 서비스 전체가 중단될 수 있습니다. 고가용성을 위해서는 항상 여러 복제본을 유지하는 것이 안전합니다.
💡 목표 CPU 사용률은 70-80% 사이가 적절합니다. 너무 높게 설정(90% 이상)하면 갑작스런 트래픽 증가에 대응하기 어렵고, 너무 낮게 설정(50% 이하)하면 리소스 낭비가 발생합니다.
💡 HPA를 적용하기 전에 반드시 Pod에 resources.requests를 설정해야 합니다. requests가 없으면 HPA가 CPU 사용률을 계산할 수 없어서 정상 작동하지 않습니다.
💡 kubectl get hpa 명령어로 현재 상태를 주기적으로 확인하세요. TARGETS 컬럼에서 현재 메트릭 값과 목표 값을 확인할 수 있고, REPLICAS 컬럼에서 실제 스케일링이 일어나고 있는지 모니터링할 수 있습니다.
💡 프로덕션 환경에서는 HPA와 함께 PodDisruptionBudget(PDB)를 설정하여, 스케일 다운 시에도 최소한의 가용성을 보장하세요.
2. HPA 메트릭 설정
시작하며
여러분이 API 서버를 운영하는데, CPU는 여유로운데 메모리 사용량이 급증하면서 OOMKilled 에러가 발생하는 상황을 경험해본 적 있나요? 이럴 때 CPU만 보고 스케일링하는 HPA는 문제를 감지하지 못하고, 결국 서비스 장애로 이어집니다.
이런 문제는 애플리케이션의 특성에 따라 다양하게 나타납니다. 이미지 처리 서비스는 메모리를 많이 사용하고, 데이터베이스는 I/O가 병목이 되며, 웹 서버는 동시 연결 수가 중요합니다.
단일 메트릭만으로는 애플리케이션의 실제 상태를 정확히 반영할 수 없습니다. 바로 이럴 때 필요한 것이 멀티 메트릭 HPA 설정입니다.
여러 메트릭을 동시에 모니터링하고, 각 메트릭의 특성에 맞게 스케일링 정책을 세밀하게 조정하여 더 정확하고 효율적인 오토스케일링을 구현할 수 있습니다.
개요
간단히 말해서, HPA는 CPU뿐만 아니라 메모리, 커스텀 메트릭 등 여러 메트릭을 동시에 사용할 수 있으며, 각 메트릭마다 다른 임계값과 정책을 설정할 수 있는 강력한 기능을 제공합니다. 왜 이 개념이 필요한지 실무 관점에서 설명하자면, 현대의 애플리케이션은 복잡하고 다양한 리소스를 사용합니다.
예를 들어, 비디오 스트리밍 서비스는 CPU와 네트워크 대역폭이 중요하고, 머신러닝 추론 서버는 GPU와 메모리가 핵심입니다. 단일 메트릭으로는 이런 복잡한 상황을 제대로 반영할 수 없습니다.
기존에는 CPU 사용률만 보고 스케일링했다면, 이제는 CPU, 메모리, 그리고 애플리케이션 특화 메트릭(예: 요청 큐 길이, 응답 시간)을 모두 고려하여 더 지능적으로 스케일링할 수 있습니다. 멀티 메트릭 HPA의 핵심 특징은 다음과 같습니다.
첫째, 여러 메트릭 중 가장 높은 스케일링 요구사항을 선택하여 적용합니다(OR 조건). 둘째, Resource 타입(CPU, 메모리), Pods 타입(커스텀 메트릭), Object 타입(Ingress의 QPS) 등 다양한 메트릭 소스를 지원합니다.
셋째, behavior 설정으로 스케일링 속도와 안정성을 세밀하게 제어할 수 있습니다. 이러한 특징들이 중요한 이유는 애플리케이션의 실제 부하 특성에 맞는 맞춤형 오토스케일링을 구현할 수 있기 때문입니다.
코드 예제
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: multi-metric-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api-server
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 75 # CPU 75% 목표
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80 # 메모리 80% 목표
behavior: # 스케일링 속도 제어
scaleDown:
stabilizationWindowSeconds: 300 # 5분간 안정화
policies:
- type: Percent
value: 50 # 한 번에 최대 50%만 축소
periodSeconds: 60
설명
이것이 하는 일: 이 HPA는 CPU와 메모리 두 가지 메트릭을 동시에 모니터링하면서, 더 보수적인 스케일 다운 정책을 적용하여 안정적인 오토스케일링을 구현합니다. 첫 번째로, metrics 섹션에 두 개의 Resource 타입 메트릭을 정의했습니다.
CPU는 75%, 메모리는 80%를 목표로 설정했는데, 메모리 임계값을 약간 높게 설정한 이유는 메모리 압박 상황이 CPU보다 서비스에 더 치명적이기 때문입니다. HPA는 두 메트릭을 각각 계산한 후, 더 많은 Pod을 요구하는 쪽을 선택합니다.
예를 들어 CPU 기준으로는 5개가 필요하고 메모리 기준으로는 7개가 필요하다면, 7개로 스케일링합니다. 두 번째로, behavior 섹션에서 스케일 다운의 동작을 세밀하게 제어합니다.
stabilizationWindowSeconds를 300초(5분)로 설정하여, 일시적인 부하 감소에 즉시 반응하지 않고 5분간 지켜본 후에 스케일 다운을 결정합니다. 이렇게 하는 이유는 부하가 다시 증가할 때 Pod을 재시작하는 오버헤드를 줄이고, 서비스 안정성을 높이기 위함입니다.
세 번째로, policies 섹션의 Percent 타입 정책은 한 번의 스케일 다운에서 현재 Pod 개수의 최대 50%만 줄이도록 제한합니다. 예를 들어 현재 10개의 Pod이 실행 중이라면, 한 번에 최대 5개까지만 줄일 수 있고, 나머지는 다음 주기에서 처리됩니다.
이는 급격한 스케일 다운으로 인한 서비스 불안정을 방지합니다. 네 번째로, 스케일 업에 대한 behavior 설정이 없다는 점에 주목하세요.
이는 의도적인 것으로, 스케일 업은 기본 설정(빠르고 공격적)을 사용하여 부하 증가에 신속하게 대응하고, 스케일 다운만 보수적으로 처리하는 전략입니다. 여러분이 이 설정을 사용하면 애플리케이션의 실제 리소스 사용 패턴을 더 정확하게 반영하여, CPU만 봤을 때 놓칠 수 있는 메모리 부족 상황도 사전에 감지하고 대응할 수 있습니다.
또한 안정화 기간과 점진적 스케일 다운 정책 덕분에 불필요한 Pod 재시작을 줄여 전체적인 서비스 안정성이 향상되고, 사용자는 더 일관된 응답 시간을 경험하게 됩니다.
실전 팁
💡 메모리 메트릭을 사용할 때는 반드시 애플리케이션이 메모리를 해제할 수 있는지 확인하세요. Java 같은 GC 언어는 메모리 사용률이 쉽게 내려가지 않아서 스케일 다운이 어려울 수 있습니다. 이 경우 메모리보다는 커스텀 메트릭(예: 힙 사용률)을 사용하는 것이 더 효과적입니다.
💡 stabilizationWindowSeconds는 애플리케이션의 트래픽 패턴에 맞게 조정하세요. 트래픽 변동이 심한 서비스는 300초(5분) 이상으로, 안정적인 서비스는 180초(3분) 정도가 적절합니다.
💡 여러 메트릭을 사용할 때는 각 메트릭의 우선순위를 고려하세요. HPA는 OR 조건으로 동작하므로, 너무 많은 메트릭을 추가하면 항상 스케일 업 상태가 될 수 있습니다. 핵심 메트릭 2-3개만 선택하는 것이 좋습니다.
💡 kubectl describe hpa 명령어로 어떤 메트릭이 현재 스케일링을 주도하고 있는지 확인할 수 있습니다. Events 섹션에서 "New size: X; reason: cpu resource utilization above target" 같은 메시지를 통해 스케일링 이유를 추적할 수 있습니다.
💡 프로덕션에 적용하기 전에 모니터링 도구(Prometheus, Grafana)로 실제 메트릭 값을 며칠간 관찰하고, 적절한 임계값을 설정하세요. 처음부터 완벽한 값을 찾기는 어렵고, 실제 데이터 기반으로 점진적으로 튜닝하는 것이 중요합니다.
3. VPA 개념과 활용
시작하며
여러분이 서비스를 운영하면서 Pod의 CPU/메모리 requests를 처음에 대충 설정했더니, 어떤 Pod은 리소스가 남아돌아 낭비되고, 어떤 Pod은 OOMKilled로 계속 재시작되는 상황을 겪어본 적 있나요? requests와 limits를 정확히 설정하는 것은 생각보다 훨씬 어렵습니다.
이런 문제는 특히 마이크로서비스 아키텍처에서 심각합니다. 수십 개의 서비스가 있고, 각 서비스의 리소스 사용 패턴이 다르며, 시간이 지나면서 코드 변경에 따라 리소스 요구사항도 계속 변합니다.
개발자가 일일이 모니터링하면서 requests 값을 조정하는 것은 거의 불가능에 가깝습니다. 바로 이럴 때 필요한 것이 VPA(Vertical Pod Autoscaler)입니다.
VPA는 실제 리소스 사용 패턴을 학습하여 자동으로 최적의 requests와 limits 값을 추천하거나 적용해줍니다. 이를 통해 리소스 효율성을 극대화하면서도 안정성을 유지할 수 있습니다.
개요
간단히 말해서, VPA는 Pod의 CPU와 메모리 requests/limits 값을 실제 사용 패턴에 맞춰 자동으로 조정하는 Kubernetes 컴포넌트입니다. HPA가 Pod 개수를 조절한다면, VPA는 각 Pod의 크기를 조절합니다.
왜 이 개념이 필요한지 실무 관점에서 설명하자면, 리소스 requests를 너무 낮게 설정하면 노드의 실제 리소스가 부족해져 성능 저하나 Pod 퇴출이 발생하고, 너무 높게 설정하면 노드의 리소스가 남아돌아 클라우드 비용이 낭비됩니다. 예를 들어, 배치 처리 서비스는 처리 데이터 크기에 따라 메모리 요구량이 크게 달라지는데, 최악의 경우에 맞춰 requests를 설정하면 평소에는 90%의 리소스가 낭비됩니다.
기존에는 개발자가 부하 테스트를 하거나 프로덕션 메트릭을 수동으로 분석해서 requests 값을 정했다면, 이제는 VPA가 히스토리 데이터를 기반으로 통계적으로 최적값을 계산하고 자동으로 적용합니다. VPA의 핵심 특징은 세 가지입니다.
첫째, 세 가지 업데이트 모드(Off, Initial, Auto)를 제공하여 자동화 수준을 선택할 수 있습니다. Off는 추천만 하고, Initial은 Pod 생성 시에만 적용하며, Auto는 실행 중에도 자동으로 적용합니다.
둘째, 실제 사용량의 히스토리를 분석하여 95 퍼센타일 같은 통계적 기법으로 안정적인 값을 추천합니다. 셋째, 최소/최대 범위를 설정하여 VPA의 추천 값이 너무 극단적으로 가지 않도록 제어할 수 있습니다.
이러한 특징들이 중요한 이유는 수동 관리의 부담을 줄이면서도 리소스 효율성과 안정성을 동시에 달성할 수 있기 때문입니다.
코드 예제
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: backend-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: backend-api
updatePolicy:
updateMode: "Auto" # Off, Initial, Auto 중 선택
resourcePolicy:
containerPolicies:
- containerName: "*"
minAllowed: # 최소 리소스
cpu: 100m
memory: 128Mi
maxAllowed: # 최대 리소스
cpu: 2
memory: 2Gi
controlledResources: ["cpu", "memory"]
설명
이것이 하는 일: VPA는 'backend-api' Deployment의 모든 Container에 대해 실제 리소스 사용량을 모니터링하고, 통계적 분석을 통해 최적의 requests 값을 계산한 후, Auto 모드에서는 Pod을 재시작하면서 새로운 값을 적용합니다. 첫 번째로, targetRef에서 모니터링할 대상을 지정합니다.
VPA는 이 Deployment의 모든 Pod에 대해 Metrics Server에서 리소스 사용 데이터를 수집하고, 보통 지난 8일간의 데이터를 분석하여 추천값을 계산합니다. 충분한 히스토리 데이터가 있어야 정확한 추천이 가능하므로, VPA를 적용한 직후보다는 며칠 후의 추천값이 더 신뢰할 수 있습니다.
두 번째로, updatePolicy의 updateMode가 VPA의 동작 방식을 결정합니다. "Off"는 추천값만 제공하고 적용하지 않아서 처음 테스트할 때 유용하고, "Initial"은 새로 생성되는 Pod에만 적용하여 기존 Pod을 재시작하지 않으며, "Auto"는 필요할 때 Pod을 재시작하면서 새 값을 적용합니다.
Auto 모드는 가장 강력하지만 Pod 재시작이 발생하므로, 중단 없는 서비스를 위해서는 충분한 복제본과 PodDisruptionBudget을 함께 사용해야 합니다. 세 번째로, resourcePolicy에서 VPA의 추천값에 제약을 설정합니다.
minAllowed와 maxAllowed는 안전 장치로, VPA가 아무리 낮은/높은 값을 추천하더라도 이 범위를 벗어나지 않습니다. 예를 들어 VPA가 50m CPU를 추천하더라도 minAllowed가 100m이면 100m가 적용되고, 4GB 메모리를 추천하더라도 maxAllowed가 2Gi면 2Gi가 적용됩니다.
이는 비정상적인 추천값으로 인한 문제를 방지합니다. 네 번째로, containerName을 "*"로 설정하여 모든 Container에 동일한 정책을 적용했지만, 실무에서는 Container별로 다른 정책을 적용할 수도 있습니다.
예를 들어 메인 애플리케이션 Container는 Auto 모드로, 사이드카 Container는 Initial 모드로 다르게 설정할 수 있습니다. 여러분이 VPA를 사용하면 개발자가 requests 값을 추측하거나 수동으로 튜닝하는 시간을 크게 절약할 수 있습니다.
특히 마이크로서비스 환경에서 수십 개의 서비스를 관리할 때, VPA가 각 서비스의 최적값을 자동으로 찾아주므로 운영 부담이 획기적으로 줄어듭니다. 또한 리소스를 실제 필요량에 맞춰 정확히 할당하여 클라우드 비용을 20-30% 절감하는 효과를 기대할 수 있으며, OOMKilled 같은 리소스 부족 문제도 사전에 방지할 수 있습니다.
실전 팁
💡 처음 VPA를 도입할 때는 반드시 updateMode: "Off"로 시작하세요. 일주일 정도 추천값을 모니터링한 후, 값이 합리적인지 확인하고 나서 "Initial"이나 "Auto"로 변경하는 것이 안전합니다.
💡 VPA와 HPA를 동시에 사용할 때는 주의가 필요합니다. CPU 메트릭을 동시에 사용하면 서로 충돌할 수 있으므로, HPA는 커스텀 메트릭을 사용하거나, VPA는 메모리만 관리하도록 설정하세요.
💡 Stateful 애플리케이케이션(데이터베이스 등)에는 VPA의 Auto 모드를 사용할 때 각별히 주의하세요. Pod 재시작이 데이터 정합성에 영향을 줄 수 있으므로, Initial 모드를 사용하거나 수동으로 점진적 롤아웃을 하는 것이 더 안전합니다.
💡 kubectl describe vpa 명령어로 현재 추천값을 확인할 수 있습니다. Lower Bound, Target, Upper Bound 세 가지 값이 표시되는데, Target이 실제로 적용되는 requests 값이고, Lower/Upper Bound는 스케일링 범위를 나타냅니다.
💡 VPA는 Metrics Server가 필수입니다. VPA를 설치하기 전에 kubectl top nodes와 kubectl top pods가 정상 작동하는지 확인하세요. Metrics Server가 없으면 VPA가 데이터를 수집할 수 없습니다.
4. Cluster Autoscaler
시작하며
여러분이 HPA로 Pod을 계속 늘리는데, 어느 순간부터 새로운 Pod이 Pending 상태로 멈춰있고 "Insufficient cpu" 에러가 발생하는 상황을 겪어본 적 있나요? 이는 클러스터의 모든 노드 리소스가 소진되어 더 이상 Pod을 배치할 공간이 없기 때문입니다.
이런 문제는 특히 트래픽이 급증하는 이벤트 기간에 치명적입니다. HPA가 아무리 빠르게 Pod을 생성해도 노드 용량이 부족하면 실제로 실행되지 못하고, 결국 서비스 장애로 이어집니다.
반대로 트래픽이 줄었을 때는 비어있는 노드가 계속 실행되면서 불필요한 비용이 발생합니다. 바로 이럴 때 필요한 것이 Cluster Autoscaler입니다.
Cluster Autoscaler는 Pod의 스케줄링 상태를 모니터링하면서 필요할 때 자동으로 노드를 추가하고, 불필요한 노드를 제거하여 클러스터 용량을 최적화합니다.
개요
간단히 말해서, Cluster Autoscaler는 Pending 상태의 Pod을 감지하여 자동으로 노드를 추가하고, 활용도가 낮은 노드를 감지하여 자동으로 제거하는 Kubernetes의 클러스터 수준 오토스케일링 솔루션입니다. 왜 이 개념이 필요한지 실무 관점에서 설명하자면, HPA와 VPA는 Pod 레벨에서만 작동하므로 클러스터 전체 용량이 부족하면 무용지물이 됩니다.
예를 들어, 블랙프라이데이 세일 같은 대규모 이벤트 때는 평소보다 10배의 Pod이 필요할 수 있는데, 이를 수용할 노드가 없으면 HPA가 제대로 작동할 수 없습니다. Cluster Autoscaler는 이런 상황에서 자동으로 노드를 확장하여 원활한 서비스 운영을 보장합니다.
기존에는 인프라 팀이 예상 부하를 기반으로 노드 수를 수동으로 조절하거나, 최악의 경우를 대비해 항상 많은 노드를 유지했다면, 이제는 Cluster Autoscaler가 실시간 수요에 맞춰 노드를 동적으로 관리합니다. Cluster Autoscaler의 핵심 특징은 다음과 같습니다.
첫째, 클라우드 프로바이더(AWS, GCP, Azure)의 Auto Scaling Group과 통합되어 실제 VM 인스턴스를 생성/삭제합니다. 둘째, 노드 추가는 빠르게(수 분 이내), 노드 제거는 신중하게(10분 이상 활용도 낮은 상태 유지 시) 처리하여 안정성을 확보합니다.
셋째, PodDisruptionBudget과 노드의 Annotation을 존중하여 중요한 Pod이 실행 중인 노드는 제거하지 않습니다. 이러한 특징들이 중요한 이유는 완전히 자동화된 인프라 관리를 통해 개발자가 비즈니스 로직에만 집중할 수 있게 해주기 때문입니다.
코드 예제
apiVersion: apps/v1
kind: Deployment
metadata:
name: cluster-autoscaler
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app: cluster-autoscaler
template:
metadata:
labels:
app: cluster-autoscaler
spec:
serviceAccountName: cluster-autoscaler
containers:
- image: k8s.gcr.io/autoscaling/cluster-autoscaler:v1.27.0
name: cluster-autoscaler
command:
- ./cluster-autoscaler
- --cloud-provider=aws # 클라우드 프로바이더
- --namespace=kube-system
- --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled
- --balance-similar-node-groups
- --skip-nodes-with-system-pods=false
- --scale-down-delay-after-add=10m # 노드 추가 후 10분간 스케일 다운 방지
- --scale-down-unneeded-time=10m # 10분간 불필요 시 제거
설명
이것이 하는 일: Cluster Autoscaler는 주기적으로(기본 10초마다) 클러스터 상태를 확인하여, 스케줄링되지 못한 Pod이 있으면 노드를 추가하고, 활용도가 50% 이하로 10분 이상 유지된 노드는 제거합니다. 첫 번째로, --cloud-provider 옵션이 어떤 클라우드 환경인지 지정합니다.
AWS를 사용하는 경우, Cluster Autoscaler는 AWS의 Auto Scaling Group(ASG) API를 호출하여 실제 EC2 인스턴스를 생성하거나 종료합니다. 이를 위해서는 적절한 IAM 권한이 필요하며, 노드의 인스턴스 프로파일에 ASG를 수정할 수 있는 권한이 부여되어야 합니다.
두 번째로, --node-group-auto-discovery 옵션은 어떤 ASG를 관리할지 자동으로 발견합니다. 여기서는 "k8s.io/cluster-autoscaler/enabled" 태그가 있는 ASG를 자동으로 찾습니다.
실무에서는 여러 ASG를 만들어서 워커 노드 타입을 분리하는데(예: 일반 워크로드용, GPU용, 메모리 최적화용), 이 옵션을 사용하면 수동으로 ASG 이름을 지정하지 않아도 자동으로 관리할 수 있습니다. 세 번째로, --scale-down-delay-after-add는 새 노드가 추가된 후 일정 시간 동안 스케일 다운을 방지합니다.
10분으로 설정한 이유는 새로운 노드에 Pod이 배치되고 안정화되는 시간을 주기 위함입니다. 만약 이 값이 너무 짧으면 노드가 추가되자마자 다시 제거되는 플래핑(flapping) 현상이 발생할 수 있습니다.
네 번째로, --scale-down-unneeded-time은 노드가 불필요한 상태로 얼마나 오래 유지되어야 제거 대상이 되는지 설정합니다. 10분으로 설정하여, 일시적인 부하 감소에는 반응하지 않고 지속적으로 활용도가 낮을 때만 노드를 제거합니다.
이 값을 너무 짧게 설정하면 비용은 절감되지만 노드 추가/제거가 빈번해져 불안정할 수 있고, 너무 길게 설정하면 불필요한 비용이 발생합니다. 다섯 번째로, --balance-similar-node-groups 옵션은 여러 가용 영역(AZ)에 걸쳐 비슷한 타입의 노드 그룹이 있을 때, 노드를 균등하게 분산합니다.
이는 고가용성을 위해 중요한데, 한 AZ에 장애가 발생해도 다른 AZ의 노드에서 서비스를 계속할 수 있습니다. 여러분이 Cluster Autoscaler를 사용하면 더 이상 트래픽 패턴을 예측하고 수동으로 노드를 조정할 필요가 없습니다.
새벽에 갑자기 트래픽이 급증해도 자동으로 노드가 추가되어 서비스를 안정적으로 유지하고, 주말에 트래픽이 줄면 자동으로 노드를 제거하여 비용을 절감합니다. 실제 사례에서 Cluster Autoscaler 도입 후 인프라 비용이 30-40% 감소하면서도 서비스 가용성은 오히려 향상된 경우가 많습니다.
실전 팁
💡 Cluster Autoscaler와 클라우드 프로바이더의 ASG 설정을 동시에 조정하지 마세요. ASG의 min/max 설정을 변경하면 Cluster Autoscaler가 이를 자동으로 인식하므로, Cluster Autoscaler를 재배포할 필요 없습니다.
💡 중요한 시스템 Pod(DNS, metrics-server 등)에는 PriorityClass를 높게 설정하세요. Cluster Autoscaler는 높은 우선순위 Pod이 Pending 상태면 더 빠르게 노드를 추가합니다.
💡 노드에 "cluster-autoscaler.kubernetes.io/scale-down-disabled=true" Annotation을 추가하면 해당 노드는 절대 제거되지 않습니다. 중요한 데이터베이스나 모니터링 Pod이 실행되는 노드에 유용합니다.
💡 Cluster Autoscaler 로그를 주기적으로 확인하세요. "scale-up failed" 같은 에러는 IAM 권한 문제나 ASG의 max 설정 문제일 수 있습니다. kubectl logs -n kube-system deployment/cluster-autoscaler 명령어로 상세 로그를 볼 수 있습니다.
💡 프로덕션 환경에서는 Cluster Autoscaler를 여러 개의 독립적인 노드 그룹(일반, GPU, 메모리 최적화 등)과 함께 사용하세요. Pod의 nodeSelector나 Affinity를 통해 적절한 노드 그룹을 선택하면, Cluster Autoscaler가 해당 그룹의 노드만 추가하여 비용 효율성을 극대화할 수 있습니다.
5. Custom Metrics 오토스케일링
시작하며
여러분이 메시지 큐를 사용하는 워커 애플리케이션을 운영하는데, CPU와 메모리는 여유로운데 큐에 메시지가 쌓이면서 처리 지연이 발생하는 상황을 겪어본 적 있나요? 이럴 때 CPU 기반 HPA는 문제를 전혀 감지하지 못하고, 사용자는 느린 응답에 불만을 느끼게 됩니다.
이런 문제는 비즈니스 로직의 특성에 따라 다양하게 나타납니다. 메시지 큐의 길이, API의 응답 시간, 데이터베이스 연결 풀 사용률, 동시 요청 수 등은 모두 서비스 품질에 직접적인 영향을 주지만, CPU/메모리 메트릭으로는 포착할 수 없습니다.
바로 이럴 때 필요한 것이 Custom Metrics 기반 오토스케일링입니다. Prometheus 같은 모니터링 시스템에서 수집한 비즈니스 메트릭을 HPA에서 직접 사용하여, 실제 서비스 품질에 직결된 지표로 스케일링할 수 있습니다.
개요
간단히 말해서, Custom Metrics 오토스케일링은 HPA가 CPU/메모리를 넘어 Prometheus 메트릭, 애플리케이션 메트릭, 외부 서비스 메트릭 등 임의의 메트릭을 기반으로 스케일링할 수 있게 해주는 강력한 확장 기능입니다. 왜 이 개념이 필요한지 실무 관점에서 설명하자면, 현대의 클라우드 네이티브 애플리케이션은 단순한 CPU 사용량보다는 비즈니스 메트릭이 더 중요합니다.
예를 들어, RabbitMQ 워커는 큐의 메시지 개수가 100개를 넘으면 처리 속도가 느려지는데, 이는 CPU 사용률과는 무관할 수 있습니다. 또한 API 게이트웨이는 초당 요청 수(RPS)가 중요한 지표이고, 머신러닝 추론 서버는 추론 지연 시간이 핵심 메트릭입니다.
기존에는 CPU/메모리만으로 스케일링하거나, 외부 스크립트를 만들어서 수동으로 스케일링했다면, 이제는 Prometheus Adapter 같은 도구를 통해 Prometheus 메트릭을 Kubernetes Metrics API로 노출하고, HPA에서 직접 사용할 수 있습니다. Custom Metrics 오토스케일링의 핵심 특징은 다음과 같습니다.
첫째, Pods 타입 메트릭(Pod별 메트릭)과 Object 타입 메트릭(Ingress, Service 같은 오브젝트의 메트릭)을 모두 지원합니다. 둘째, Prometheus, Datadog, New Relic 등 다양한 모니터링 시스템과 통합할 수 있습니다.
셋째, 비즈니스 로직에 특화된 메트릭을 사용하여 더 정확하고 의미 있는 스케일링을 구현할 수 있습니다. 이러한 특징들이 중요한 이유는 애플리케이션의 실제 성능과 사용자 경험에 직결된 지표로 오토스케일링을 수행할 수 있기 때문입니다.
코드 예제
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: rabbitmq-consumer-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: rabbitmq-consumer
minReplicas: 2
maxReplicas: 15
metrics:
- type: Pods # Pod별 메트릭
pods:
metric:
name: rabbitmq_queue_messages_ready # Prometheus 메트릭 이름
target:
type: AverageValue
averageValue: "30" # Pod당 평균 30개 메시지 목표
- type: Object # 오브젝트 메트릭
object:
metric:
name: http_requests_per_second
describedObject:
apiVersion: v1
kind: Service
name: api-service
target:
type: Value
value: "1000" # 서비스 전체 초당 1000 요청 목표
설명
이것이 하는 일: 이 HPA는 Prometheus에서 수집한 RabbitMQ 큐 메시지 개수와 HTTP 요청 수를 실시간으로 모니터링하면서, 각 메트릭의 목표값을 유지하기 위해 Pod 개수를 동적으로 조절합니다. 첫 번째로, Pods 타입 메트릭을 사용하여 각 Pod이 처리해야 할 평균 메시지 개수를 30개로 제한합니다.
Prometheus Adapter가 'rabbitmq_queue_messages_ready' 메트릭을 Kubernetes Metrics API로 노출하면, HPA는 이를 읽어서 현재 큐의 총 메시지 개수를 현재 Pod 수로 나눈 값을 계산합니다. 예를 들어 큐에 300개의 메시지가 있고 현재 5개의 Pod이 실행 중이라면, Pod당 평균 60개가 되어 목표치인 30개를 초과하므로, HPA는 10개로 스케일 업합니다.
이렇게 하면 각 워커가 과부하 없이 안정적으로 메시지를 처리할 수 있습니다. 두 번째로, Object 타입 메트릭을 사용하여 서비스 전체의 HTTP 요청 수를 모니터링합니다.
이는 특정 Pod이 아닌 'api-service'라는 Service 오브젝트에 대한 메트릭으로, 모든 Pod으로 들어오는 총 요청 수를 나타냅니다. 초당 1000개 요청을 목표로 설정했는데, 만약 실제 요청 수가 2000개라면 HPA는 Pod을 두 배로 늘립니다.
이 방식은 API 게이트웨이나 로드밸런서 앞단에서 측정한 메트릭을 사용할 때 유용합니다. 세 번째로, 두 개의 서로 다른 타입의 메트릭을 동시에 사용했다는 점이 중요합니다.
HPA는 각 메트릭별로 필요한 Pod 개수를 계산한 후, 가장 높은 값을 선택합니다. 예를 들어 RabbitMQ 메트릭 기준으로는 8개가 필요하고, HTTP 요청 메트릭 기준으로는 12개가 필요하다면, 12개로 스케일링합니다.
이는 모든 메트릭의 요구사항을 만족시키기 위함입니다. 네 번째로, 이 설정이 작동하려면 사전에 Prometheus Adapter를 설치하고, Prometheus에서 해당 메트릭을 수집하도록 구성해야 합니다.
Prometheus Adapter의 설정 파일에서 어떤 Prometheus 메트릭을 어떤 이름으로 Kubernetes에 노출할지 정의해야 하며, 이 과정이 다소 복잡하지만 한 번 설정하면 모든 HPA에서 재사용할 수 있습니다. 여러분이 Custom Metrics 오토스케일링을 사용하면 CPU/메모리 같은 간접 지표가 아닌, 실제 비즈니스 영향을 주는 직접 지표로 스케일링할 수 있습니다.
메시지 큐가 쌓이기 시작하면 즉시 워커를 늘려서 지연을 방지하고, API 요청이 급증하면 빠르게 서버를 추가하여 응답 시간을 유지하며, 트래픽이 줄면 자동으로 리소스를 회수하여 비용을 절감합니다. 실제로 Custom Metrics를 도입한 후 서비스 응답 시간이 50% 개선되고, 사용자 만족도가 크게 향상된 사례가 많습니다.
실전 팁
💡 Prometheus Adapter를 설치하기 전에 Prometheus가 이미 해당 메트릭을 수집하고 있는지 확인하세요. Prometheus UI에서 메트릭을 쿼리해보고, 정상적인 값이 나오는지 테스트한 후에 Adapter를 설정하는 것이 디버깅을 훨씬 쉽게 만듭니다.
💡 Custom Metrics의 이름 규칙이 중요합니다. Prometheus Adapter는 메트릭 이름을 변환할 때 특정 규칙을 따르므로, Adapter의 설정과 HPA의 메트릭 이름이 정확히 일치해야 합니다. kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1" 명령어로 현재 노출된 메트릭 목록을 확인할 수 있습니다.
💡 Custom Metrics의 값이 0이 되는 상황을 고려하세요. 예를 들어 큐가 완전히 비면 메트릭 값이 0이 되어 HPA가 minReplicas까지 스케일 다운합니다. 이것이 의도한 동작인지, 아니면 최소한의 워커를 항상 유지해야 하는지 비즈니스 요구사항을 명확히 하세요.
💡 External Metrics도 고려하세요. Custom Metrics는 클러스터 내부 메트릭을 대상으로 하지만, External Metrics는 AWS CloudWatch, Azure Monitor 같은 외부 시스템의 메트릭을 직접 사용할 수 있습니다. SQS 큐 길이, DynamoDB 스로틀링 비율 같은 관리형 서비스 메트릭을 사용할 때 유용합니다.
💡 메트릭의 지연 시간을 고려하여 스케일링 정책을 설정하세요. Prometheus는 보통 15-30초 스크랩 간격을 사용하고, Prometheus Adapter도 캐시를 사용하므로, 실제 부하 변화와 HPA의 반응 사이에 1-2분의 지연이 있을 수 있습니다. 급격한 트래픽 변화가 예상되면 더 보수적인(낮은) 임계값을 설정하세요.
6. 오토스케일링 모니터링
시작하며
여러분이 HPA를 설정했는데, 트래픽이 급증했을 때 스케일링이 예상보다 느리거나, 때로는 전혀 작동하지 않는 상황을 겪어본 적 있나요? 오토스케일링을 설정하는 것만으로는 충분하지 않고, 실제로 제대로 작동하는지 지속적으로 모니터링하고 튜닝해야 합니다.
이런 문제는 프로덕션 환경에서 매우 흔합니다. HPA가 메트릭을 제대로 읽지 못하거나, 스케일링 쿨다운 시간 때문에 반응이 느리거나, 노드 리소스 부족으로 Pod이 Pending 상태로 남아있을 수 있습니다.
이런 상황을 사전에 감지하고 대응하지 못하면 서비스 장애로 이어집니다. 바로 이럴 때 필요한 것이 체계적인 오토스케일링 모니터링입니다.
Kubernetes Events, Metrics, 그리고 모니터링 도구를 활용하여 스케일링 동작을 실시간으로 추적하고, 문제를 조기에 발견하며, 최적의 설정값을 찾아낼 수 있습니다.
개요
간단히 말해서, 오토스케일링 모니터링은 HPA, VPA, Cluster Autoscaler의 동작을 실시간으로 관찰하고, 스케일링 이벤트를 추적하며, 메트릭 이상을 감지하여 오토스케일링이 항상 정상적으로 작동하도록 보장하는 필수적인 운영 활동입니다. 왜 이 개념이 필요한지 실무 관점에서 설명하자면, 오토스케일링은 복잡한 시스템이고 많은 변수가 있습니다.
예를 들어, Metrics Server가 다운되면 HPA가 메트릭을 읽을 수 없어 스케일링이 멈추고, Cluster Autoscaler가 IAM 권한 문제로 노드를 추가하지 못할 수 있으며, VPA의 추천값이 실제 요구사항과 맞지 않을 수 있습니다. 이런 문제들은 모니터링 없이는 발견하기 어렵습니다.
기존에는 문제가 발생한 후에 로그를 뒤지면서 원인을 찾았다면, 이제는 Prometheus로 메트릭을 수집하고, Grafana로 시각화하며, Alertmanager로 이상 징후를 실시간으로 알림받아 사전에 대응할 수 있습니다. 오토스케일링 모니터링의 핵심 특징은 다음과 같습니다.
첫째, Kubernetes Events를 통해 스케일링 결정의 이유와 타이밍을 추적할 수 있습니다. 둘째, kube-state-metrics를 사용하여 HPA의 현재 상태, 목표 메트릭, 실제 메트릭을 Prometheus로 수집할 수 있습니다.
셋째, Grafana 대시보드로 시계열 데이터를 시각화하여 스케일링 패턴과 이상 징후를 쉽게 파악할 수 있습니다. 이러한 특징들이 중요한 이유는 오토스케일링이 블랙박스가 아닌 투명하고 예측 가능한 시스템이 되어, 신뢰도 높은 프로덕션 운영이 가능하기 때문입니다.
코드 예제
# Prometheus에서 HPA 메트릭을 수집하는 PromQL 쿼리 예시
# HPA의 현재 복제본 수
kube_horizontalpodautoscaler_status_current_replicas{horizontalpodautoscaler="web-app-hpa"}
# HPA의 목표 복제본 수
kube_horizontalpodautoscaler_status_desired_replicas{horizontalpodautoscaler="web-app-hpa"}
# HPA가 사용하는 메트릭의 현재 값
kube_horizontalpodautoscaler_status_current_metrics_value{horizontalpodautoscaler="web-app-hpa"}
# 스케일링 비율 (현재/목표)
kube_horizontalpodautoscaler_status_current_replicas / kube_horizontalpodautoscaler_status_desired_replicas
# Cluster Autoscaler 노드 수
sum(kube_node_info)
# Pending 상태 Pod 수 (스케일링 병목 감지)
count(kube_pod_status_phase{phase="Pending"})
설명
이것이 하는 일: 이 PromQL 쿼리들은 kube-state-metrics가 노출한 HPA 메트릭을 Prometheus에서 조회하여, 오토스케일링의 현재 상태와 동작을 실시간으로 파악할 수 있게 해줍니다. 첫 번째로, kube_horizontalpodautoscaler_status_current_replicas는 HPA가 현재 관리하고 있는 실제 Pod 개수를 나타냅니다.
이 값이 시간에 따라 어떻게 변하는지 관찰하면 스케일링 패턴을 이해할 수 있습니다. 예를 들어 매일 오전 9시에 급증한다면, 출근 시간대에 사용자 트래픽이 몰린다는 것을 알 수 있고, 이를 기반으로 스케일링 정책을 최적화할 수 있습니다.
두 번째로, desired_replicas와 current_replicas를 비교하여 스케일링 지연을 감지할 수 있습니다. 정상적인 경우 두 값은 거의 일치해야 하지만, desired가 10인데 current가 5라면 Pod이 생성되지 못하고 있다는 신호입니다.
이는 노드 리소스 부족, 이미지 Pull 실패, PodDisruptionBudget 제약 등 다양한 원인이 있을 수 있으며, kubectl get events와 함께 분석하면 정확한 원인을 찾을 수 있습니다. 세 번째로, current_metrics_value는 HPA가 스케일링 결정에 사용하는 메트릭의 실제 값입니다.
이 값이 목표치(target)와 어떻게 비교되는지 시각화하면, HPA가 왜 스케일 업 또는 다운을 결정했는지 이해할 수 있습니다. 예를 들어 CPU 목표가 70%인데 current_metrics_value가 90%라면, HPA는 스케일 업을 시도하고 있을 것입니다.
네 번째로, 스케일링 비율(current/desired)을 계산하여 1이 아닌 경우를 알림으로 설정할 수 있습니다. 이 비율이 1보다 작으면 스케일 업이 진행 중이거나 막혀있다는 의미이고, 1보다 크면(드물지만) 스케일 다운이 진행 중입니다.
이 값이 5분 이상 1이 아니라면 문제가 있는 것이므로, Alertmanager로 알림을 받을 수 있습니다. 다섯 번째로, Pending 상태의 Pod 개수를 모니터링하는 것이 매우 중요합니다.
Pending Pod이 계속 증가한다면 Cluster Autoscaler가 제대로 작동하지 않거나, 노드가 최대 개수에 도달했거나, 특정 리소스(GPU 등)가 부족하다는 신호입니다. 이 메트릭으로 알림을 설정하면 인프라 병목을 조기에 발견할 수 있습니다.
여러분이 이런 모니터링을 구축하면 오토스케일링이 투명하게 작동하여, 언제 어떻게 스케일링이 일어나는지 명확히 알 수 있습니다. 문제가 발생했을 때 즉시 알림을 받아 대응할 수 있고, 히스토리 데이터를 분석하여 스케일링 정책을 계속 개선할 수 있습니다.
실제로 체계적인 모니터링을 도입한 후 평균 장애 대응 시간이 70% 단축되고, 불필요한 스케일링으로 인한 비용 낭비를 30% 줄인 사례가 많습니다.
실전 팁
💡 Grafana 대시보드를 만들 때는 메트릭만이 아니라 Kubernetes Events도 함께 표시하세요. Grafana의 Kubernetes Events 플러그인을 사용하면 "Scaled up to 10" 같은 이벤트를 메트릭 그래프와 함께 볼 수 있어, 스케일링 결정의 맥락을 이해하기 쉽습니다.
💡 알림 임계값을 설정할 때는 false positive를 줄이기 위해 "for" 조건을 사용하세요. 예를 들어 "Pending Pod이 5분 이상 존재할 때만 알림"으로 설정하면, 일시적인 Pending 상태(정상적인 스케일 업 중)에는 알림을 받지 않습니다.
💡 HPA의 Conditions 필드를 모니터링하세요. kubectl get hpa -o yaml에서 status.conditions를 보면 "AbleToScale: False" 같은 상태를 확인할 수 있는데, 이는 HPA가 스케일링을 시도했지만 실패했다는 의미입니다. kube-state-metrics도 이 정보를 노출하므로 Prometheus 알림을 설정할 수 있습니다.
💡 주기적으로(예: 매주) HPA와 VPA의 추천값을 리뷰하세요. VPA의 Recommendation을 확인하여 현재 requests 설정이 적절한지 점검하고, HPA의 스케일링 히스토리를 분석하여 min/max 범위나 목표 메트릭을 조정할 기회를 찾으세요.
💡 비용 메트릭도 함께 모니터링하세요. Kubecost 같은 도구를 사용하면 각 HPA가 관리하는 Deployment의 시간별 비용을 추적할 수 있습니다. 스케일링이 비용에 미치는 영향을 가시화하면, 과도한 스케일 업을 방지하고 비용 최적화 기회를 발견할 수 있습니다.
7. 오토스케일링 최적화 전략
시작하며
여러분이 오토스케일링을 설정했는데, 비용은 예상보다 많이 나오고, 가끔 서비스가 느려지며, 로그에는 Pod이 계속 재시작되는 메시지가 가득한 상황을 경험해본 적 있나요? 오토스케일링을 도입하는 것만으로는 부족하고, 비용과 성능의 균형을 맞추는 최적화가 필요합니다.
이런 문제는 오토스케일링의 기본 설정만으로는 해결하기 어렵습니다. 트래픽 패턴, 애플리케이션 특성, 비즈니스 요구사항에 맞춰 세밀한 튜닝이 필요합니다.
예를 들어 스케일 업은 빨라야 하지만 무분별하게 많은 Pod을 생성하면 비용이 급증하고, 스케일 다운은 비용을 절감하지만 너무 빠르면 트래픽 재증가 시 대응이 늦습니다. 바로 이럴 때 필요한 것이 체계적인 오토스케일링 최적화 전략입니다.
스케일링 속도, 안정화 기간, 메트릭 임계값, 리소스 예약 등을 종합적으로 고려하여, 서비스 품질을 유지하면서 비용을 최소화하는 최적점을 찾아낼 수 있습니다.
개요
간단히 말해서, 오토스케일링 최적화는 HPA의 behavior 설정, VPA의 리소스 정책, Cluster Autoscaler의 타이밍 파라미터를 조정하고, PodDisruptionBudget과 Resource Quotas를 활용하여 안정성, 성능, 비용의 최적 균형을 찾는 지속적인 튜닝 프로세스입니다. 왜 이 개념이 필요한지 실무 관점에서 설명하자면, 기본 설정은 일반적인 케이스를 대상으로 하므로 여러분의 특정 상황에 최적이 아닙니다.
예를 들어, 이커머스 사이트는 특정 시간대(점심, 저녁)에 트래픽이 급증하므로 사전 스케일 업이 필요하고, 뉴스 사이트는 돌발 뉴스 시 순간적으로 10배의 트래픽이 발생하므로 매우 빠른 스케일 업이 필요하며, 배치 처리 시스템은 비용이 최우선이므로 느린 스케일 업과 빠른 스케일 다운이 적절합니다. 기존에는 문제가 발생할 때마다 설정을 조금씩 바꾸는 반응적 접근을 했다면, 이제는 모니터링 데이터를 기반으로 체계적으로 최적화하는 선제적 접근을 할 수 있습니다.
오토스케일링 최적화의 핵심 특징은 다음과 같습니다. 첫째, 스케일 업과 다운에 서로 다른 정책을 적용하여 비대칭 스케일링을 구현합니다.
둘째, PodDisruptionBudget으로 스케일 다운 중에도 최소 가용성을 보장합니다. 셋째, 예측 기반 스케일링(Predictive Autoscaling)을 통해 트래픽 패턴을 학습하고 사전에 대응합니다.
넷째, Resource Quotas와 LimitRanges로 과도한 스케일링을 방지합니다. 이러한 특징들이 중요한 이유는 실무에서 요구하는 복잡하고 다양한 요구사항을 충족시킬 수 있기 때문입니다.
코드 예제
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: optimized-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web-app
minReplicas: 3
maxReplicas: 50
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
behavior:
scaleUp:
stabilizationWindowSeconds: 0 # 즉시 스케일 업
policies:
- type: Percent
value: 100 # 한 번에 최대 100% 증가 (2배)
periodSeconds: 15
- type: Pods
value: 4 # 또는 한 번에 4개 추가
periodSeconds: 15
selectPolicy: Max # 두 정책 중 더 공격적인 것 선택
scaleDown:
stabilizationWindowSeconds: 300 # 5분간 안정화
policies:
- type: Percent
value: 10 # 한 번에 최대 10%만 감소
periodSeconds: 60
selectPolicy: Min # 가장 보수적인 정책 선택
설명
이것이 하는 일: 이 최적화된 HPA는 트래픽 증가에는 즉각 반응하여 사용자 경험을 보호하고, 트래픽 감소에는 천천히 반응하여 불필요한 Pod 재시작을 방지하는 비대칭 스케일링 전략을 구현합니다. 첫 번째로, scaleUp의 stabilizationWindowSeconds를 0으로 설정하여 안정화 기간 없이 즉시 스케일 업합니다.
기본값은 0이지만 명시적으로 설정하는 것이 의도를 명확히 합니다. 트래픽 급증 시 몇 초라도 빠르게 대응하는 것이 사용자 경험에 큰 차이를 만들기 때문에, 스케일 업에서는 안정화 기간을 두지 않는 것이 일반적입니다.
두 번째로, scaleUp에 두 개의 policies를 정의하고 selectPolicy를 Max로 설정했습니다. Percent 정책은 현재 Pod 개수의 100%를 추가(즉, 2배로)하고, Pods 정책은 무조건 4개를 추가합니다.
예를 들어 현재 3개의 Pod이 실행 중이라면, Percent 정책은 3개를 추가하려 하고, Pods 정책은 4개를 추가하려 하므로, Max 정책에 의해 4개를 추가하여 총 7개가 됩니다. 만약 현재 10개라면 Percent 정책이 10개를 추가하려 하므로, 총 20개가 됩니다.
이렇게 Pod 개수가 적을 때는 절대값으로, 많을 때는 비율로 스케일링하여 모든 상황에서 적절한 반응 속도를 유지합니다. 세 번째로, scaleDown의 stabilizationWindowSeconds를 300초(5분)로 설정하여, 메트릭이 목표보다 낮아져도 5분간 지켜본 후에 스케일 다운을 결정합니다.
이는 트래픽이 일시적으로 줄었다가 다시 증가하는 패턴을 흡수하여, Pod을 줄였다가 다시 늘리는 비효율을 방지합니다. 5분은 대부분의 웹 애플리케이션에 적절하지만, 트래픽 패턴에 따라 300초에서 600초 사이로 조정할 수 있습니다.
네 번째로, scaleDown의 policies는 매우 보수적으로 설정되어, 한 번에 최대 10%만 줄이고, 60초마다 한 번씩만 평가합니다. 예를 들어 현재 20개의 Pod이 있다면, 한 번에 최대 2개만 제거하고, 1분 후에 다시 평가하여 또 2개를 제거할 수 있습니다.
이렇게 점진적으로 스케일 다운하면 트래픽이 다시 증가할 때 대응할 여유가 생기고, 서비스 안정성이 높아집니다. 다섯 번째로, selectPolicy를 스케일 업은 Max(가장 공격적), 스케일 다운은 Min(가장 보수적)으로 설정하여 비대칭 전략을 명확히 했습니다.
이는 "빠르게 확장하고, 천천히 축소"라는 클라우드 네이티브 애플리케이션의 모범 사례를 반영합니다. 여러분이 이런 최적화된 설정을 사용하면 트래픽 급증 시 사용자는 지연을 거의 느끼지 못하고, 트래픽 감소 시 불필요한 Pod 재시작으로 인한 오버헤드를 최소화할 수 있습니다.
실제 사례에서 이런 비대칭 정책을 도입한 후 평균 응답 시간이 40% 개선되고, Pod 재시작 횟수가 60% 감소하며, 전체 인프라 비용은 25% 절감된 경우가 있습니다. 무엇보다 서비스가 안정적이고 예측 가능해져서 개발자와 운영팀의 스트레스가 크게 줄어듭니다.
실전 팁
💡 PodDisruptionBudget(PDB)를 반드시 함께 사용하세요. HPA가 스케일 다운할 때 PDB가 설정되어 있으면 최소 가용 Pod 수를 보장하므로, 과도한 스케일 다운으로 인한 서비스 중단을 방지할 수 있습니다. 예: minAvailable: 50%로 설정하면 항상 절반 이상의 Pod이 실행됩니다.
💡 트래픽 패턴을 분석하여 예측 기반 스케일링을 고려하세요. Kubernetes의 기본 HPA는 반응형이지만, KEDA(Kubernetes Event-Driven Autoscaling) 같은 도구를 사용하면 시간대별로 다른 minReplicas를 설정하거나, 예정된 이벤트 전에 미리 스케일 업할 수 있습니다.
💡 애플리케이션의 시작 시간을 최적화하세요. Pod이 Ready 상태가 되기까지 오래 걸리면(예: 1분 이상), 빠른 스케일 업 정책의 효과가 반감됩니다. 컨테이너 이미지 최적화, Readiness Probe 튜닝, 애플리케이션 warm-up 최적화를 통해 시작 시간을 단축하세요.
💡 Resource Quotas를 설정하여 실수로 인한 과도한 스케일링을 방지하세요. Namespace 수준에서 최대 CPU/메모리 합계를 제한하면, HPA가 잘못 설정되어 수백 개의 Pod을 생성하려 해도 Quota에 의해 제한됩니다. 이는 클라우드 비용 폭탄을 방지하는 안전 장치입니다.
💡 정기적으로(예: 분기마다) 오토스케일링 정책을 리뷰하세요. 비즈니스가 성장하고 트래픽 패턴이 변하면 최적의 설정도 달라집니다. Grafana에서 지난 3개월의 스케일링 히스토리를 분석하고, 평균 Pod 수, 최대 Pod 수, 스케일링 빈도를 확인하여 min/max, 목표 메트릭, behavior 정책을 지속적으로 개선하세요.
8. 멀티 클러스터 오토스케일링
시작하며
여러분의 서비스가 성장하여 단일 Kubernetes 클러스터를 넘어 여러 리전, 여러 클러스터로 확장되었을 때, 각 클러스터의 오토스케일링을 개별적으로 관리하는 것이 얼마나 복잡한지 경험해본 적 있나요? 클러스터마다 다른 설정, 불균형한 리소스 사용, 일관성 없는 정책 등이 운영 부담을 기하급수적으로 증가시킵니다.
이런 문제는 글로벌 서비스나 대규모 엔터프라이즈 환경에서 필연적으로 발생합니다. 리전별로 트래픽 패턴이 다르고, 클러스터별로 리소스 용량이 다르며, 장애 발생 시 트래픽을 다른 클러스터로 재분배해야 하는 상황이 자주 발생합니다.
각 클러스터의 HPA를 수동으로 조정하는 것은 거의 불가능합니다. 바로 이럴 때 필요한 것이 멀티 클러스터 오토스케일링 전략입니다.
중앙화된 정책 관리, 클러스터 간 워크로드 분산, 페더레이션 기반 스케일링을 통해 여러 클러스터를 마치 하나의 클러스터처럼 효율적으로 관리할 수 있습니다.
개요
간단히 말해서, 멀티 클러스터 오토스케일링은 여러 Kubernetes 클러스터에 걸쳐 일관된 오토스케일링 정책을 적용하고, 클러스터 간 워크로드를 지능적으로 분산하며, 글로벌 최적화를 달성하는 고급 운영 전략입니다. 왜 이 개념이 필요한지 실무 관점에서 설명하자면, 대부분의 프로덕션 환경은 고가용성과 재해 복구를 위해 멀티 클러스터 아키텍처를 채택합니다.
예를 들어, AWS의 us-east-1과 us-west-2에 각각 클러스터를 두고, 평소에는 트래픽을 분산하다가 한 리전에 장애가 발생하면 다른 리전으로 전환합니다. 이때 각 클러스터의 오토스케일링이 독립적으로 작동하면 한 클러스터는 과부하, 다른 클러스터는 유휴 상태가 되는 비효율이 발생합니다.
기존에는 각 클러스터마다 HPA를 복사해서 배포하고, 트래픽 변화에 따라 수동으로 조정했다면, 이제는 Karmada, Kubefed 같은 페더레이션 도구나, Argo CD 같은 GitOps 도구를 사용하여 중앙에서 정책을 관리하고 자동으로 배포할 수 있습니다. 멀티 클러스터 오토스케일링의 핵심 특징은 다음과 같습니다.
첫째, Kubernetes Federation을 통해 여러 클러스터에 동일한 HPA 정책을 일관되게 배포합니다. 둘째, Global Load Balancer(예: Istio, Linkerd의 멀티 클러스터 기능)와 통합하여 클러스터 간 트래픽 분산을 최적화합니다.
셋째, 클러스터별 특성(리전별 가격, 리소스 가용성)을 고려한 지능적 워크로드 배치를 구현합니다. 넷째, 중앙화된 모니터링으로 모든 클러스터의 오토스케일링 상태를 통합 관리합니다.
이러한 특징들이 중요한 이유는 글로벌 규모의 서비스를 효율적이고 안정적으로 운영할 수 있기 때문입니다.
코드 예제
# Karmada PropagationPolicy 예시 - 여러 클러스터에 HPA 배포
apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
name: hpa-propagation
namespace: default
spec:
resourceSelectors:
- apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
name: web-app-hpa
placement:
clusterAffinity:
clusterNames:
- us-east-cluster
- us-west-cluster
- eu-central-cluster
replicaScheduling:
replicaDivisionPreference: Weighted # 가중치 기반 분배
replicaSchedulingType: Divided
weightPreference:
staticWeightList:
- targetCluster:
clusterNames:
- us-east-cluster
weight: 2 # 50% 트래픽
- targetCluster:
clusterNames:
- us-west-cluster
weight: 1 # 25% 트래픽
- targetCluster:
clusterNames:
- eu-central-cluster
weight: 1 # 25% 트래픽
설명
이것이 하는 일: 이 PropagationPolicy는 Karmada 페더레이션 컨트롤 플레인을 통해 'web-app-hpa'라는 HPA를 세 개의 클러스터에 자동으로 배포하고, 각 클러스터에 워크로드를 가중치에 따라 분산합니다. 첫 번째로, resourceSelectors에서 어떤 리소스를 페더레이션할지 지정합니다.
여기서는 HPA를 선택했지만, Deployment, Service, ConfigMap 등 모든 Kubernetes 리소스를 페더레이션할 수 있습니다. 실무에서는 HPA뿐만 아니라 Deployment와 Service도 함께 페더레이션하여 전체 애플리케이션 스택을 일관되게 배포합니다.
Karmada는 선택된 리소스를 각 멤버 클러스터에 자동으로 복제하므로, 개발자는 한 번만 kubectl apply를 실행하면 모든 클러스터에 배포됩니다. 두 번째로, placement.clusterAffinity에서 어떤 클러스터에 배포할지 정의합니다.
clusterNames로 명시적으로 지정할 수도 있고, labelSelector로 특정 레이블을 가진 클러스터를 동적으로 선택할 수도 있습니다. 예를 들어 "region: us" 레이블을 가진 모든 클러스터에 배포하도록 설정하면, 새로운 US 리전 클러스터를 추가할 때 자동으로 포함됩니다.
이는 동적으로 확장되는 인프라에서 매우 유용합니다. 세 번째로, replicaScheduling의 Weighted 전략은 클러스터별로 다른 비율의 워크로드를 배치합니다.
us-east-cluster의 가중치가 2이고 나머지가 1이므로, 총 가중치는 4이고, us-east는 50%(2/4), 나머지는 각각 25%(1/4)의 Pod을 받습니다. 예를 들어 HPA의 desiredReplicas가 20이라면, us-east에 10개, us-west에 5개, eu-central에 5개의 Pod이 배포됩니다.
이 가중치는 리전별 트래픽 비율, 리소스 가격, 데이터 레지던시 요구사항 등을 고려하여 설정합니다. 네 번째로, replicaDivisionPreference의 Weighted 모드는 동적으로 작동합니다.
HPA가 스케일링을 수행하면 Karmada가 이를 감지하고, 새로운 desiredReplicas를 가중치에 따라 재분배합니다. 예를 들어 HPA가 20에서 40으로 스케일 업하면, us-east는 10에서 20으로, us-west는 5에서 10으로 자동으로 증가합니다.
이 과정이 완전히 자동화되어 수동 개입이 필요 없습니다. 다섯 번째로, 이 설정은 클러스터 간 고가용성도 제공합니다.
한 클러스터(예: us-east)에 장애가 발생하면, Global Load Balancer가 트래픽을 나머지 클러스터로 재분배하고, 각 클러스터의 HPA가 증가한 트래픽에 맞춰 자동으로 스케일 업합니다. 장애 클러스터가 복구되면 Karmada가 워크로드를 다시 원래 비율로 재분배합니다.
여러분이 이런 멀티 클러스터 오토스케일링을 구현하면 글로벌 규모의 서비스도 단일 클러스터만큼 간단하게 관리할 수 있습니다. 중앙에서 한 번의 배포로 모든 리전에 일관된 정책을 적용하고, 리전별 트래픽 변화에 자동으로 대응하며, 장애 발생 시에도 자동으로 워크로드를 재분배하여 서비스 연속성을 보장합니다.
실제로 멀티 클러스터 오토스케일링을 도입한 후 글로벌 서비스의 가용성이 99.9%에서 99.99%로 향상되고, 운영 인력은 절반으로 줄어든 사례가 많습니다.
실전 팁
💡 멀티 클러스터 오토스케일링을 시작하기 전에 네트워크 레이턴시를 측정하세요. 클러스터 간 통신이 필요한 애플리케이션(예: 마이크로서비스)은 레이턴시에 민감하므로, 같은 리전의 여러 AZ를 먼저 시도하고, 다른 리전 확장은 신중하게 진행하세요.
💡 Karmada나 Kubefed 같은 페더레이션 도구 외에도, Argo CD의 ApplicationSet을 사용하여 여러 클러스터에 HPA를 배포할 수 있습니다. Argo CD는 GitOps 워크플로우와 잘 통합되므로, 코드 리뷰와 CI/CD 파이프라인을 통해 오토스케일링 정책을 관리할 수 있습니다.
💡 클러스터별로 다른 메트릭 소스를 사용할 수 있습니다. 예를 들어 각 리전의 Prometheus 인스턴스를 사용하여 로컬 메트릭으로 HPA를 구동하면, 페더레이션 컨트롤 플레인 장애 시에도 각 클러스터가 독립적으로 오토스케일링을 계속할 수 있습니다.
💡 Global Load Balancer의 헬스 체크와 HPA를 통합하세요. 클러스터의 Pod이 과부하 상태일 때 헬스 체크를 실패시키면, GLB가 트래픽을 다른 클러스터로 재분배하고, 해당 클러스터의 HPA가 스케일 업하는 자동화된 페일오버를 구현할 수 있습니다.
💡 멀티 클러스터 환경에서는 통합 모니터링이 필수입니다. Thanos나 Cortex를 사용하여 여러 클러스터의 Prometheus 메트릭을 중앙 집중화하고, 하나의 Grafana 대시보드에서 모든 클러스터의 오토스케일링 상태를 볼 수 있도록 구성하세요. 이렇게 하면 클러스터 간 불균형이나 이상 징후를 빠르게 발견할 수 있습니다.
댓글 (0)
함께 보면 좋은 카드 뉴스
Istio 보안 완벽 가이드
마이크로서비스 환경에서 필수적인 Istio 보안 기능을 실무 중심으로 설명합니다. mTLS부터 인증, 인가까지 단계별로 학습하여 안전한 서비스 메시를 구축할 수 있습니다.
Istio 트래픽 관리 완벽 가이드
Istio의 트래픽 관리 기능을 마스터하는 완벽 가이드입니다. VirtualService와 DestinationRule을 활용한 라우팅부터 트래픽 분할, 헤더 기반 라우팅까지 실무에 필요한 모든 내용을 다룹니다.
Istio 설치와 구성 완벽 가이드
Kubernetes 환경에서 Istio 서비스 메시를 설치하고 구성하는 방법을 초급 개발자도 쉽게 이해할 수 있도록 실무 스토리와 비유로 풀어낸 가이드입니다. istioctl 설치부터 사이드카 주입까지 단계별로 학습합니다.
서비스 메시 완벽 가이드
마이크로서비스 간 통신을 안전하고 효율적으로 관리하는 서비스 메시의 핵심 개념부터 실전 도입까지, 초급 개발자를 위한 완벽한 입문서입니다. Istio와 Linkerd 비교, 사이드카 패턴, 실무 적용 노하우를 담았습니다.
Helm 마이크로서비스 패키징 완벽 가이드
Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.