Cloudnet AWES 5주차 스터디를 진행하며 정리한 글입니다.
이번 포스팅에서는 쿠버네티스에서 리소스 확장 방식 중 Pod의 CPU 및 메모리 Request과 Limit을 자동으로 조정하여 성능을 최적화하는 방식인 VPA에 대해 소개하겠습니다.
VPA
VPA(Vertical Pod Autoscaler)는 Pod 개수는 유지한 채, 개별 Pod의 리소스를 동적으로 조정하는 방식입니다.
VPA는 HPA와 동시에 사용할 수 없으며, 해당 스케일링을 하게 된다면 pod를 재실행해야합니다.
VPA는
1) pod의 과거 사용량을 분석하여 최적의 CPU, Memory Request, Limits을 추천하고,
2) 실행 중인 pod의 리소스를 자동으로 조정할 수 있습니다.
VPA의 동작원리

Request
- 컨테이너 실행될 때 최소한으로 보장 받는 값입니다.
- 스케줄러는 Request 값을 기준으로 노드에 컨테이너를 배치합니다.
- 노드에 충분한 리소스가 없으면 해당 pod는 Pending되고, cluster autoscaler가 활성화된 경우에는 새로운 노드가 추가될 수도 있습니다.
Limit
- 컨테이너가 사용할 수 있는 최대 값입니다.
- 컨테이너가 Limit을 초과할 경우 CPU는 제한된 속도로 실행되고 Memory는 OOM으로 종료됩니다.
따라서, request 값이 크다면 불필요한 node 추가로 인해 비용이 증가되고, 너무 낮으면 한 노드에 과도한 pod가 배치되어 성능 저하 및 OOM이 발생할 수 있어서 적절한 request값을 설정하는 것이 중요합니다.
1) VPA는 실제 Pod에 CPU/Memory 사용량을 모니터링하면서 적절한 requests 값을 자동으로 설정하는데, VPA의 Recommender는 메트릭 서버로부터 Pod의 CPU 및 메모리 사용량 데이터를 수집합니다.
2) 수집된 데이터를 기반으로 각 컨테이너에 대한 최적의 리소스 요청 및 제한 값을 계산합니다. 이때, percentile 값을 사용하여 리소스 사용 패턴을 분석합니다.
3) Admission Controller와 Updater는 Recommender의 추천 값을 적용하여 새로운 Pod의 리소스를 설정하거나, 기존 Pod의 리소스를 조정합니다.
참고)
design-proposals-archive/autoscaling/vertical-pod-autoscaler.md at main · kubernetes/design-proposals-archive
Archive of Kubernetes Design Proposals. Contribute to kubernetes/design-proposals-archive development by creating an account on GitHub.
github.com
Pod CPU/Memory 리소스 최적화하기 (VPA 및 Kubecost 추천로직 분석)
devocean.sk.com
VPA의 구성 요소
- Recommends : Pod의 CPU 및 메모리 사용량을 모니터링하고 적절한 Request/Limit 값을 추천
- Updater : VPA 정책에 따라 Pod의 리소스 값을 업데이트하고 필요하면 Pod를 재시작
- Admission Controller : Recommender의 추천값을 기반으로 새로운 Pod가 생성될 때 적절한 리소스를 설정하도록 조정, 초기 리소스 할당 최적화
VPA의 모드
- off : 리소스를 모니터링하고 추천값을 제공하지만 실제 변경은 하지 않음
- auto : VPA가 직접 Pod의 리소스를 업데이트하고 필요하면 재시작
- initial : 처음 생성될 때만 VPA가 요청값을 설정하고 이후에는 변경하지 않음
이제 VPA를 설치하고 실제로 리소스가 증가되어 작동하는 것을 확인해보도록 하겠습니다.
VPA 실습
VPA 레포지토리를 클론하고,
# 현재 실습환경에서는 이미 받아두었습니다.
# 아래 내용은 저의 실습환경에 대한 내용이니, 필요하신 분들은 아래 git repository에서 VPA 설치는 각자 진행하셔서
# 현재 코드블록은 스킵하시는 것을 추천드립니다.
git clone https://github.com/kubernetes/autoscaler.git
# 설치에 필요한 openssl 1.0 제거 후 1.1.1 버전 이상 다운로드
openssl version
yum remove openssl -y
yum install openssl11 -y
openssl11 version
# 스크립트 파일 내에 openssl11 수정
sed -i 's/openssl/openssl11/g' ~/autoscaler/vertical-pod-autoscaler/pkg/admission-controller/gencerts.sh
git status
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
git add .
git commit -m "openssl version modify"
# VPA 배포
watch -d kubectl get pod -n kube-system
cat hack/vpa-up.sh
./hack/vpa-up.sh
sed -i 's/openssl/openssl11/g' ~/autoscaler/vertical-pod-autoscaler/pkg/admission-controller/gencerts.sh
./hack/vpa-up.sh
# VPA 배포 확인
kubectl get crd | grep autoscaling
kubectl get mutatingwebhookconfigurations vpa-webhook-config
kubectl get mutatingwebhookconfigurations vpa-webhook-config -o json | jq
hamster 예제를 배포합니다.
초기 배포시에는 햄스터 'ㅅ' 파드는 CPU는 100M, Memory는 50Mi로 설정된 것을 알 수 있습니다.
하지만 시간이 흐를 수록, VPA updater가 Pod를 강제종료하고 (evict) 새로운 리소스 추천 값을 적용하기 위해 재배포한 이벤트 로그를 확인할 수 있습니다.
이때, 파드의 Request 값은 CPU 587m, Memory 262144k로 변경되었습니다.
# 예제 파일 확인 햄스터~ 'ㅅ'
cat examples/hamster.yaml
# This config creates a deployment with two pods, each requesting 100 millicores
# and trying to utilize slightly above 500 millicores (repeatedly using CPU for
# 0.5s and sleeping 0.5s).
# It also creates a corresponding Vertical Pod Autoscaler that adjusts the
# requests.
# Note that the update mode is left unset, so it defaults to "Auto" mode.
---
apiVersion: "autoscaling.k8s.io/v1"
kind: VerticalPodAutoscaler
metadata:
name: hamster-vpa
spec:
# recommenders field can be unset when using the default recommender.
# When using an alternative recommender, the alternative recommender's name
# can be specified as the following in a list.
# recommenders:
# - name: 'alternative'
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: hamster
resourcePolicy:
containerPolicies:
- containerName: '*'
minAllowed:
cpu: 100m
memory: 50Mi
maxAllowed:
cpu: 1
memory: 500Mi
controlledResources: ["cpu", "memory"]
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hamster
spec:
selector:
matchLabels:
app: hamster
replicas: 2
template:
metadata:
labels:
app: hamster
spec:
securityContext:
runAsNonRoot: true
runAsUser: 65534 # nobody
containers:
- name: hamster
image: registry.k8s.io/ubuntu-slim:0.14
resources:
requests:
cpu: 100m
memory: 50Mi
command: ["/bin/sh"]
args:
- "-c"
- "while true; do timeout 0.5s yes >/dev/null; sleep 0.5s; done"
# 예제 파일 배포 햄스터~ 'ㅅ'
kubectl apply -f examples/hamster.yaml
verticalpodautoscaler.autoscaling.k8s.io/hamster-vpa created
deployment.apps/hamster created
# 배포 초기 상태 - 파드의 리소스 Requests가 처음 배포한대로 적게 잡혀 있음
Every 2.0s: kubectl top pod;echo ----------------------… yujiyeon-ui-MacBookPro.local: 01:23:21
NAME CPU(cores) MEMORY(bytes)
hamster-598b78f579-b8t82 392m 0Mi
hamster-598b78f579-dzxsl 498m 0Mi
hamster-598b78f579-nbkzj 342m 0Mi
----------------------
Requests:
cpu: 100m
memory: 262144k
--
Requests:
cpu: 100m
memory: 50Mi
--
Requests:
cpu: 100m
# VPA에 의해 기존 파드 삭제되고 신규 파드가 생성
❯ kubectl get events --sort-by=".metadata.creationTimestamp" | grep VPA
109s Normal EvictedPod verticalpodautoscaler/hamster-vpa VPA Updater evicted Pod hamster-598b78f579-5ld7r to apply resource recommendation.
109s Normal EvictedByVPA pod/hamster-598b78f579-5ld7r Pod was evicted by VPA Updater to apply resource recommendation.
49s Normal EvictedByVPA pod/hamster-598b78f579-dzxsl Pod was evicted by VPA Updater to apply resource recommendation.
49s Normal EvictedPod verticalpodautoscaler/hamster-vpa VPA Updater evicted Pod hamster-598b78f579-dzxsl to apply resource recommendation.
memory: 262144k
# 시간 흐른 후 - 파드의 리소스 Requests가 변화한 것을 알 수 있음
Every 2.0s: kubectl top pod;echo ----------------------… yujiyeon-ui-MacBookPro.local: 01:26:00
in 2.563s (0)
NAME CPU(cores) MEMORY(bytes)
hamster-598b78f579-b8t82 389m 0Mi
hamster-598b78f579-ml7cc 493m 0Mi
----------------------
Requests:
cpu: 587m
memory: 262144k
--
Requests:
cpu: 587m
memory: 262144k

