KEDA + Prometheus Adapter로 HPA 커스텀 메트릭 오토스케일링(스레드·큐·지연 기반)
CPU만 보고 스케일하면 늦습니다. 실제로는 웹 스레드풀 사용률, DB 커넥션 대기열, 요청 지연(p95), 메시지 큐 길이가 먼저 비명을 지릅니다. 이 글은 Kubernetes에서 KEDA와 Prometheus Adapter를 이용해 이런 도메인 메트릭으로 HPA를 구동하는 방법을 단계별로 정리합니다.
1) 아키텍처 개요
Prometheus가 애플리케이션/인프라 지표를 수집하고, Recording Rule로 스케일에 적합한 지표를 만듭니다. Prometheus Adapter는 해당 지표를 Kubernetes Custom Metrics API로 노출합니다. HPA는 그 지표를 목표값으로 삼아 레플리카를 조정하고, KEDA는 큐/외부 지표 이벤트 기반 스케일을 담당합니다.
[App Metrics] → Prometheus → (Recording Rules) → Prometheus Adapter → HPA(Custom Metrics)
[Queue/External] → KEDA Scalers → HPA(External Metrics)
2) 전제 조건
- 클러스터에
Prometheus&Alertmanager가 동작 중 - 애플리케이션이
/actuator/prometheus등으로 지표 노출(Micrometer 권장) - kubectl, helm 사용 가능
3) Prometheus Recording Rule: 스레드/대기열/지연 파생 지표
지난 글의 USE 파생지표를 스케일 친화적 이름으로 별도 기록해 둡니다.
# use-hpa.yml
groups:
- name: hpa.targets
rules:
- record: hpa:thread_utilization
expr: (sum by (application) (tomcat_threads_busy))
/ ignoring() (sum by (application) (tomcat_threads_config_max))
- record: hpa:db_pending
expr: sum by (application) (hikaricp_connections_pending)
- record: hpa:http_p95
expr: histogram_quantile(0.95,
sum by (le) (rate(http_server_requests_seconds_bucket{uri!~"/actuator.*"}[5m])))
적용 후 리로드:
promtool check rules use-hpa.yml
kubectl -n monitoring create configmap use-hpa --from-file=use-hpa.yml
# Prometheus 설정에 ruleFiles로 포함 후 재기동 또는 SIGHUP
4) Prometheus Adapter 설치 & 매핑
helm으로 배포하고, 매핑 규칙에서 어떤 지표를 Custom Metrics로 노출할지 정의합니다.
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install prom-adapter prometheus-community/prometheus-adapter -n monitoring \
--create-namespace \
-f values-adapter.yaml
values-adapter.yaml의 핵심만:
rules:
custom:
- seriesQuery: 'hpa:thread_utilization'
resources:
overrides:
namespace: {resource: "namespace"}
pod: {resource: "pod"}
name:
matches: "hpa:thread_utilization"
as: "svc_thread_utilization"
metricsQuery: 'avg(<<.Series>>{namespace="prod"})'
- seriesQuery: 'hpa:db_pending'
resources:
overrides:
namespace: {resource: "namespace"}
name:
matches: "hpa:db_pending"
as: "db_pending"
metricsQuery: 'sum(<<.Series>>{namespace="prod"})'
- seriesQuery: 'hpa:http_p95'
resources:
overrides:
namespace: {resource: "namespace"}
name:
matches: "hpa:http_p95"
as: "http_p95_seconds"
metricsQuery: 'avg(<<.Series>>{namespace="prod"})'
정상 노출 확인:
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta2" | jq .
5) HPA: 커스텀 메트릭으로 스케일
스레드풀 사용률을 0.70으로 유지하도록 목표를 설정합니다. 대기열/지연은 보조 기준으로 함께 쓸 수 있습니다.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: order-api
namespace: prod
spec:
minReplicas: 2
maxReplicas: 20
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 100 # 1분에 최대 2배
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 180
policies:
- type: Percent
value: 50
periodSeconds: 60
metrics:
- type: Pods
pods:
metric:
name: svc_thread_utilization
target:
type: AverageValue
averageValue: "0.70"
- type: Pods
pods:
metric:
name: http_p95_seconds
target:
type: AverageValue
averageValue: "0.80"
팁: behavior로 급격 스케일링을 제한/완화하여 톱니현상(Thrashing)을 줄입니다.
6) KEDA: 큐 길이/외부 지표 기반 스케일
큐(예: RabbitMQ, Kafka)나 외부 서비스 백로그로 스케일하고 싶다면 HPA 대신(또는 함께) KEDA를 사용합니다.
6-1) 설치
helm repo add kedacore https://kedacore.github.io/charts
helm install keda kedacore/keda -n keda --create-namespace
6-2) Prometheus Scaler(레이트 기반)
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: order-api-keda
namespace: prod
spec:
scaleTargetRef:
name: order-api
minReplicaCount: 2
maxReplicaCount: 30
cooldownPeriod: 180
pollingInterval: 15
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus.monitoring.svc.cluster.local:9090
metricName: http_requests_rate
threshold: "200" # 초당 200req 이상이면 스케일
query: |
sum(rate(http_server_requests_seconds_count{namespace="prod"}[1m]))
6-3) RabbitMQ 큐 길이 기반
triggers:
- type: rabbitmq
metadata:
protocol: amqp
host: amqp://user:pass@rabbitmq:5672/
queueName: order-events
mode: QueueLength
value: "1000" # 큐 길이 1000 초과 시 스케일
KEDA는 외부 지표를 External Metrics로 HPA에 제공하므로, 트래픽 성격에 맞게 혼합 구성할 수 있습니다.
7) 안정화 파라미터 & 안전장치
- stabilizationWindowSeconds: 최근 윈도우의 최솟값(ScaleDown)/최댓값(ScaleUp)을 사용해 요동 완화
- pollingInterval/cooldownPeriod(KEDA): 스케일링 감지 주기/축소 지연 설정
- 최대/최소 레플리카: 장애 시에도 과금 폭주/과소 프로비저닝 방지
- 지표 품질: 샘플 누락/지연 시 CPU를 보조 기준으로 추가
8) 실제 튜닝 순서(짧고 확실하게)
- 기록식으로
hpa:*지표를 먼저 만들고 1주일 관찰 - HPA 목표값을 “평시 평균 + 10% 여유”로 설정
- ScaleUp은 과감하게(예: 100%/분), ScaleDown은 보수적으로(예: 50%/3분)
- KEDA로 큐/백로그 스파이크 대응을 보강
- 대시보드에 레플리카 수, p95, 스레드 사용률, 큐 길이를 한 화면에 배치
9) 트러블슈팅 빠른 분기
- “metrics not found” → Adapter
rules.custom매핑/네임스페이스 라벨 확인 - 스케일이 늦다 →
pollingInterval단축, ScaleUp 정책 상향, 기록식 평균 윈도우 1m로 - 스케일 톱니현상 → ScaleDown 안정화 창 증가, 목표값 완화(0.65→0.70), p95 대신 p90
- KEDA 동작 안 함 →
keda-operator로그/TriggerAuthentication 시크릿 확인
10) 체크리스트(복붙용)
- Recording Rules:
hpa:thread_utilization,hpa:db_pending,hpa:http_p95 - Prometheus Adapter 매핑 및
custom.metrics.k8s.io확인 - HPA v2
behavior로 안정화 정책 적용 - KEDA 설치 & Prometheus/Queue Scaler 구성
- 대시보드: 레플리카/지연/스레드/큐 길이 모니터링
- 런북: 스케일 실패 시 수동 레플리카 명령/롤백 절차 문서화
결론: CPU를 “보조”로 두고, 사용자 체감에 직접 연결된 메트릭(스레드, 대기열, 지연, 큐 길이)을 스케일 트리거로 삼으세요. KEDA + Prometheus Adapter 조합이면 도입은 가볍고 효과는 즉각적입니다.
'배포·CI,CD·클라우드' 카테고리의 다른 글
| External Secrets로 시크릿 자동 주입: AWS Secrets Manager/KMS · Kubernetes 네이티브 시크릿 관리 (1) | 2025.11.01 |
|---|---|
| Argo CD로 GitOps 파이프라인 구축: App-of-Apps, 환경 분리, 자동 동기화/PR 기반 승격 (0) | 2025.11.01 |
| Argo Rollouts로 프로그레시브 딜리버리: Canary/Blue-Green, 자동 프로모션·중단, 메트릭 연동(Prometheus) (0) | 2025.10.31 |
| GitHub Actions: push 시 테스트 자동화 YAML (0) | 2025.10.04 |
| Dockerfile 멀티스테이지로 이미지 절반 만들기 (0) | 2025.10.04 |