📑 목차
Image by MR-PANDA on Pixabay
쿠버네티스 비용 최적화의 필요성 및 도전 과제
클라우드 환경에서 애플리케이션을 운영하는 기업들에게 쿠버네티스는 확장성과 유연성을 제공하는 핵심 기술로 자리매김하였다. 그러나 이러한 이점과 더불어 클라우드 비용 관리는 쿠버네티스 운영의 가장 큰 도전 과제 중 하나로 인식되고 있다. 워크로드의 변동성이 큰 환경에서는 리소스의 과도한 프로비저닝(over-provisioning)으로 인해 상당한 유휴 리소스가 발생하며, 이는 불필요한 비용 지출로 이어진다. 반대로 리소스가 부족할 경우 서비스 품질 저하를 초래할 수 있으므로, 적정 수준의 리소스 할당과 효율적인 관리는 필수적이다.
본 글에서는 쿠버네티스 클러스터의 비용 효율성을 극대화하기 위한 세 가지 핵심 전략인 Karpenter를 활용한 노드 프로비저닝, HPA(Horizontal Pod Autoscaler)를 통한 워크로드 확장성 관리, 그리고 최적의 리소스 할당 전략에 대해 심층적으로 분석한다. 이러한 전략들을 통합적으로 적용함으로써, 기업은 안정적인 서비스 운영과 동시에 클라우드 비용을 효과적으로 절감할 수 있을 것으로 판단된다.
클라우드 비용 모델 이해
클라우드 서비스 제공자는 다양한 과금 모델을 통해 인프라 리소스를 제공한다. 대표적으로 온디맨드 인스턴스는 필요한 시점에 즉시 리소스를 사용할 수 있지만, 비용 효율성은 상대적으로 낮다. 예약 인스턴스(Reserved Instances)는 장기적인 사용을 약정하여 할인된 가격으로 리소스를 확보할 수 있으나, 유연성이 떨어진다. 반면 스팟 인스턴스(Spot Instances)는 클라우드 공급자의 유휴 리소스를 매우 저렴한 가격으로 사용할 수 있으나, 언제든지 회수될 수 있다는 특성을 가진다. 쿠버네티스 환경에서 이러한 인스턴스 유형들을 워크로드 특성에 맞춰 적절히 조합하는 것은 비용 절감의 중요한 요소이다.
리소스 낭비의 주요 원인
쿠버네티스 환경에서 리소스 낭비가 발생하는 주요 원인은 다음과 같이 분석될 수 있다:
- 과도한 리소스 요청 (Over-provisioning): 애플리케이션의 실제 사용량보다 더 많은 CPU, 메모리를 Pod에 할당하는 경우, 노드의 리소스는 충분히 활용되지 못한다.
- 유휴 노드 (Idle Nodes): 워크로드 감소 시에도 불필요하게 많은 노드가 유지되거나, Pod 스케줄링에 비효율적인 노드들이 존재하여 리소스가 낭비된다.
- 스케줄링 비효율성: Pod의 요구사항과 노드의 가용 리소스 간의 불일치로 인해 Pod가 특정 노드에 스케줄링되지 못하고 대기 상태에 머무르거나, 노드 간 리소스 불균형이 심화될 수 있다.
- 워크로드 변동성에 대한 비효율적인 대응: 급격한 트래픽 증가나 감소에 대해 클러스터의 리소스가 적절하고 신속하게 확장/축소되지 못하면, 피크 타임에는 성능 문제가 발생하고 유휴 시간에는 비용 낭비가 초래된다.
Karpenter를 활용한 노드 프로비저닝 최적화
기존 쿠버네티스 클러스터에서 노드 오토스케일링은 주로 Cluster Autoscaler(CA)에 의해 이루어졌으나, CA는 특정 클라우드 공급자의 인스턴스 그룹을 기반으로 동작하여 유연성과 반응성 측면에서 한계를 가진다. 이러한 한계를 극복하기 위해 등장한 것이 Karpenter이다. Karpenter는 AWS에서 개발된 오픈소스 노드 프로비저닝 도구로, Pod의 스케줄링 요구사항에 따라 동적으로 노드를 프로비저닝하고 유휴 노드를 효율적으로 제거함으로써 비용 최적화를 달성한다.
Karpenter 작동 원리 및 비용 절감 효과
Karpenter는 Pod가 스케줄링되지 못하고 Pending 상태에 있을 때, 해당 Pod의 리소스 요청(CPU, 메모리, 스토리지 등)과 노드 셀렉터, 톨러레이션, 어피니티 등의 요구사항을 분석하여 가장 적합한 인스턴스 타입을 실시간으로 식별하고 프로비저닝한다. 이는 기존 CA가 미리 정의된 인스턴스 그룹 내에서만 노드를 추가하는 방식과 대조된다. Karpenter는 또한 노드 활용률이 낮아지면 해당 노드를 효율적으로 제거하여 유휴 리소스를 최소화한다.
Karpenter의 가장 큰 비용 절감 효과는 스팟 인스턴스 활용 극대화에 있다. Karpenter는 다양한 스팟 인스턴스 유형을 고려하여 비용 효율적인 노드를 선택하고, 스팟 인스턴스 회수 시에는 Pod를 다른 노드로 이동시킨 후 새로운 스팟 인스턴스를 프로비저닝하는 방식으로 안정성을 유지한다. 이로 인해 온디맨드 인스턴스 대비 최대 90%까지 비용을 절감할 수 있는 것으로 알려져 있다.
Karpenter와 Cluster Autoscaler 비교
| 기준 | Karpenter | Cluster Autoscaler |
|---|---|---|
| 반응성 | 매우 빠름 (Pod 스케줄링 실패 즉시 반응) | 상대적으로 느림 (스케줄링 실패 후 일정 시간 대기) |
| 비용 효율성 | 매우 높음 (스팟 인스턴스 및 최적 인스턴스 선택) | 중간 (미리 정의된 인스턴스 그룹에 의존) |
| 유연성 | 매우 높음 (모든 인스턴스 유형 및 아키텍처 지원) | 낮음 (Auto Scaling Group에 의존) |
| 복잡성 | 설정 초기 복잡성 존재하나, 장기적으로 운영 단순화 | 비교적 단순하나, 최적화에 한계 |
Karpenter NodePool 설정 예시 (AWS EKS 기준):
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
name: default
spec:
template:
spec:
requirements:
- key: kubernetes.io/arch
operator: In
values: ["amd64"]
- key: kubernetes.io/os
operator: In
values: ["linux"]
- key: karpenter.sh/capacity-type # 스팟 인스턴스 선호
operator: In
values: ["spot", "on-demand"]
- key: karpenter.sh/instance-category # 특정 인스턴스 카테고리 선호
operator: In
values: ["c", "m", "r"]
nodeClassRef:
name: default
limits:
resources:
cpu: 1000 # 클러스터가 최대로 가질 수 있는 CPU 코어 제한
disruption:
consolidationPolicy: WhenEmpty # 노드가 비어있을 때만 통합
expireAfter: 720h # 노드 생성 후 최대 30일 후 만료
---
apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
name: default
spec:
amiFamily: AL2 # Amazon Linux 2 AMI 사용
role: KarpenterNodeRole # 노드에 할당할 IAM 역할
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: my-cluster # EKS 클러스터 서브넷 지정
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: my-cluster # EKS 클러스터 보안 그룹 지정
instanceSelector:
# Karpenter가 선택할 인스턴스 타입 필터링
# 예: 특정 vCPU, 메모리 범위 지정 또는 특정 인스턴스 타입 제외
# instance-family: c5, m5, r5 등
# cpu: "2"
# memory: "4Gi"
tags:
karpenter.sh/discovery: my-cluster # 생성되는 노드에 태그 추가
Environment: Production
Owner: PlatformTeam
위 예시에서 볼 수 있듯이, `NodePool`은 Pod의 요구사항과 노드 정책을 정의하고, `EC2NodeClass`는 AWS 인스턴스 관련 세부 설정을 담당한다. 이를 통해 Karpenter는 워크로드에 최적화된 인스턴스를 유연하게 프로비저닝할 수 있다.
Image by peteranta on Pixabay
HPA (Horizontal Pod Autoscaler)를 이용한 워크로드 확장성 관리
HPA (Horizontal Pod Autoscaler)는 쿠버네티스의 핵심적인 워크로드 확장성 관리 도구이다. HPA는 지정된 메트릭(예: CPU 사용률, 메모리 사용률, 커스텀 메트릭)을 기반으로 Deployment, StatefulSet, ReplicaSet과 같은 워크로드 컨트롤러의 Pod 수를 자동으로 조절한다. 이는 피크 타임에 서비스의 안정성을 보장하고, 유휴 시간에는 불필요한 리소스 사용을 줄여 비용을 절감하는 데 기여한다.
HPA 작동 원리 및 비용 절감 효과
HPA는 Metrics Server 또는 다른 커스텀 메트릭 API를 통해 Pod의 리소스 사용률 데이터를 수집한다. 그리고 사용자가 HPA 정의 시 설정한 임계치와 비교하여 Pod의 복제본 수를 증가시키거나 감소시킨다. 예를 들어, CPU 사용률이 50%를 초과하면 Pod 수를 늘리고, 30% 미만으로 떨어지면 Pod 수를 줄이는 방식으로 작동한다.
HPA를 통한 비용 절감 효과는 다음과 같다:
- 탄력적인 리소스 사용: 워크로드의 실제 수요에 맞춰 Pod 수를 조절하므로, 항상 필요한 만큼의 리소스만 운영하게 된다. 이는 유휴 리소스 최소화로 이어진다.
- 과도한 프로비저닝 방지: 수동으로 피크 타임에 맞춰 Pod 수를 설정하는 대신, HPA가 자동으로 확장/축소하므로 과도한 리소스 할당을 방지한다.
- 안정적인 서비스 유지: 트래픽 증가 시 Pod 수를 늘려 서비스 지연이나 장애를 방지하고, 이는 곧 고객 만족도 유지 및 잠재적 손실 방지로 연결된다.
HPA 설정 모범 사례
minReplicas와maxReplicas설정: 최소 Pod 수와 최대 Pod 수를 적절히 설정하는 것이 중요하다.minReplicas는 서비스의 기본 부하를 처리할 수 있는 수준으로,maxReplicas는 예상되는 최대 부하를 감당할 수 있도록 충분히 높게 설정해야 한다.- Cool-down/Stabilization Window 고려: HPA는 급격한 스케일링 변화(thrashing)를 방지하기 위해 일정 시간 동안 스케일링 결정을 지연시키는 쿨다운 기간을 가진다. 워크로드의 특성에 맞춰 이 기간을 조정하는 것이 안정적인 운영에 도움이 된다.
- Custom Metrics 활용: CPU, 메모리 사용률 외에 QPS(Query Per Second), 메시지 큐 길이, Latency 등 애플리케이션의 비즈니스 로직과 관련된 커스텀 메트릭을 HPA의 기준으로 활용할 경우, 더욱 정교하고 효율적인 스케일링이 가능하다. 이를 위해서는 Prometheus와 같은 모니터링 시스템과 External Metrics API 연동이 필요하다.
- 리소스 요청(requests)의 정확성: HPA는 Pod의 CPU, 메모리
requests값을 기준으로 사용률을 계산하므로, 이 값이 정확하지 않으면 HPA가 의도한 대로 동작하지 않을 수 있다.
HorizontalPodAutoscaler YAML 예시 (CPU 기준):
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-web-app-hpa
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-web-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50 # CPU 사용률이 50%를 초과하면 스케일 아웃
# - type: Resource
# resource:
# name: memory
# target:
# type: AverageValue
# averageValue: 200Mi # 메모리 사용량이 200Mi를 초과하면 스케일 아웃
# - type: Pods
# pods:
# metric:
# name: http_requests_per_second
# target:
# type: AverageValue
# averageValue: "10k" # Pod당 초당 HTTP 요청이 10k를 초과하면 스케일 아웃 (Custom Metrics 예시)
위 예시는 my-web-app Deployment의 CPU 사용률이 평균 50%를 초과하면 Pod 수를 늘리고, 2개에서 10개 사이로 유지하도록 설정된 HPA이다. 워크로드의 특성을 면밀히 분석하여 적절한 메트릭과 임계치를 설정하는 것이 HPA 최적화의 핵심이다.
Image by YALEC on Pixabay
효율적인 리소스 할당 전략
쿠버네티스 환경에서 리소스 할당은 Pod가 사용할 CPU, 메모리 등의 리소스를 정의하는 것을 의미하며, 이는 클러스터의 안정성, 성능, 그리고 비용 효율성에 직접적인 영향을 미친다. requests와 limits 값의 정확한 설정은 노드 활용률을 극대화하고 리소스 낭비를 최소화하는 데 매우 중요하다.
requests와 limits의 정확한 설정
requests(요청): Pod가 스케줄링될 때 보장받아야 하는 최소 리소스 양을 의미한다. 쿠버네티스 스케줄러는 노드의 가용 리소스가requests값을 충족하는지 확인한 후 Pod를 해당 노드에 할당한다. CPU requests는 밀리코어(m) 단위로, Memory requests는 바이트(B, Mi, Gi) 단위로 지정된다. 이 값이 너무 낮으면 Pod가 스케줄링될 수는 있으나, 실제 실행 시 리소스 부족으로 성능 저하를 겪을 수 있다. 반대로 너무 높으면 불필요하게 많은 리소스가 예약되어 노드 활용률이 저하될 수 있다.limits(제한): Pod가 사용할 수 있는 최대 리소스 양을 의미한다. CPU limits를 초과하는 Pod는 CPU 스로틀링(throttling)을 겪어 성능이 저하될 수 있으며, Memory limits를 초과하는 Pod는 OOMKilled(Out Of Memory Killed) 상태가 되어 강제로 종료될 수 있다.limits를 설정하지 않으면 Pod는 노드의 모든 가용 리소스를 사용할 수 있으나, 이는 다른 Pod에 영향을 미쳐 노드 전체의 안정성을 해칠 수 있다.
정확한 설정의 중요성:
- 스케줄링 효율성:
requests는 스케줄러가 Pod를 어느 노드에 배치할지 결정하는 기준이 되므로, 정확해야 한다. - 노드 활용률:
requests와limits가 실제 사용량과 근접할수록 노드의 리소스가 효율적으로 분배되어 전체 클러스터 비용이 절감된다. - 서비스 안정성:
limits는 Pod가 다른 Pod의 리소스를 침범하지 않도록 보호하여 서비스의 안정성을 보장한다.
리소스 할당 모니터링 및 튜닝
정확한 리소스 할당은 한 번의 설정으로 끝나는 것이 아니라, 지속적인 모니터링과 튜닝을 통해 이루어져야 한다. 워크로드의 특성과 시간이 지남에 따른 사용량 변화를 분석하는 것이 중요하다.
- 모니터링 도구 활용: Prometheus, Grafana, Datadog 등과 같은 모니터링 도구를 사용하여 Pod 및 노드의 CPU, 메모리 사용량을 지속적으로 추적해야 한다. 이를 통해 과소/과대 할당된 리소스를 식별할 수 있다.
- VPA (Vertical Pod Autoscaler) 활용: VPA는 Pod의 과거 리소스 사용량 패턴을 분석하여 최적의
requests와limits값을 자동으로 추천하거나 적용해주는 쿠버네티스 컴포넌트이다. VPA는 크게 세 가지 모드로 동작할 수 있다:Off: 권장 사항만 제공하고 아무것도 변경하지 않는다.Initial: Pod 생성 시점에만 권장 값을 적용한다.Recreate: Pod를 재생성하여 권장 값을 적용한다.Auto: Pod를 재생성하지 않고 실행 중인 Pod의 리소스 설정을 동적으로 변경한다 (실험적 기능).
- 워크로드 특성 분석: 애플리케이션이 CPU-bound인지, memory-bound인지, 또는 I/O-bound인지를 파악하여 리소스 할당 전략을 수립해야 한다. 예를 들어, CPU 사용량이 불규칙한 배치 작업은 CPU
limits를requests보다 높게 설정하여 필요시 버스트(burst) 사용을 허용할 수 있다.
Pod 리소스 할당 YAML 예시:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-api-service
spec:
replicas: 3
selector:
matchLabels:
app: my-api-service
template:
metadata:
labels:
app: my-api-service
spec:
containers:
- name: api-container
image: my-registry/my-api-service:v1.0.0
ports:
- containerPort: 8080
resources:
requests:
cpu: "200m" # 최소 0.2 CPU 코어 보장
memory: "256Mi" # 최소 256MiB 메모리 보장
limits:
cpu: "500m" # 최대 0.5 CPU 코어 사용 제한
memory: "512Mi" # 최대 512MiB 메모리 사용 제한
위 예시에서 requests와 limits를 명확히 설정함으로써, Pod가 스케줄러에게 최소한의 리소스를 요청하고, 노드에서 사용할 수 있는 최대 리소스를 제한하게 된다. 이는 클러스터 안정성과 비용 효율성을 동시에 확보하는 데 필수적인 조치이다.
결론 및 향후 과제
쿠버네티스 환경에서 비용 최적화는 단일 솔루션으로 달성될 수 있는 목표가 아니며, Karpenter, HPA, 그리고 리소스 할당 전략이 유기적으로 결합될 때 비로소 최대의 시너지 효과를 발휘할 수 있다. Karpenter는 워크로드의 요구사항에 맞춰 최적의 노드를 동적으로 프로비저닝하여 불필요한 인프라 비용을 줄이고, HPA는 워크로드의 변동성에 따라 Pod 수를 자동으로 조절하여 운영 효율성을 높인다. 마지막으로, requests와 limits를 포함한 리소스 할당 전략은 노드 내부의 리소스 활용도를 극대화하여 낭비를 최소화하는 기반을 제공한다.
이러한 전략들을 성공적으로 구현하기 위해서는 지속적인 모니터링과 데이터 기반의 분석이 필수적이다. 애플리케이션의 성능 메트릭, 리소스 사용량, 클라우드 비용 데이터를 종합적으로 분석하여 최적화 포인트를 찾아내고, 주기적으로 설정을 튜닝하는 노력이 요구된다. 또한, VPA와 같은 자동화 도구를 적극적으로 활용하여 리소스 할당의 정확성을 높이는 것도 좋은 방안이다.
결론적으로, 클라우드 인프라 효율성은 단순히 기술적인 최적화를 넘어, 비용 거버넌스의 중요한 축이 된다. 본 글에서 제시된 쿠버네티스 비용 최적화 전략들이 독자 여러분의 클라우드 운영에 실질적인 도움이 되기를 바란다. 여러분의 쿠버네티스 비용 최적화 경험이나 궁금한 점이 있다면 댓글로 공유해 주시기 바란다.