KRR
KRR은 Prometheus-based Kubernetes Resource Recommendations의 약자로, 실제 사용량 기준으로 Request와 Limit의 사용량을 추천합니다.
https://github.com/robusta-dev/krr#getting-started
GitHub - robusta-dev/krr: Prometheus-based Kubernetes Resource Recommendations
Prometheus-based Kubernetes Resource Recommendations - robusta-dev/krr
github.com
KRR과 VPA의 비교
Krr는 설치가 간편하고 즉시 리소스 추천을 제공할 수 있으며 확장성과 커스텀 가능성이 뛰어나다고 합니다.
표는 GPT가 생성하여 비교해주었습니다.

Mac 환경에서 krr을 설치하고 결과값을 확인해보겠습니다.
제 로컬 환경에서도 쿠버네티스 환경에 배포된 리소스들에 대한 추천값을 데이터화하여 확인할 수 있었습니다.
brew tap robusta-dev/homebrew-krr
brew install krr
krr --help
# 히스토리 데이터 기간, CPU Percentile, 메모리 버퍼 등을 커스터마이징하여 추천 설정 가능
krr simple
┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ Memory ┃ Memory ┃
┃ Number ┃ Namespace ┃ Name ┃ Pods ┃ Old Pods ┃ Type ┃ Container ┃ CPU Diff ┃ CPU Requests ┃ CPU Limits ┃ Memory Diff ┃ Requests ┃ Limits ┃
┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━┩
│ 1. │ monitoring │ kube-promet… │ 1 │ 0 │ Deployment │ grafana-sc-… │ +10m │ (+10m) unset │ unset │ +112Mi │ (+112Mi) │ unset -> │
│ │ │ │ │ │ │ │ │ -> 10m │ │ │ unset -> │ 112Mi │
│ │ │ │ │ │ │ │ │ │ │ │ 112Mi │ │
│ 2. │ │ │ │ │ │ grafana-sc-… │ +10m │ (+10m) unset │ unset │ +115Mi │ (+115Mi) │ unset -> │
│ │ │ │ │ │ │ │ │ -> 10m │ │ │ unset -> │ 115Mi │
│ │ │ │ │ │ │ │ │ │ │ │ 115Mi │ │
│ 3. │ │ │ │ │ │ grafana │ +12m │ (+12m) unset │ unset │ +113Mi │ (+113Mi) │ unset -> │
│ │ │ │ │ │ │ │ │ -> 12m │ │ │ unset -> │ 113Mi │
│ │ │ │ │ │ │ │ │ │ │ │ 113Mi │ │
├────────┼────────────┼──────────────┼──────┼──────────┼─────────────┼──────────────┼──────────┼──────────────┼────────────┼─────────────┼──────────────┼─────────────┤
│ 4. │ monitoring │ kube-promet… │ 1 │ 0 │ Deployment │ kube-state-… │ +10m │ (+10m) unset │ unset │ +100Mi │ (+100Mi) │ unset -> │
│ │ │ │ │ │ │ │ │ -> 10m │ │ │ unset -> │ 100Mi │
│ │ │ │ │ │ │ │ │ │ │ │ 100Mi │ │
├────────┼────────────┼──────────────┼──────┼──────────┼─────────────┼──────────────┼──────────┼──────────────┼────────────┼─────────────┼──────────────┼─────────────┤
│ 5. │ monitoring │ kube-promet… │ 1 │ 0 │ Deployment │ kube-promet… │ +10m │ (+10m) unset │ unset │ +100Mi │ (+100Mi) │ unset -> │
│ │ │ │ │ │ │ │ │ -> 10m │ │ │ unset -> │ 100Mi │
│ │ │ │ │ │ │ │ │ │ │ │ 100Mi │ │
├────────┼────────────┼──────────────┼──────┼──────────┼─────────────┼──────────────┼──────────┼──────────────┼────────────┼─────────────┼──────────────┼─────────────┤
│ 6. │ monitoring │ prometheus-… │ 1 │ 8 │ Deployment │ prometheus-… │ +170m │ (+170m) │ unset │ +242Mi │ (+242Mi) │ unset -> │
│ │ │ │ │ │ │ │ │ unset -> │ │ │ unset -> │ 242Mi │
│ │ │ │ │ │ │ │ │ 170m │ │ │ 242Mi │ │
├────────┼────────────┼──────────────┼──────┼──────────┼─────────────┼──────────────┼──────────┼──────────────┼────────────┼─────────────┼──────────────┼─────────────┤
│ 7. │ monitoring │ prometheus-… │ 1 │ 0 │ StatefulSet │ prometheus │ +28m │ (+28m) unset │ unset │ +561Mi │ (+561Mi) │ unset -> │
│ │ │ │ │ │ │ │ │ -> 28m │ │ │ unset -> │ 561Mi │
│ │ │ │ │ │ │ │ │ │ │ │ 561Mi │ │
│ 8. │ │ │ │ │ │ config-relo… │ +10m │ (+10m) unset │ unset │ +100Mi │ (+100Mi) │ unset -> │
│ │ │ │ │ │ │ │ │ -> 10m │ │ │ unset -> │ 100Mi │
│ │ │ │ │ │ │ │ │ │ │ │ 100Mi │ │
├────────┼────────────┼──────────────┼──────┼──────────┼─────────────┼──────────────┼──────────┼──────────────┼────────────┼─────────────┼──────────────┼─────────────┤
│ 9. │ monitoring │ kube-promet… │ 3 │ 0 │ DaemonSet │ node-export… │ +30m │ (+10m) unset │ unset │ +300Mi │ (+100Mi) │ unset -> │
│ │ │ │ │ │ │ │ (3 pods) │ -> 10m │ │ (3 pods) │ unset -> │ 100Mi │
│ │ │ │ │ │ │ │ │ │ │ │ 100Mi │ │
└────────┴────────────┴──────────────┴──────┴──────────┴─────────────┴──────────────┴──────────┴──────────────┴────────────┴─────────────┴──────────────┴─────────────┘
# 1달(720시간) 데이터 기준으로 CPU Peak 사용량의 90%와 메모리 Peak 사용량의 10% 여유를 설정하는 예시
krr simple --history_duration 720 --cpu_percentile 90 --memory_buffer_percentage 10
'스터디 > AEWS' 카테고리의 다른 글
[AEWS] 5주차 쿠버네티스 오토스케일링 이해하기 - Karpenter (0) | 2025.03.09 |
---|---|
[AEWS] 5주차 쿠버네티스 오토스케일링 이해하기 - 클러스터 오토스케일러 (CAS, CPA) (0) | 2025.03.09 |
[AEWS] 5주차 쿠버네티스 오토스케일링 이해하기 - 수평 확장 (HPA, KEDA) (0) | 2025.03.08 |
[AEWS] 4주차 Grafana 이해하기 (0) | 2025.03.02 |
[AEWS] 4주차 kube-prometheus-stack 설치 및 PromQL 쿼리 사용해보기 (0) | 2025.03.02 |