본문 바로가기
IT/k8s

[k8s] Karpenter 오토스케일로 EKS 비용 절감 검증하는 방법

by 수누다 2026. 7. 14.
반응형

Karpenter 오토스케일로 EKS 비용 절감 검증하는 방법

Karpenter 오토스케일을 검토하시는 분들은 비슷한 지점에서 막히곤 합니다. HPA로 파드 수는 잘 늘고 줄어드는데, 월말 청구서를 보면 노드가 생각보다 오래 남아 있어서 클라우드 비용 절감 체감이 약하거든요. 특히 AWS EKS를 운영하다 보면 파드 오토스케일링과 노드 비용 최적화가 완전히 같은 문제가 아니라는 점을 금방 느끼게 됩니다.

저도 초반에는 "HPA만 잘 잡으면 끝나는 거 아닌가?" 싶었는데, 실제로는 노드 단위 빈 공간이 더 큰 병목이었습니다. 이럴 때 Karpenter 오토스케일은 파드 요구사항에 맞춰 노드를 더 유연하게 만들고, 유휴 노드를 정리하는 데 강점이 있습니다. 이번 글에서는 Kubernetes 오토스케일링 관점에서 Karpenter가 왜 비용 최적화에 유리한지, 그리고 AWS EKS 비용 최적화 효과를 어떤 지표로 검증해야 하는지 정리해보겠습니다.

Karpenter 오토스케일 기반 EKS 아키텍처 개요 이미지

Karpenter가 스케줄링되지 못한 파드를 감지하고 적절한 EC2 노드를 만들고, 유휴 노드를 정리하는 흐름을 보여주는 이미지입니다.

Karpenter 오토스케일이 비용 절감에 유리한 이유

쉽게 말해 Karpenter는 파드가 실제로 필요로 하는 리소스에 맞춰 노드를 바로 만들어주는 도구입니다. 기존 Cluster Autoscaler도 노드 수를 늘리고 줄일 수 있지만, 보통 미리 정의한 노드 그룹을 중심으로 확장하다 보니 리소스가 남는 구간이 생기기 쉽습니다.

반면 Karpenter는 Pending 상태의 파드를 보고 CPU, 메모리, 아키텍처, 용량 유형(온디맨드/스팟) 같은 조건에 맞는 인스턴스를 더 유연하게 고릅니다. 운영에서 보면 이 차이가 꽤 큽니다. 특정 인스턴스 몇 개만 반복해서 늘리는 대신, 워크로드 특성에 맞춰 c 계열, m 계열, r 계열을 섞고 스팟까지 활용하기 쉬워지거든요.

항목 Cluster Autoscaler Karpenter
확장 기준 기존 노드 그룹 중심 파드 요구사항 중심
인스턴스 선택 유연성 상대적으로 제한적 높음
빈 리소스 최소화 노드 그룹 크기에 영향 받음 상황별 최적화에 유리
스팟 활용 구성 복잡도 있음 정책 설계가 비교적 직관적
비용 절감 포인트 노드 수 축소 노드 크기와 종류까지 최적화

핵심은 단순히 노드를 빨리 만드는 데 있지 않습니다. Karpenter 오토스케일의 진짜 장점은 불필요하게 큰 노드를 오래 붙잡고 있지 않게 만드는 구조에 있습니다. 결국 비용은 시간당 단가와 실행 시간의 곱이라서, 둘을 같이 줄여야 체감이 나더라고요.

Karpenter 오토스케일 도입 전에 먼저 봐야 할 비용 지표

Karpenter를 붙였는데도 "그래서 얼마가 절감됐지?"를 설명하지 못하면 운영팀 설득이 어렵습니다. 감으로 보면 꼭 해석이 꼬입니다. 최소한 아래 지표는 같은 기간 기준으로 같이 보는 편이 좋습니다.

  • 노드 평균 사용률: CPU와 메모리 요청량 대비 실제 사용률
  • 유휴 시간: 야간 또는 비업무 시간에 노드가 얼마나 오래 남는지
  • 파드 Pending 빈도: 확장 지연이 발생하는지
  • 인스턴스 타입 다양성: 특정 타입에 과도하게 묶여 있는지
  • 스팟 비중: 안정성과 비용 균형이 맞는지

