- Authors

- Name
- Youngju Kim
- @fjvbn20031
목차
1. Karpenter란 무엇인가
Karpenter는 AWS가 개발한 오픈소스 쿠버네티스 노드 프로비저너입니다. 기존 Cluster Autoscaler가 Auto Scaling Group(ASG)을 통해 간접적으로 노드를 관리하는 것과 달리, Karpenter는 EC2 API를 직접 호출하여 워크로드에 최적화된 노드를 수십 초 만에 프로비저닝합니다.
핵심 특징
- 직접 EC2 프로비저닝: ASG 없이 EC2 Fleet API를 직접 호출
- 빠른 스케일링: 약 45
60초 내에 노드 온라인 (CA 대비 34분) - 지능형 인스턴스 선택: 워크로드 요구사항에 맞는 최적 인스턴스 타입 자동 선택
- 빈 패킹 최적화: 고급 빈 패킹 알고리즘으로 클러스터 활용률 극대화
- 자동 통합(Consolidation): 미사용 노드 자동 제거 및 저비용 노드로 교체
- 드리프트 감지: 설정 변경 시 자동으로 노드를 최신 상태로 교체
2. 왜 Karpenter인가: Cluster Autoscaler의 한계
Cluster Autoscaler의 문제점
+------------------------------------------+
| Cluster Autoscaler |
| |
| Pod Pending |
| | |
| v |
| CA가 ASG에 스케일 아웃 요청 |
| | |
| v |
| ASG가 미리 정의된 Launch Template로 |
| EC2 인스턴스 시작 |
| | |
| v |
| 노드 등록까지 3~5분 소요 |
+------------------------------------------+
Cluster Autoscaler는 다음과 같은 한계를 가집니다:
- ASG 의존성: 사전에 정의된 Node Group에 묶여 유연성이 떨어짐
- 느린 스케일링: ASG를 거치기 때문에 3~5분의 프로비저닝 시간 소요
- 인스턴스 타입 제한: Node Group별로 고정된 인스턴스 타입만 사용 가능
- 비효율적 빈 패킹: 노드 그룹 단위로만 스케일링하여 리소스 낭비 발생
- 수동 관리 부담: 다양한 워크로드를 위해 여러 Node Group을 수동으로 관리
Karpenter의 접근 방식
+------------------------------------------+
| Karpenter |
| |
| Pod Pending |
| | |
| v |
| Karpenter가 Pod 요구사항 분석 |
| (CPU, Memory, GPU, Topology 등) |
| | |
| v |
| 최적 인스턴스 타입 자동 선택 |
| (200+ 인스턴스 타입에서 비용 최적화) |
| | |
| v |
| EC2 Fleet API 직접 호출 |
| | |
| v |
| 45~60초 내 노드 Ready |
+------------------------------------------+
3. Karpenter 아키텍처
전체 구조
+----------------------------------------------------------------+
| EKS Cluster |
| |
| +------------------+ +-----------------------------+ |
| | Karpenter | | Kubernetes API Server | |
| | Controller |---->| (Pod Watch, Node Mgmt) | |
| | (Deployment) | +-----------------------------+ |
| +--------+---------+ |
| | |
| | NodePool + EC2NodeClass 참조 |
| | |
| +--------v---------+ +-----------------------------+ |
| | 인스턴스 타입 | | AWS Services | |
| | 선택 엔진 |---->| - EC2 Fleet API | |
| | (비용/용량 최적화)| | - SSM (AMI Discovery) | |
| +------------------+ | - Pricing API | |
| | - SQS (Interruption) | |
| | - EventBridge | |
| +-----------------------------+ |
+----------------------------------------------------------------+
핵심 컴포넌트
Karpenter는 세 가지 주요 CRD(Custom Resource Definition)를 사용합니다:
| CRD | API 버전 | 설명 |
|---|---|---|
| NodePool | karpenter.sh/v1 | 노드 프로비저닝 제약 조건 정의 |
| EC2NodeClass | karpenter.k8s.aws/v1 | AWS 고유 인스턴스 설정 |
| NodeClaim | karpenter.sh/v1 | 런타임에 생성되는 노드 요청 객체 |
프로비저닝 흐름
1. Pod가 Pending 상태로 감지됨
|
2. Karpenter가 Pod의 리소스 요청, nodeSelector,
affinity, tolerations 등을 분석
|
3. 매칭되는 NodePool 결정 (weight 기반 우선순위)
|
4. EC2NodeClass에서 AWS 설정 참조
(서브넷, 보안 그룹, AMI 등)
|
5. 최적 인스턴스 타입 선택
(비용, 용량, 요구사항 기반)
|
6. EC2 Fleet API로 인스턴스 시작
|
7. NodeClaim 객체 생성 및 추적
|
8. 노드 등록 완료 -> Pod 스케줄링
4. NodePool 상세 설정
NodePool은 Karpenter v1에서 기존 Provisioner를 대체하는 핵심 CRD입니다.
기본 NodePool 예제
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: default
spec:
template:
metadata:
labels:
team: platform
environment: production
spec:
requirements:
# 인스턴스 카테고리 제한
- key: karpenter.k8s.aws/instance-category
operator: In
values: ['c', 'm', 'r']
# 인스턴스 세대 제한
- key: karpenter.k8s.aws/instance-generation
operator: Gt
values: ['5']
# 용량 타입 (on-demand 또는 spot)
- key: karpenter.sh/capacity-type
operator: In
values: ['on-demand', 'spot']
# 가용 영역
- key: topology.kubernetes.io/zone
operator: In
values: ['ap-northeast-2a', 'ap-northeast-2b', 'ap-northeast-2c']
# 아키텍처
- key: kubernetes.io/arch
operator: In
values: ['amd64', 'arm64']
# EC2NodeClass 참조
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
# 노드 만료 시간 (72시간 후 자동 교체)
expireAfter: 72h
# 리소스 한도
limits:
cpu: '1000'
memory: 1000Gi
# 중단(Disruption) 정책
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 1m
budgets:
- nodes: '10%'
- nodes: '0'
schedule: '0 9 * * MON-FRI'
duration: 1h
# NodePool 가중치 (높을수록 우선)
weight: 50
requirements 주요 키
+---------------------------------------------+--------------------------------+
| Key | 설명 |
+---------------------------------------------+--------------------------------+
| karpenter.sh/capacity-type | on-demand 또는 spot |
| karpenter.k8s.aws/instance-category | 인스턴스 패밀리 (c, m, r 등) |
| karpenter.k8s.aws/instance-generation | 인스턴스 세대 (5, 6, 7 등) |
| karpenter.k8s.aws/instance-size | 인스턴스 크기 (large, xlarge) |
| karpenter.k8s.aws/instance-gpu-count | GPU 수량 |
| karpenter.k8s.aws/instance-gpu-name | GPU 이름 (a10g, t4 등) |
| topology.kubernetes.io/zone | 가용 영역 |
| kubernetes.io/arch | CPU 아키텍처 |
| kubernetes.io/os | 운영체제 |
+---------------------------------------------+--------------------------------+
다중 NodePool 전략
# 프로덕션 워크로드용 (On-Demand 전용, 높은 우선순위)
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: production
spec:
template:
metadata:
labels:
workload-type: production
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ['on-demand']
- key: karpenter.k8s.aws/instance-category
operator: In
values: ['m', 'r']
- key: karpenter.k8s.aws/instance-generation
operator: Gt
values: ['5']
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: production
expireAfter: 168h
limits:
cpu: '500'
memory: 500Gi
disruption:
consolidationPolicy: WhenEmpty
consolidateAfter: 5m
weight: 100
---
# 개발/테스트용 (Spot 허용, 낮은 우선순위)
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: development
spec:
template:
metadata:
labels:
workload-type: development
annotations:
dev-team: 'true'
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ['spot', 'on-demand']
- key: karpenter.k8s.aws/instance-category
operator: In
values: ['c', 'm']
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: development
expireAfter: 24h
limits:
cpu: '200'
memory: 200Gi
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 30s
weight: 10
5. EC2NodeClass 상세 설정
EC2NodeClass는 AWS 고유의 인스턴스 설정을 정의하는 CRD입니다.
완전한 EC2NodeClass 예제
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
name: default
spec:
# AMI 설정
amiSelectorTerms:
- alias: al2023@latest
# IAM 역할
role: KarpenterNodeRole-my-cluster
# 서브넷 선택
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: my-cluster
network-type: private
# 보안 그룹 선택
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: my-cluster
# 블록 디바이스 매핑
blockDeviceMappings:
- deviceName: /dev/xvda
ebs:
volumeSize: 100Gi
volumeType: gp3
iops: 3000
throughput: 125
encrypted: true
deleteOnTermination: true
# 메타데이터 옵션
metadataOptions:
httpEndpoint: enabled
httpProtocolIPv6: disabled
httpPutResponseHopLimit: 2
httpTokens: required
# 태그
tags:
Environment: production
ManagedBy: karpenter
Team: platform
# 사용자 데이터 (부트스트랩 스크립트)
userData: |
#!/bin/bash
echo "Karpenter managed node"
# 추가 부트스트랩 로직
AMI 선택 옵션
# 옵션 1: 별칭(alias) 사용 (권장)
amiSelectorTerms:
- alias: al2023@latest # Amazon Linux 2023 최신
# - alias: al2@latest # Amazon Linux 2
# - alias: bottlerocket@latest # Bottlerocket
# 옵션 2: 태그 기반 선택
amiSelectorTerms:
- tags:
environment: production
ami-type: custom-al2023
# 옵션 3: AMI ID 직접 지정
amiSelectorTerms:
- id: ami-0123456789abcdef0
지원하는 AMI 패밀리
+-----------------+------------------------------------------+
| AMI Family | 설명 |
+-----------------+------------------------------------------+
| AL2023 | Amazon Linux 2023 (권장) |
| AL2 | Amazon Linux 2 |
| Bottlerocket | AWS Bottlerocket (컨테이너 전용 OS) |
| Windows2019 | Windows Server 2019 |
| Windows2022 | Windows Server 2022 |
| Windows2025 | Windows Server 2025 |
+-----------------+------------------------------------------+
6. 통합(Consolidation): 비용 최적화의 핵심
Karpenter의 Consolidation은 클러스터 비용을 자동으로 최적화하는 핵심 기능입니다.
Consolidation 동작 방식
Consolidation 유형:
+------------------------------------------------------------------+
| |
| 1. 삭제(Delete) Consolidation |
| - 노드의 모든 Pod가 다른 노드에서 실행 가능한 경우 |
| - 해당 노드를 안전하게 제거 |
| |
| 2. 교체(Replace) Consolidation |
| - 현재 노드를 더 작고 저렴한 인스턴스로 교체 가능한 경우 |
| - 새 노드 프로비저닝 -> Pod 마이그레이션 -> 구 노드 제거 |
| |
+------------------------------------------------------------------+
Consolidation 정책 설정
# 정책 1: 빈 노드만 통합
disruption:
consolidationPolicy: WhenEmpty
consolidateAfter: 30s
# 정책 2: 빈 노드 + 미활용 노드 통합 (권장)
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 1m
Disruption Budget으로 속도 제어
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 1m
budgets:
# 전체 노드의 10%까지만 동시에 중단 허용
- nodes: '10%'
# 업무 시간에는 중단 차단
- nodes: '0'
schedule: '0 9 * * MON-FRI'
duration: 8h
# 특정 사유에 대해서만 예산 적용 (v1.0+)
- nodes: '5%'
reasons:
- 'Underutilized'
Spot-to-Spot Consolidation
Spot 인스턴스 간 통합은 최소 15개 이상의 인스턴스 타입이 설정되어야 활성화됩니다.
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: spot-optimized
spec:
template:
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ['spot']
# 다양한 인스턴스 타입으로 Spot-to-Spot 통합 활성화
- key: karpenter.k8s.aws/instance-category
operator: In
values: ['c', 'm', 'r']
- key: karpenter.k8s.aws/instance-generation
operator: Gt
values: ['4']
- key: karpenter.k8s.aws/instance-size
operator: In
values: ['large', 'xlarge', '2xlarge', '4xlarge']
7. 드리프트 감지(Drift Detection)
드리프트 감지는 NodePool이나 EC2NodeClass의 설정이 변경되었을 때, 기존 노드가 최신 설정과 일치하지 않는 것을 탐지하고 자동으로 교체하는 기능입니다.
드리프트가 감지되는 경우
+---------------------------------------------------+
| 드리프트 감지 시나리오 |
+---------------------------------------------------+
| - AMI가 업데이트된 경우 |
| - NodePool의 requirements가 변경된 경우 |
| - EC2NodeClass의 보안 그룹이 변경된 경우 |
| - EC2NodeClass의 서브넷이 변경된 경우 |
| - 블록 디바이스 설정이 변경된 경우 |
| - 메타데이터 옵션이 변경된 경우 |
| - 태그가 변경된 경우 |
+---------------------------------------------------+
드리프트 교체 프로세스
1. Karpenter가 NodeClaim과 현재 NodePool/EC2NodeClass 비교
|
2. 차이 발견 시 NodeClaim에 Drifted 상태 표시
|
3. Disruption Budget 확인
|
4. 새 노드 프로비저닝 (최신 설정 적용)
|
5. 기존 노드의 Pod를 안전하게 drain
|
6. 기존 노드 종료
8. 인터럽션 처리(Interruption Handling)
Karpenter는 다양한 EC2 인터럽션 이벤트를 자동으로 처리합니다.
지원하는 인터럽션 유형
+-----------------------------+----------------------------------------+
| 인터럽션 유형 | 설명 |
+-----------------------------+----------------------------------------+
| Spot Interruption | 2분 전 경고로 Spot 회수 알림 |
| Rebalance Recommendation | 중단 위험 증가 시 사전 알림 |
| Scheduled Maintenance | AWS 예정된 유지보수 이벤트 |
| Instance State Change | 인스턴스 상태 변경 (stopping, stopped) |
+-----------------------------+----------------------------------------+
SQS 기반 인터럽션 처리 아키텍처
+-------------------+ +-------------------+ +------------------+
| EC2 Spot | | Amazon | | Amazon |
| Interruption |---->| EventBridge |---->| SQS Queue |
| Notice | | Rules | | |
+-------------------+ +-------------------+ +--------+---------+
|
+-------------------+ +-------------------+ |
| EC2 Rebalance |---->| EventBridge |----+ |
| Recommendation | | | | |
+-------------------+ +-------------------+ | |
v v
+----+---------+----+
| Karpenter |
| Controller |
| |
| 1. 이벤트 수신 |
| 2. 노드 Cordon |
| 3. Pod Drain |
| 4. 새 노드 시작 |
| 5. 기존 노드 종료 |
+-------------------+
인터럽션 처리 설정
Helm 설치 시 SQS 큐 이름을 지정합니다:
helm install karpenter oci://public.ecr.aws/karpenter/karpenter \
--version "1.0.0" \
--namespace karpenter \
--create-namespace \
--set "settings.clusterName=my-cluster" \
--set "settings.interruptionQueue=my-cluster-karpenter" \
--set controller.resources.requests.cpu=1 \
--set controller.resources.requests.memory=1Gi \
--set controller.resources.limits.cpu=1 \
--set controller.resources.limits.memory=1Gi
9. Spot 인스턴스 베스트 프랙티스
다양한 인스턴스 타입 설정
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: spot-diverse
spec:
template:
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ['spot']
# 다양한 인스턴스 패밀리로 Spot 가용성 확보
- key: karpenter.k8s.aws/instance-category
operator: In
values: ['c', 'm', 'r', 'c', 'm']
# 여러 세대 허용
- key: karpenter.k8s.aws/instance-generation
operator: In
values: ['5', '6', '7']
# 다양한 크기 허용
- key: karpenter.k8s.aws/instance-size
operator: In
values: ['large', 'xlarge', '2xlarge', '4xlarge']
# 여러 가용 영역
- key: topology.kubernetes.io/zone
operator: In
values: ['ap-northeast-2a', 'ap-northeast-2b', 'ap-northeast-2c']
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
Spot + On-Demand 혼합 전략
# Spot 우선 NodePool (높은 가중치)
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: spot-first
spec:
template:
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ['spot']
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
weight: 100
limits:
cpu: '500'
---
# On-Demand 대체 NodePool (낮은 가중치)
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: on-demand-fallback
spec:
template:
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ['on-demand']
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
weight: 1
limits:
cpu: '200'
Spot 사용 시 주의사항
- 다양한 인스턴스 타입 허용: 최소 15개 이상의 인스턴스 타입을 허용하여 Spot 가용성을 극대화
- 여러 가용 영역 사용: 단일 AZ에 의존하지 않고 여러 AZ에 걸쳐 Spot 용량 확보
- PDB(Pod Disruption Budget) 설정: 중요 워크로드에 PDB를 설정하여 최소 가용성 보장
- Graceful Shutdown 처리: terminationGracePeriodSeconds를 적절히 설정
10. Helm을 통한 Karpenter 설치
사전 준비
# 환경 변수 설정
export KARPENTER_NAMESPACE="karpenter"
export KARPENTER_VERSION="1.0.0"
export CLUSTER_NAME="my-eks-cluster"
export AWS_ACCOUNT_ID="$(aws sts get-caller-identity --query Account --output text)"
export TEMPOUT="$(mktemp)"
IAM 역할 생성
# Karpenter 컨트롤러 역할 생성
aws iam create-role \
--role-name "KarpenterControllerRole-${CLUSTER_NAME}" \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::oidc-provider/oidc.eks.REGION.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
},
"Action": "sts:AssumeRoleWithWebIdentity"
}]
}'
# Karpenter 노드 역할 생성
aws iam create-role \
--role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}]
}'
Helm 설치
# Helm 리포지토리 추가 (OCI)
helm 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}-karpenter" \
--set "serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn=arn:aws:iam::${AWS_ACCOUNT_ID}:role/KarpenterControllerRole-${CLUSTER_NAME}" \
--set controller.resources.requests.cpu=1 \
--set controller.resources.requests.memory=1Gi \
--set controller.resources.limits.cpu=1 \
--set controller.resources.limits.memory=1Gi \
--wait
설치 확인
# Karpenter Pod 상태 확인
kubectl get pods -n karpenter
# CRD 확인
kubectl get crd | grep karpenter
# 로그 확인
kubectl logs -n karpenter -l app.kubernetes.io/name=karpenter -f
11. 완전한 배포 예제
전체 구성 (NodePool + EC2NodeClass)
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
name: production
spec:
amiSelectorTerms:
- alias: al2023@latest
role: KarpenterNodeRole-my-cluster
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: my-cluster
network-type: private
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: my-cluster
blockDeviceMappings:
- deviceName: /dev/xvda
ebs:
volumeSize: 100Gi
volumeType: gp3
iops: 3000
throughput: 125
encrypted: true
deleteOnTermination: true
metadataOptions:
httpEndpoint: enabled
httpPutResponseHopLimit: 2
httpTokens: required
tags:
Environment: production
ManagedBy: karpenter
---
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: production
spec:
template:
metadata:
labels:
environment: production
managed-by: karpenter
spec:
requirements:
- key: karpenter.k8s.aws/instance-category
operator: In
values: ['c', 'm', 'r']
- key: karpenter.k8s.aws/instance-generation
operator: Gt
values: ['5']
- key: karpenter.sh/capacity-type
operator: In
values: ['on-demand']
- key: topology.kubernetes.io/zone
operator: In
values: ['ap-northeast-2a', 'ap-northeast-2b', 'ap-northeast-2c']
- key: kubernetes.io/arch
operator: In
values: ['amd64']
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: production
expireAfter: 168h
limits:
cpu: '1000'
memory: 2000Gi
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 2m
budgets:
- nodes: '10%'
- nodes: '0'
schedule: '0 2 * * *'
duration: 1h
weight: 100
테스트 워크로드 배포
apiVersion: apps/v1
kind: Deployment
metadata:
name: inflate
namespace: default
spec:
replicas: 0
selector:
matchLabels:
app: inflate
template:
metadata:
labels:
app: inflate
spec:
containers:
- name: inflate
image: public.ecr.aws/eks-distro/kubernetes/pause:3.7
resources:
requests:
cpu: '1'
memory: 1Gi
# 스케일 업하여 Karpenter 프로비저닝 트리거
kubectl scale deployment inflate --replicas=10
# 노드 프로비저닝 확인
kubectl get nodes -w
# NodeClaim 상태 확인
kubectl get nodeclaims
# 스케일 다운하여 Consolidation 확인
kubectl scale deployment inflate --replicas=0
12. Karpenter vs Cluster Autoscaler 비교표
+-----------------------------+----------------------------+----------------------------+
| 항목 | Karpenter | Cluster Autoscaler |
+-----------------------------+----------------------------+----------------------------+
| 프로비저닝 방식 | EC2 API 직접 호출 | ASG 통한 간접 호출 |
| 프로비저닝 속도 | 45~60초 | 3~5분 |
| 인스턴스 선택 | 자동 최적화 (200+ 타입) | Node Group 고정 타입 |
| 빈 패킹 | Pod 단위 최적화 | Node Group 단위 |
| Consolidation | 내장 (자동) | 제한적 (scale-down) |
| 드리프트 감지 | 자동 | 미지원 |
| Spot 인스턴스 | 네이티브 지원, 자동 다각화 | ASG Mixed Instances |
| Spot 인터럽션 처리 | SQS 기반 자동 처리 | 별도 도구 필요 |
| 멀티 아키텍처 | AMD64 + ARM64 자동 선택 | 별도 Node Group 필요 |
| 설정 복잡도 | NodePool + EC2NodeClass | ASG + Launch Template |
| 멀티 클라우드 | AWS 전용 (커뮤니티 확장) | 공식 멀티 클라우드 |
| 비용 절감 효과 | 25~40% (빈패킹 + Spot) | 10~20% |
| 쿠버네티스 공식 프로젝트 | 아니오 (AWS 주도) | 예 (SIG Autoscaling) |
+-----------------------------+----------------------------+----------------------------+
13. 자주 발생하는 문제와 해결
Pod가 Pending 상태로 남는 경우
# NodePool 요구사항 확인
kubectl describe nodepool default
# Karpenter 로그에서 프로비저닝 실패 원인 확인
kubectl logs -n karpenter -l app.kubernetes.io/name=karpenter | grep -i "error\|failed"
# Pod 이벤트 확인
kubectl describe pod [pod-name]
일반적인 원인과 해결 방법
- 서브넷 또는 보안 그룹 태그 미설정: EC2NodeClass의 selector 태그가 실제 AWS 리소스에 적용되어 있는지 확인
- IAM 권한 부족: Karpenter 컨트롤러 역할에 필요한 EC2, IAM, SSM 권한 확인
- 리소스 한도 초과: NodePool의 limits 설정이 현재 사용량을 초과하지 않는지 확인
- 인스턴스 타입 가용성: 특정 AZ에서 해당 인스턴스 타입의 용량이 부족한 경우
14. 마무리
Karpenter는 쿠버네티스 노드 프로비저닝의 패러다임을 바꾸고 있습니다. ASG 기반의 정적인 노드 관리에서 벗어나, 워크로드 중심의 동적 인프라 프로비저닝이 가능해졌습니다.
도입 권장 시나리오
- 다양한 인스턴스 타입이 필요한 워크로드
- Spot 인스턴스를 적극 활용하고 싶은 경우
- 빠른 스케일링이 중요한 이벤트성 워크로드
- 비용 최적화가 핵심 목표인 클러스터
- GPU/ML 워크로드가 포함된 환경
주의사항
- AWS EKS 전용이므로 멀티 클라우드 환경에서는 Cluster Autoscaler 병행 고려
- v1.0+ 안정 버전 사용을 권장
- SQS 큐 설정으로 Spot 인터럽션 처리 반드시 활성화
- NodePool의 limits를 적절히 설정하여 비용 폭주 방지