VPA 사용 시 발생할 수 있는 위험 요소
VPA는 Vertical Pod Autoscaler로 pod의 cpu/memory/request/limit 값을 자동으로 조정하는 기능이다.
즉, 애플리케이션의 실제 사용량(HPA가 보는 CPU 사용률 같은 지표 + 메모리 사용 패턴)을 분석해서
이 pod는 지금보다 메모리를 더 많이 줘야한다. CPU는 줄여도 된다. 같은 결론을 내린 후 pod 스펙을 자동으로 업데이트한다.
핵심 동작
- Recommender: Pod의 자원 사용량을 수집하고 적정 request/limit 값을 계산한다.
- Updater: 필요시 pod를 재시작해 새로운 자원 스펙을 적용한다.
- Admission Controller: 새로 만들어지는 Pod에 추천값을 적용한다.
왜 필요한가 #
사람이 request/limit 값을 정확하게 맞추기 어렵다 우리는 보통 휴리스틱하게 자원을 분배하여 맞춰가는 모습을 많이 볼 수 있는데
트래픽 변동, 배치 작업, gc 패턴, 메모리 피크등 대문에 정확한 자원값을 고정적으로 잡는 것은 사실상 불가능하다.
VPA는 실측 기반으로 값을 잡아준다.
Over-provisioning 방지
cpu 메모리를 넉넉하게 잡으면 안정적이지만 노드 자원이 낭비되고 비용이 증가한다.
VPA는 실제 사용치를 기반으로 최소한의 근거있는 Request/Limit 을 유지한다.
Under-provisioning 방지
위와 반대로 메모리 피크를 고려하지 못하면 OOMKilled를 맞을수도 있고 VPA는 메모리 패턴을 분석해
적정 Request를 높여준다.
HPA 상호보완
HPA는 파드 개수를 조절하지만 Request/Limit은 그대로라서 pod 10개를 늘렸는데 실제로 request가
말도 안되게 크게 설정돼 있으면 노드가 부족해 Scale out이 제대로 되지 않는다.
VPA는 바로 이런 비효율을 해결한다.
VPA 사용시 발생할 수 있는 위험 요소 #
운영 환경에서는 이게 제일 중요한데, 대부분의 문제는 Pod 재시작 때문에 발생한다.
- Pod 강제 재시작 -> 트래픽 순간 장애(downtime)
updater가 새로운 자원값을 적용하려면 파드 재생성이 필요하다.
무중단 설정(rolling, podDistruptionBudget 최소한의 파드수 유지)을 잘 안해두면 서비스가 순간적으로 끊긴다.
특히 statefulSet은 매우 위험하다.
- 메모리 과추천(Over-Recommendation) -> 노드 부족 / 비용 폭증
Recommender는 안전하게 동작하기 위해 메모리 Request를 넉넉하게 추천하는 경향이 있다.
이 경우 다음과 같은 문제가 발생한다.
- 하나의 파드 메모리 request가 크게 늘어 노드에 스케줄이 불가능하다.
- 전체 클러스터 자원 압박 -> 비용 증가
- 불필요한 Scale out
- HPA랑 충돌 위험
HPA랑 VPA를 같이 사용하게 되면 아래가 문제다
- HPA는 cpu 사용률을 기준으로 스케일링 함
- VPA는 CPU request/limit 자체를 변경함
- CPU Request가 변경되면 cpu 사용률(usage, request)가 다시 계산되기 때문에 HPA가 오작동하거나 과도하게 파드를 늘릴 수 있음
일반적으로 VPA는 request만 조절, Limit은 그대로 설정을 많이 사용한다.
또는 HPA와 VPA를 동시에 쓰고 싶으면 VPA는 Request만 Update 모드로 둔다.
- 순간적 부하 피크에 의해 잘못된 자원값이 추천될 위험
특정 시점의 급격한 메모리 spike가 발생하면, Recommender가 이를 정상 피크로 인식하고 Request를 지나치게 높여버릴 수 있다.
특히 gc pause, 특정 batch job, 비정상적인 장애, 메모리 leak
같은 일시적인 패턴에도 영향을 받는다.
- 크리티컬 워크로드에는 예측 불가능성이 증가한다.
VPA 추천값은 통계 기반이라 예측 정확성이 100%가 아니다.
자원이 민감한 워크로드에선 사람이 직접 고정하는게 나을 수 있음.
노드 스케일링 로직과 충돌 eks cluster auto scaler 환경에서 vpa로 인해 request가 커지면 다음이 동시에 일어남.
파드가 기존 노드에 스케쥴 안됨
cluster autoscaler가 노드에 스케일 아웃 시도
노드가 늘어나기전에 vpa가 또 계산
반복
오토스케일링이 불안정해지고 비용이 증가할 수 있음.
결론 #
vpa는 자원 효율성과 안정성을 크게 올려주는 강력한 기능이지만 재시작 기반이라는 점때문에 조심해야하며
HPA와 공존하면서 충돌때문에 조심해야한다. 그리고 recommender가 너무 과도하게 프로비저닝할수있는 문제가 있다.
모순적이게도 인간의 오버 프로비저닝은 막을 수 있지만, 지가 오버프로비저닝을 spike 트래픽같은것이나 cpu 높은 사용률 배치가 돌아 날수도 있다는것.
그냥 성능 테스트로 파드 수 구하는걸로 하자..
example #
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-app
labels:
app: sample-app
spec:
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
selector:
matchLabels:
app: sample-app
template:
metadata:
labels:
app: sample-app
spec:
containers:
- name: app
image: example/sample:latest
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
롤링 업데이트 디플로이먼트로 다운타임 방지시켜놓기 1
cpu 기반 hpa인데 최대 10개까지 늘어난다.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: sample-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: sample-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
이건 커스텀 hpa고 rps 값을 기반으로 올린다. cpu 변동 영향을 안받음.
qps http latancy 기반이다.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: sample-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: sample-app
minReplicas: 2
maxReplicas: 15
metrics:
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "50"
vpa 예시도 알아보자
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: sample-app-vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: sample-app
updatePolicy:
updateMode: "Auto" # 자동으로 Request 조정 + 필요한 경우 Pod 재시작
resourcePolicy:
containerPolicies:
- containerName: app
mode: "Auto"
controlledValues: "RequestsOnly" # 핵심: Limit은 변경하지 않도록 강제
minAllowed:
cpu: "100m"
memory: "128Mi"
maxAllowed:
cpu: "1"
memory: "2Gi"
위에처럼 줬다면 pod최소 하나쯤은 살아두게 해두자 podDisruptionBudget 정책을 살려두자
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: sample-app-pdb
spec:
minAvailable: 1
selector:
matchLabels:
app: sample-app
LimitRange로 클러스터 보호겸 네임스페이스 단위로 vpa가 너무 낮거나 높은 request는 추천하지 않도록 제한
apiVersion: v1
kind: LimitRange
metadata:
name: namespace-limit-range
spec:
limits:
- max:
cpu: "2"
memory: "4Gi"
min:
cpu: "50m"
memory: "64Mi"
type: Container