메트릭은 CloudWatch, Prometheus, Grafana 조합으로 많이 보고, 비용은 AWS Cost Explorer 또는 CUR로 맞춰보면 됩니다. 포인트는 하나입니다. 메트릭과 비용 데이터를 반드시 같은 기간으로 맞춰서 비교해야 한다는 점입니다.

Kubernetes 오토스케일링 구성, 이렇게 잡으면 시작이 편합니다

실전 구현 자체는 아주 복잡하지 않습니다. 다만 EKS 클러스터가 이미 있어야 하고, IRSA 또는 EKS Pod Identity 같은 AWS 권한 구성이 가능해야 합니다. 그리고 Karpenter가 파드 요청값을 기준으로 판단하므로 워크로드의 resources.requests가 비어 있으면 기대한 최적화가 잘 나오지 않습니다. 이 부분은 정말 중요합니다.

  1. EKS 클러스터 이름과 리전을 환경 변수로 설정합니다.
  2. Karpenter 컨트롤러용 IAM 역할과 중단 이벤트용 큐를 준비합니다.
  3. Helm으로 Karpenter를 설치합니다.
  4. NodePool과 EC2NodeClass를 정의합니다.
  5. 워크로드의 requests/limits를 다시 점검합니다.
export CLUSTER_NAME=my-eks
export AWS_DEFAULT_REGION=ap-northeast-2
export KARPENTER_NAMESPACE=karpenter
export KARPENTER_VERSION=1.14.0
export KARPENTER_IAM_ROLE_ARN=arn:aws:iam::123456789012:role/KarpenterControllerRole

aws eks update-kubeconfig --name $CLUSTER_NAME --region $AWS_DEFAULT_REGION
kubectl config current-context
kubectl get nodes

클러스터 연결부터 먼저 확인해두세요. 여기서 컨텍스트가 꼬이면 다른 클러스터에 배포하는 사고가 의외로 자주 납니다. 한 번만 겪어도 이 단계가 왜 중요한지 바로 느껴지더라고요.

Karpenter 설치 예시

helm upgrade --install karpenter oci://public.ecr.aws/karpenter/karpenter \
  --version $KARPENTER_VERSION \
  --namespace $KARPENTER_NAMESPACE \
  --create-namespace \
  --set settings.clusterName=$CLUSTER_NAME \
  --set settings.interruptionQueue=$CLUSTER_NAME \
  --set serviceAccount.annotations.eks\.amazonaws\.com/role-arn=$KARPENTER_IAM_ROLE_ARN \
  --wait

kubectl -n $KARPENTER_NAMESPACE get pods

설치가 끝나면 컨트롤러 파드가 정상 기동하는지 먼저 확인합니다. 여기서 CrashLoopBackOff가 보이면 IAM 권한, 서브넷 태그, 보안 그룹 태그, 이벤트 큐 설정부터 보는 게 빠릅니다.

Karpenter 오토스케일 설정과 NodePool 연결 구조 이미지

Karpenter 컨트롤러, NodePool, EC2NodeClass, 워크로드 파드가 어떻게 연결되는지 보여주는 구성 다이어그램입니다.

NodePool과 EC2NodeClass 예시

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: default
spec:
  template:
    spec:
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: default
      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: node.kubernetes.io/instance-type
          operator: In
          values: ["c6i.large", "m6i.large", "r6i.large"]
      expireAfter: 720h
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 5m
  limits:
    cpu: "200"
---
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
  name: default
spec:
  role: KarpenterNodeRole-my-eks
  amiSelectorTerms:
    - alias: al2023@latest
  subnetSelectorTerms:
    - tags:
        karpenter.sh/discovery: my-eks
  securityGroupSelectorTerms:
    - tags:
        karpenter.sh/discovery: my-eks

여기서 핵심은 세 가지입니다. 첫째, NodePool에는 nodeClassRef가 필요합니다. 둘째, 최근 EKS 기준으로는 AL2보다 AL2023 계열 AMI 선택이 더 자연스럽습니다. 셋째, consolidation을 켜야 유휴 노드 정리가 제대로 일어납니다. 실제 비용 절감은 스케일 아웃보다 이 정리 단계에서 더 크게 체감되는 경우가 많습니다.

테스트용 워크로드 배포

apiVersion: apps/v1
kind: Deployment
metadata:
  name: inflate
spec:
  replicas: 0
  selector:
    matchLabels:
      app: inflate
  template:
    metadata:
      labels:
        app: inflate
    spec:
      terminationGracePeriodSeconds: 0
      containers:
        - name: inflate
          image: public.ecr.aws/eks-distro/kubernetes/pause:3.7
          resources:
            requests:
              cpu: 1
