비용 최적화 — 쿠버네티스 자원 낭비 줄이기
쿠버네티스 비용 낭비가 요청(requests)·실제 사용·노드 청구 사이의 간극에서 발생하는 구조를 이해하고, 가시성 확보부터 라이트사이징(VPA)·오토스케일링(HPA·Cluster Autoscaler·Karpenter)·스팟 인스턴스·빈 패킹까지 워크로드와 인프라 양쪽에서 비용을 조이는 실전 전략을 정리합니다.
지난 글에서 ResourceQuota로 한 테넌트가 자원을 독식하지 못하게 막는 이야기를 했다. 그런데 자원을 “나눠 막는 것”과 “낭비 없이 쓰는 것”은 다른 문제다. 쿠버네티스 클러스터의 청구서는 종종 실제로 일한 양보다 훨씬 크게 나온다. 그 차이가 곧 낭비다. 비용 최적화는 이 낭비가 어디서 생기는지 정확히 짚고, 워크로드와 인프라 양쪽에서 체계적으로 줄여가는 작업이다.
낭비의 정체 — 세 막대의 간극
비용 최적화를 이해하려면 서로 다른 세 가지 “양”을 구분해야 한다. 청구되는 양, 예약된 양, 실제 사용된 양이다.
청구는 노드 용량 기준이다. 노드를 켜두면 그 위에서 무엇을 하든 풀 용량만큼 돈이 나간다. 스케줄링은 requests 기준이다. 스케줄러는 Pod의 requests 합계가 노드 용량을 넘지 않는 선에서 배치하므로, requests가 예약되지 않은 빈 슬롯은 노드 비용을 내면서도 아무도 안 쓴다. 그리고 가치는 실제 사용 기준이다. requests를 잡아놨지만 실제로는 그 절반도 안 쓴다면, 그 차이(슬랙)만큼 노드를 더 켜둔 셈이다.
낭비는 이 세 막대의 간극에서 나온다. 핵심 통찰은 이것이다. 거의 모든 쿠버네티스 낭비의 근원은 과대 요청(over-request) — 실제 사용량보다 훨씬 큰 requests를 잡아두는 것이다. 그래서 최적화의 출발점은 이 간극을 측정하고 좁히는 것이다.
첫 단계는 언제나 측정
측정 없는 최적화는 추측이다. 어떤 워크로드가, 어떤 네임스페이스가, 어떤 노드가 돈을 쓰는지 보이지 않으면 손댈 곳을 알 수 없다. 다행히 앞선 글들에서 다룬 도구들이 기반이 된다 — metrics-server로 실시간 사용량을, Prometheus로 이력을, 그리고 OpenCost나 Kubecost 같은 도구로 워크로드별 비용을 환산해 볼 수 있다.
# Pod별 실제 CPU/메모리 사용량 (metrics-server 필요)
kubectl top pods -A --sort-by=memory
# requests 대비 실제 사용을 비교 — 과대 요청 찾기의 출발점
kubectl describe node <node> | grep -A12 "Allocated resources"
무엇을 볼지가 중요하다. requests 대비 실제 사용률이 낮은 워크로드(과대 요청), 오랫동안 사용률이 낮은 노드(빈 슬롯), 그리고 바인딩되지 않은 PVC나 놀고 있는 LoadBalancer 같은 “유령 자원”을 찾는다.
두 방향에서 조이기
비용을 줄이는 레버는 크게 두 방향이다. 워크로드 측에서는 요청 자체를 줄이고, 인프라 측에서는 자원의 단가를 낮춘다. 둘은 곱셈으로 작용한다.
워크로드 측 — 요청을 줄인다
가장 효과가 큰 것은 라이트사이징(rightsizing)이다. 과대 요청을 실제 사용에 맞게 낮추면, 같은 노드에 더 많은 Pod가 들어가고 노드 수가 줄어든다. 앞서 다룬 VPA(Vertical Pod Autoscaler)가 메트릭을 바탕으로 적정 requests를 추천해 주므로, 이를 권고 모드로 돌려 데이터를 모은 뒤 적용한다.
# VPA를 '권고만' 모드로 — 추천값을 보고 사람이 판단
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: api-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: api
updatePolicy:
updateMode: "Off" # 추천만, 자동 변경 없음
다음은 HPA다. 부하에 따라 복제본을 늘리고 줄이면, 한가한 시간대에 자원을 반납해 비용을 아낀다. 마지막으로 유휴 정리 — 개발/스테이징 환경을 야간이나 주말에 0으로 축소하고, 쓰지 않는 PVC와 LoadBalancer를 회수한다. 24/7로 켜둘 이유가 없는 환경은 의외로 큰 비용이다.
인프라 측 — 단가를 낮춘다
워크로드가 요청을 줄였다면, 이제 그 요청을 더 싸게 충족한다. Cluster Autoscaler나 Karpenter는 빈 노드를 자동으로 끄고, 수요가 늘면 노드를 공급한다 — 특히 Karpenter는 워크로드의 요구에 딱 맞는 인스턴스 타입을 골라 빈 슬롯을 줄인다. 스팟(Spot) 인스턴스는 같은 자원을 큰 폭으로 할인된 가격에 제공한다. 중단될 수 있다는 단점이 있으므로, 중단에 견디는(stateless, 재시작 가능한) 워크로드를 스팟에 배치하는 것이 정석이다.
여기에 빈 패킹(bin-packing)으로 노드 밀도를 높이고, 안정적인 기저 부하(baseline)에 대해서는 클라우드의 예약/약정 할인을 적용하면 단가가 더 내려간다. 변동 부하는 스팟·온디맨드로, 기저 부하는 약정으로 — 이 조합이 비용 곡선을 크게 낮춘다.
순서가 중요하다
레버가 많다고 아무거나 당기면 안 된다. 순서가 있다. 먼저 가시성을 확보해 낭비의 위치를 파악하고, 라이트사이징으로 과대 요청을 잡고, 오토스케일링으로 수요에 맞춰 자원을 신축적으로 만든 다음, 마지막으로 단가 인하(스팟·약정)를 적용한다. 순서를 거꾸로 하면 — 예를 들어 과대 요청을 그대로 둔 채 노드만 스팟으로 바꾸면 — 낭비를 싼값에 사는 셈이 된다.
그리고 비용 최적화는 한 번의 프로젝트가 아니라 지속적인 운영(FinOps)이다. 워크로드는 계속 바뀌므로, 측정 → 조정 → 검증의 루프를 정기적으로 돌려야 절감 효과가 유지된다.
정리 — 그리고 다음
쿠버네티스 비용 낭비는 요청·사용·청구의 세 막대 간극에서 오며, 그 근원은 대부분 과대 요청이다. 측정으로 낭비를 드러내고, 워크로드 측에서는 라이트사이징·HPA·유휴 정리로 요청을 줄이고, 인프라 측에서는 오토스케일러·스팟·빈 패킹·약정으로 단가를 낮춘다. 가시성 → 라이트사이징 → 오토스케일링 → 단가 인하의 순서를 지키고, 이를 지속적 루프로 운영한다.
여기까지 클러스터를 안정적이고 효율적으로 운영하는 법을 다뤘다. 하지만 아무리 잘 운영해도 재해는 온다 — 리전 장애, 인적 실수, 데이터 손상. 다음 글에서는 최악의 상황에 대비하는 재해 복구(DR) 전략으로 이어진다.
지난 글: 멀티 테넌시 — 하나의 클러스터를 안전하게 나눠 쓰기
다음 글: 재해 복구 — 최악의 상황에 대비하는 DR 전략
읽어주셔서 감사합니다. 😊