kubectl apply -f inflate.yaml
kubectl scale deployment inflate --replicas 5
kubectl get pods -w

이렇게 테스트하면 Pending 상태였던 파드 수요를 Karpenter가 보고 새 노드를 띄우는 흐름을 확인할 수 있습니다. 이후 replicas를 다시 줄이거나 배포를 삭제해보면 노드 통합 정리까지 관찰할 수 있습니다. 작은 워크로드부터 붙여보는 방식이 운영 리스크도 낮고 결과도 해석하기 편합니다.

AWS EKS 비용 최적화를 위한 운영 포인트

이 섹션은 꼭 짚고 넘어가야 합니다. Karpenter를 도입했다고 자동으로 클라우드 비용 절감이 되진 않습니다. 정책을 어떻게 잡느냐에 따라 결과가 꽤 다르게 나옵니다.

  • requests를 현실적으로 작성: 과장된 요청값은 큰 노드를 계속 부릅니다.
  • 스팟과 온디맨드 혼합: 서비스 성격에 따라 풀을 나누는 편이 안정적입니다.
  • 워크로드 분리: API 서버 계열과 배치 계열을 같은 NodePool에 몰지 않는 게 좋습니다.
  • 스케일 인 여유 시간 확인: 너무 공격적으로 줄이면 재기동이 잦아질 수 있습니다.
  • PodDisruptionBudget 검토: 축소가 막혀 노드가 안 내려가는 경우가 생각보다 많습니다.

처음부터 모든 워크로드를 하나의 NodePool에 넣으면 정책 충돌이 생기기 쉽습니다. 최소한 안정성 우선 풀비용 우선 풀 정도는 분리해두면 운영이 훨씬 편합니다. 이거 진짜 편하더라고요.

⚠️ 실제로 많이 겪는 문제와 해결법

문서만 보면 금방 될 것 같아도 운영 환경에서는 자잘한 함정이 많습니다. 특히 권한, 태그, 요청값 같은 기본 설정에서 많이 막힙니다.

1. 노드가 아예 생성되지 않는 경우

대부분은 IAM 또는 태그 문제입니다. 서브넷과 보안 그룹에 karpenter.sh/discovery 태그가 빠져 있으면 인프라 리소스를 찾지 못합니다.

kubectl describe nodepool default
kubectl -n karpenter logs deploy/karpenter

로그에서 subnet, security group, instance profile, access denied 관련 메시지를 먼저 확인하면 원인이 빨리 보입니다.

2. 노드는 생기는데 비용이 생각보다 안 줄어드는 경우

이 경우도 자주 나옵니다. 원인은 대개 세 가지입니다.

  • 파드 requests가 과하게 큼
  • PodDisruptionBudget 때문에 빈 노드를 못 비움
  • 스팟 허용 범위가 너무 좁음

Karpenter가 덜 똑똑해서가 아니라 입력값이 비효율적인 경우가 많습니다. 결국 스케줄러와 오토스케일러도 선언된 요청값을 기준으로 움직이니까요.

3. 스팟 중단 대응이 불안한 경우

스팟은 비용 면에서 매력적이지만 서비스 성격에 따라 조심해야 합니다. 중단 알림을 받았을 때 드레이닝과 재스케줄링이 자연스럽게 되도록 준비가 필요합니다. 중요한 서비스는 무조건 스팟으로 몰기보다 온디맨드와 섞는 편이 안전합니다.

Karpenter 오토스케일 비용 절감 결과 대시보드 이미지

파드 수 증가에 따라 노드가 늘고, 유휴 시간대에 통합 정리로 노드 수가 줄어드는 메트릭 대시보드 예시입니다.

Karpenter 오토스케일 비용 절감 효과, 어떻게 검증해야 할까

여기서 중요한 건 "노드 수가 줄었다"로 끝내지 않는 겁니다. 노드 수는 줄었는데 더 비싼 타입을 오래 썼다면 의미가 없거든요. 저는 아래 순서로 비교하면 결과 해석이 가장 깔끔했습니다.

  1. 도입 전 2주와 도입 후 2주를 비교합니다.
  2. 같은 요일, 같은 시간대 기준으로 워크로드 패턴을 맞춥니다.
  3. EC2 비용, 노드 평균 개수, 평균 vCPU 사용률을 함께 봅니다.
  4. 배포 실패, Pending 시간, 재스케줄링 지연이 늘지 않았는지 확인합니다.
  5. 스팟 비중 증가가 장애로 이어지지 않았는지 점검합니다.

특히 비용 / 요청 처리량 같은 지표가 설명력이 좋습니다. 같은 트래픽을 처리하는데 필요한 EC2 비용이 줄었는지 보면, 단순 총액보다 훨씬 설득력이 있습니다. 팀 내 공유 문서에도 이 지표를 같이 적어두면 의사결정이 빨라집니다.

kubectl top nodes
kubectl top pods -A
aws ce get-cost-and-usage \
  --time-period Start=2026-07-01,End=2026-07-15 \
  --granularity DAILY \
  --metrics UnblendedCost \
  --group-by Type=DIMENSION,Key=SERVICE

위 명령은 비용 추세를 보는 기본 예시입니다. 참고로 Cost Explorer의 종료일은 보통 마지막 날짜 다음 날로 잡아야 비교가 깔끔합니다. 운영에서는 CUR를 Athena로 조회하거나 Grafana에 연결해 시계열로 보는 쪽이 더 편합니다.

해석할 때 주의할 점

  • 도입 직후 며칠은 캐시, 배포 주기, 스팟 수급 영향으로 흔들릴 수 있습니다.
  • 트래픽 자체가 줄어서 비용이 감소한 것을 Karpenter 효과로 착각하면 안 됩니다.
  • RI나 Savings Plans 영향도 함께 봐야 합니다.

결국 비교 기준은 같은 부하 조건이어야 합니다. 이 기준만 지켜도 해석 오류가 꽤 줄어듭니다.

정리: 이런 환경이라면 Karpenter 도입 가치가 큽니다

다음 조건에 해당하면 Karpenter 도입 효과가 비교적 잘 나옵니다.

  • 트래픽 변동폭이 크다
  • 워크로드 종류가 다양하다
  • EKS에서 인스턴스 타입 선택 폭을 넓게 가져갈 수 있다
  • 스팟 활용 여지가 있다
  • 현재 노드 유휴 시간이 길다

반대로 워크로드가 매우 단순하고 부하가 거의 고정되어 있다면 체감 효과가 크지 않을 수도 있습니다. 그래서 무조건 도입부터 하기보다, 현재 비효율이 어디서 생기는지 먼저 확인하는 편이 맞습니다. 그다음 작은 서비스에 시범 적용하고 결과를 비교하면 훨씬 덜 위험합니다.

Karpenter 오토스케일과 기존 오토스케일링 비교 인포그래픽

노드 그룹 기반 확장과 파드 요구사항 기반 확장의 차이를 한눈에 요약한 비교 이미지입니다.

마무리

이번 글의 핵심은 간단합니다. Karpenter 오토스케일은 단순한 증설 도구라기보다, AWS EKS 비용 최적화를 운영 레벨에서 밀어주는 도구에 가깝습니다. 다만 효과는 설치 여부보다 requests 품질, NodePool 정책, 스팟 전략, 검증 방식에 더 크게 좌우됩니다.

지금 EKS 비용이 애매하게 새고 있다고 느끼신다면, 전면 도입부터 하기보다 작은 워크로드에 먼저 붙여보세요. 그리고 이전 글의 HPA/VPA 튜닝 가이드도 함께 보시면 파드 스케일링과 노드 스케일링을 한 흐름으로 이해하는 데 도움이 됩니다. 다음 글에서는 스팟과 온디맨드 혼합 정책을 어떻게 설계해야 장애 없이 비용을 줄일 수 있는지 이어서 다뤄보겠습니다.

자주 묻는 질문

Karpenter만 도입하면 비용이 바로 줄어드나요?

아닙니다. requests 값, NodePool 정책, 스팟 허용 범위가 같이 맞아야 의미 있는 절감이 나옵니다.

Cluster Autoscaler를 꼭 버려야 하나요?

꼭 그렇진 않습니다. 다만 인스턴스 선택 유연성과 운영 단순성이 중요하다면 Karpenter가 더 잘 맞는 환경이 많습니다.

비용 절감 효과는 무엇으로 확인하나요?

총 EC2 비용만 보지 말고, 같은 트래픽 대비 비용, 노드 평균 사용률, 유휴 시간, Pending 감소 여부를 함께 보시면 됩니다.

반응형