[CloudNeta] EKS 워크샵 스터디 (5) - EKS 디버깅 마스터 가이드 (2)

이번 게시글에서는 EKS 워크샵 스터디 제 5주차 내용을 작성합니다.

이 글은 3부로 나누어집니다.

  1. 5주차 - EKS 디버깅 마스터 가이드 (1)
  2. 5주차 - EKS 디버깅 마스터 가이드 (2) (현재 보고계신 글)
  3. 5주차 - EKS 디버깅 마스터 가이드 (3)

V. 네트워킹 디버깅 워크플로우

VPC CNI → DNS → Service → NetworkPolicy 순 계층별 진단 흐름을 살펴봅시다.

flowchart TB
    START([네트워크 문제 감지])
    D1[VPC CNI 점검]
    D2[DNS 해석 확인]
    D3[Service 연결]
    D4[NetworkPolicy]

    DT1[IP 고갈 / ENI 제한Prefix Delegation]
    DT2[CoreDNS OOMndots:5 / DNSCache]
    DT3[Selector 불일치port/targetPort]
    DT4[AND vs OR 혼동Default Deny]

    GW[Gateway API]
    NS[netshoot 디버깅]

    START -->|파드 IP 미할당| D1
    START -->|DNS 실패| D2
    START -->|연결 불가| D3
    START -->|차단 의심| D4

    D1 --> DT1
    D2 --> DT2
    D3 --> DT3
    D4 --> DT4

    D3 -.->|Ingress/LB| GW
    D4 -.->|패킷 분석| NS

    style START fill:#ff4444,stroke:#cc3636,color:#fff
    style D1 fill:#4286f4,stroke:#2a6acf,color:#fff
    style D2 fill:#4286f4,stroke:#2a6acf,color:#fff
    style D3 fill:#4286f4,stroke:#2a6acf,color:#fff
    style D4 fill:#ff9900,stroke:#cc7a00,color:#fff
    style DT1 fill:#fbbc04,stroke:#c99603,color:#000
    style DT2 fill:#fbbc04,stroke:#c99603,color:#000
    style DT3 fill:#fbbc04,stroke:#c99603,color:#000
    style DT4 fill:#ff4444,stroke:#cc3636,color:#fff
    style GW fill:#4286f4,stroke:#2a6acf,color:#fff
    style NS fill:#10b981,stroke:#0d8a63,color:#fff

증상 → 진단 경로 요약

위의 증상과 그에 대해 어떤 부분을 점검하고 그 주요 원인이 무엇인지 살펴봅시다.

증상 1차 점검 주요 원인
파드 IP 미할당 VPC CNI IP 고갈 / ENI 제한 → Prefix Delegation
DNS 실패 DNS 해석 CoreDNS OOM, ndots:5 문제, DNSCache 부재
연결 불가 Service 연결 Selector 불일치, port / targetPort 설정 오류
차단 의심 NetworkPolicy AND vs OR 혼동, Default Deny 누락

보조 도구: Ingress/LB 재설계 시 Gateway API, 패킷 레벨 분석은 netshoot 컨테이너로 진단

VPC CNI: IP 고갈 & ENI 제한

문제 증상 / 내용 대응
IP 고갈 서브넷의 사용 가능 IP 부족 → 파드가 ContainerCreating에서 멈춤 서브넷 확장 / Secondary CIDR
ENI 제한 인스턴스 타입별 ENI 수 × ENI당 IP 제한 (c5.xlarge: 4 ENI × 15 IP = 최대 58 파드) 인스턴스 타입 상향
Prefix Delegation ENI에 /28 prefix(16 IP) 할당 → IP 용량 16배 확대 (c5.xlarge: 최대 110 파드) 아래 명령어로 활성화

진단 및 활성화

# 서브넷별 사용 가능 IP 확인
aws ec2 describe-subnets --subnet-ids <subnet-id> \
  --query 'Subnets[].{ID:SubnetId,AZ:AvailabilityZone,Available:AvailableIpAddressCount}'

# Prefix Delegation 활성화 (IP 용량 16배)
kubectl set env daemonset aws-node -n kube-system ENABLE_PREFIX_DELEGATION=true

# 노드의 현재 ENI / 파드 수 확인
kubectl get nodes -o json | jq '.items[] | {name: .metadata.name, allocatable_pods: .status.allocatable.pods}'

Service 연결 실패 진단

flowchart TB
    START([Service 연결 실패])
    D1[Endpoints 확인]
    D2A[Selector 라벨 불일치]
    D2B[Pod Not Ready]
    D3A[port / targetPort 불일치]
    D3B[kube-proxy / SG]

    START --> D1
    D1 -->|Endpoints 비어있음| D2A
    D1 -->|Endpoints 비어있음| D2B
    D1 -->|IP 존재| D3A
    D1 -->|IP 존재| D3B

    style START fill:#ff4444,stroke:#cc3636,color:#fff
    style D1 fill:#fbbc04,stroke:#c99603,color:#000
    style D2A fill:#10b981,stroke:#0d8a63,color:#fff
    style D2B fill:#10b981,stroke:#0d8a63,color:#fff
    style D3A fill:#10b981,stroke:#0d8a63,color:#fff
    style D3B fill:#10b981,stroke:#0d8a63,color:#fff

핵심 진단 명령어

# Endpoints 확인 (비어있으면 Selector 불일치)
kubectl get endpoints <service-name>

# Service selector와 파드 label 비교
kubectl get svc <svc> -o jsonpath='{.spec.selector}'
kubectl get pods --show-labels

# 파드가 실제 리스닝하는 포트 확인
kubectl get pod <pod> -o jsonpath='{.spec.containers[*].ports[*].containerPort}'

DNS 디버깅: CoreDNS & ndots

문제 증상 대응
⚠️ CoreDNS OOM 5,000+ Pod 클러스터에서 쿼리 급증 시 OOMKilled → 클러스터 전체 DNS 해석 실패 메모리 증가 + NodeLocal DNSCache
🌐 ndots:5 문제 외부 도메인 조회 시 5번 불필요한 쿼리 (api.example.com → 4번 실패 후 성공) ndots:2 또는 trailing dot(.) 사용
NodeLocal DNSCache 각 노드에 DNS 캐시 → CoreDNS 부하 감소 (VPC DNS 한도: ENI당 1,024 pkt/s) 대규모 클러스터 필수

진단 명령어

# CoreDNS 상태 확인
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl top pods -n kube-system -l k8s-app=kube-dns

# 파드 내부 resolv.conf 확인 (ndots 값)
kubectl exec <pod> -- cat /etc/resolv.conf

# DNS 해석 테스트
kubectl run -it --rm debug --image=busybox --restart=Never -- nslookup kubernetes.default

NetworkPolicy 디버깅

함정 내용
🚫 Default Deny podSelector: {}로 모든 ingress 차단 - Allow 규칙 선작성 없이 적용하면 전체 트래픽 차단
🔀 AND vs OR 혼동 indent 한 레벨 차이로 보안 정책이 완전히 달라짐. 같은 from 항목 = AND(교집합), 별도 from 항목 = OR(합집합)
🏷️ namespaceSelector 라벨 namespaceSelector는 네임스페이스에 라벨이 있어야 동작. kubectl label ns prod user=alice 필수

AND vs OR - indent 차이에 주의

# AND: "alice NS의 client 파드"만 허용
ingress:
  - from:
      - namespaceSelector:        # ← 같은 from 항목
          matchLabels: { user: alice }
        podSelector:              # ← AND 결합
          matchLabels: { role: client }

# OR: "alice NS 전체" 또는 "모든 NS의 client Pod"
ingress:
  - from:
      - namespaceSelector:        # ← 첫 번째 from
          matchLabels: { user: alice }
      - podSelector:              # ← 두 번째 from (OR)
          matchLabels: { role: client }

Gateway API 디버깅

flowchart LR
    GC[GatewayClass]
    GW[Gateway]
    HR[HTTPRoute]
    SVC[Service]

    GC --> GW --> HR --> SVC

    GC -.- C1[Accepted 조건
controller 매칭] GW -.- C2[Programmed 조건
LB 프로비저닝] HR -.- C3[ResolvedRefs 조건
parentRef / backendRef 매칭] SVC -.- C4[Endpoints Health Check] style GC fill:#4286f4,stroke:#2a6acf,color:#fff style GW fill:#4286f4,stroke:#2a6acf,color:#fff style HR fill:#4286f4,stroke:#2a6acf,color:#fff style SVC fill:#4286f4,stroke:#2a6acf,color:#fff style C1 fill:#fbbc04,stroke:#c99603,color:#000 style C2 fill:#fbbc04,stroke:#c99603,color:#000 style C3 fill:#fbbc04,stroke:#c99603,color:#000 style C4 fill:#fbbc04,stroke:#c99603,color:#000

상태 점검 순서

# 1. GatewayClass 상태 확인 (Accepted 조건)
kubectl get gatewayclass
kubectl describe gatewayclass <name>

# 2. Gateway 상태 확인 (Programmed 조건 = LB 프로비저닝)
kubectl get gateway -A
kubectl describe gateway <name> -n <ns>

# 3. HTTPRoute 상태 확인 (ResolvedRefs = parentRef/backendRef 매칭)
kubectl get httproute -A
kubectl describe httproute <name> -n <ns>

# 4. 최종 Target Group Health 확인
aws elbv2 describe-target-health --target-group-arn <tg-arn>

netshoot 실전 디버깅

모드 내용
Ephemeral Container 기존 파드에 디버그 컨테이너 주입 - 파드 재시작 없이 네트워크 진단
포함 도구 curl, dig, tcpdump, iperf3, ss, traceroute, mtr, nslookup
독립 디버깅 파드 임시 파드로 클러스터 내부 네트워크 테스트 - 종료 시 자동 삭제 (--rm)

실전 사용법

# 기존 파드에 ephemeral container로 추가
kubectl debug <pod-name> -it --image=nicolaka/netshoot

# 독립 디버깅 파드 실행
kubectl run tmp-shell --rm -i --tty --image nicolaka/netshoot -- bash

# DNS 해석 확인
dig <service>.<namespace>.svc.cluster.local

# TCP 연결 테스트
curl -v http://<service>.<namespace>.svc.cluster.local:<port>/health

# 패킷 캡처 (특정 파드 IP 트래픽)
tcpdump -i any host <pod-ip> -n

# 소켓 상태 확인
ss -tunap

VI. PVC 마운트 실패 4대 패턴

개요

PVC 마운트가 실패하는 4가지 패턴을 살펴봅시다.

패턴 원인 대응
AZ 불일치 EBS 볼륨은 단일 AZ에 존재 - 파드가 다른 AZ 노드에 스케줄되면 마운트 실패 volumeBindingMode: WaitForFirstConsumer
볼륨 제한 초과 인스턴스 타입별 최대 EBS 볼륨 수 제한 (Nitro: 타입별 상이, 최대 128개) 더 큰 인스턴스 타입 또는 볼륨 분산
ReadWriteOnce (RWO) EBS는 RWO만 지원 - 여러 노드 동시 마운트 불가 → Multi-Attach 에러 다중 접근 필요 시 EFS (ReadWriteMany)
Detach 지연 (~6분) 이전 파드 삭제 후에도 EBS 볼륨이 즉시 해제 안 됨 - AWS API detach 최대 6분 강제 detach는 데이터 손실 위험 - 기다릴 것

EBS vs EFS 비교

항목 EBS (gp3) EFS
접근 모드 ReadWriteOnce (단일 노드) ReadWriteMany (다중 노드)
성능 최대 16,000 IOPS / 1,000 MB/s 탄력적 처리량 (Bursting / Provisioned)
AZ 제약 단일 AZ 종속 다중 AZ 자동 복제
적합 시나리오 DB, StatefulSet, 단일 파드 공유 파일, CMS, 로그 수집
비용 용량 + IOPS 기반 과금 사용량 기반 과금 (GB당)
CSI Driver ebs.csi.aws.com efs.csi.aws.com
Auto Mode 내장 지원 (gp3 기본) EFS CSI 별도 설치 필요
주요 제약 Multi-Attach 불가, AZ 종속 Mount Target SG TCP 2049 필수

판단 기준: 여러 파드가 동시에 같은 볼륨에 접근해야 하면 EFS, 단일 파드 고성능 I/O가 필요하면 EBS (gp3)

스토리지 성능 최적화

주제 내용
gp3 IOPS 튜닝 기본 3,000 IOPS / 125 MB/s → 최대 16,000 IOPS / 1,000 MB/s. IOPS : 처리량 비율 최소 4:1
볼륨 확장 allowVolumeExpansion: true 필수. PVC patch로 온라인 확장 가능 - 축소는 불가
고아 볼륨 정리 Finalizer 수동 제거 시 고아 EBS 볼륨 발생 → 주기적으로 available 상태 볼륨 확인 (비용 낭비 방지)

실전 명령어

# gp3 고성능 StorageClass 생성
cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata: { name: fast-ebs }
provisioner: ebs.csi.aws.com
parameters: { type: gp3, iops: "16000", throughput: "1000" }
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
EOF

# 볼륨 확장 (온라인)
kubectl patch pvc <pvc> -p '{"spec":{"resources":{"requests":{"storage":"50Gi"}}}}'

# 고아 볼륨 찾기
aws ec2 describe-volumes \
  --filters "Name=tag:kubernetes.io/created-for/pvc/name,Values=*" \
  --query 'Volumes[?State==`available`].{ID:VolumeId,PVC:Tags[?Key==`kubernetes.io/created-for/pvc/name`]|[0].Value}'

Auto Mode 스토리지 제약

항목 동작
내장 EBS 드라이버 gp3 기본 지원 - 별도 CSI Driver 설치 불필요. WaitForFirstConsumer 자동, allowVolumeExpansion: true 기본
gp2 미지원 기본 gp3. gp2 StorageClass 사용 불가, io2 Block Express 미지원. 기본 EBS 암호화 제공
EFS 별도 설치 EFS CSI Driver는 Auto Mode 자동 관리 대상 아님. ReadWriteMany 필요 시 수동 설치. FSx for Lustre도 별도

Auto Mode 지원 매트릭스

볼륨 타입 지원 상태
gp3 내장 지원
gp2 미지원
io2 제한적 (Block Express 미지원)
EFS 별도 설치 필요
FSx for Lustre 별도 설치 필요

VII. GPU 진단

워크플로우 살펴보기

nvidia-smi → Driver → CUDA → Device Plugin → DCGM 순서로 계층별 진단

flowchart TB
    START([GPU 문제 발생])
    D1[nvidia-smi 실행?]
    D2[GPU 인식됨?]
    D3[CUDA 버전 호환?]
    D4[Device Plugin 동작?]
    D5[DCGM 메트릭 정상?]

    A1[Driver 설치 확인]
    A2[Driver/CUDA 매칭]
    A3[ClusterPolicy 확인]
    A4[워크로드 레벨 디버깅]

    START --> D1
    D1 -->|실패| A1
    D1 -->|성공| D2
    D2 -->|미인식| A1
    D2 -->|인식됨| D3
    D3 -->|불일치| A2
    D3 -->|호환| D4
    D4 -->|미동작| A3
    D4 -->|정상| D5
    D5 -->|정상| A4

    style START fill:#ff4444,stroke:#cc3636,color:#fff
    style D1 fill:#fbbc04,stroke:#c99603,color:#000
    style D2 fill:#fbbc04,stroke:#c99603,color:#000
    style D3 fill:#fbbc04,stroke:#c99603,color:#000
    style D4 fill:#fbbc04,stroke:#c99603,color:#000
    style D5 fill:#fbbc04,stroke:#c99603,color:#000
    style A1 fill:#10b981,stroke:#0d8a63,color:#fff
    style A2 fill:#10b981,stroke:#0d8a63,color:#fff
    style A3 fill:#10b981,stroke:#0d8a63,color:#fff
    style A4 fill:#10b981,stroke:#0d8a63,color:#fff

CUDA XID 에러 패턴

XID 의미 원인 조치
31 GPU memory page fault 잘못된 메모리 접근 드라이버 업데이트, 메모리 할당 검증
43 GPU stopped responding GPU 응답 없음 노드 재시작
48 Double bit ECC error 하드웨어 메모리 결함 노드 교체 필수 (영구 결함)
74 NVLink error GPU 간 통신 실패 NVLink 토폴로지 확인, 케이블 점검
79 GPU fallen off the bus PCIe 통신 단절 노드 교체 필수 (하드웨어 결함)
94 Contained error 메모리 무결성 오류 ECC 모드 확인, 노드 교체 검토

XID 에러 확인

# 커널 로그에서 XID 에러 검색
kubectl debug node/<gpu-node> -it --image=ubuntu
dmesg | grep -i "xid"

# 출력 예시 (하드웨어 결함)
# [123.456] NVRM: Xid (PCI:0000:10:1c): 79, GPU has fallen off the bus.
# → XID 48, 79: 즉시 노드 교체

NCCL Timeout 디버깅

체크 포인트 내용
멀티노드 통신 분산 학습 시 노드 간 NCCL 타임아웃 - 파드 간 통신 확인이 최우선
EFA 설정 p4d/p5 인스턴스: EFA Device Plugin 설치 필수, vpc.amazonaws.com/efa 리소스 요청
Security Group 동일 SG 내부 모든 트래픽 허용 - SG self-referencing rule 확인
환경변수 NCCL_SOCKET_IFNAME, NCCL_IB_DISABLE 설정, WORLD_SIZE / RANK 매칭 필수

NCCL 디버그 환경변수

env:
  - name: NCCL_DEBUG
    value: "INFO"            # 디버그 로그 활성화
  - name: NCCL_DEBUG_SUBSYS
    value: "ALL"
  - name: NCCL_SOCKET_IFNAME
    value: "eth0"            # VPC CNI 기본 인터페이스
  - name: NCCL_IB_DISABLE
    value: "1"               # EKS에서 InfiniBand 비활성화
# 파드 간 통신 테스트
kubectl exec -it <pod> -- nc -zv <target-pod-ip> 12345

vLLM 디버깅

주제 내용
gpu_memory_utilization 기본 0.9 (GPU 메모리 90%). OOM 시 0.850.8 단계적 감소, 낭비 시 0.95까지 증가
OOM vs KV Cache 모델 로드 OOM → 더 큰 GPU 또는 Quantization (AWQ / GPTQ) / "No available blocks" → KV Cache 부족, max_model_len 감소
Tensor Parallel --tensor-parallel-size = 파드 GPU 수 일치. H100×8 → TP=8 (70B 모델). TP 수는 hidden dim 약수 (2, 4, 8)

vLLM 파라미터 튜닝 예시

args:
  - --model=/models/llama-3.1-70b
  - --tensor-parallel-size=4        # GPU 수와 일치
  - --gpu-memory-utilization=0.85   # OOM 시 감소 (기본 0.9)
  - --max-model-len=8192            # KV Cache 크기 결정
  - --max-num-batched-tokens=8192   # 처리량/지연 균형
  - --max-num-seqs=256              # 동시 처리 시퀀스 수
  - --swap-space=4                  # CPU 메모리 스왑 공간 (GiB)

튜닝 순서: OOM → gpu_memory_utilization 감소 → max_model_len 감소 → max_num_seqs 감소

GPU Operator 컴포넌트 구조

flowchart TB
    CP[ClusterPolicy]
    D[NVIDIA Driver]
    CT[Container Toolkit]
    DP[Device Plugin]
    DE[DCGM Exporter]
    GFD[GPU Feature Discovery]
    OV[Operator Validator]
    NODE([Node: nvidia.com/gpu])

    CP --> D
    CP --> CT
    CP --> DP
    CP --> DE
    CP --> GFD
    CP --> OV

    D --> NODE
    CT --> NODE
    DP --> NODE
    DE --> NODE
    GFD --> NODE
    OV --> NODE

    style CP fill:#4286f4,stroke:#2a6acf,color:#fff
    style D fill:#10b981,stroke:#0d8a63,color:#fff
    style CT fill:#10b981,stroke:#0d8a63,color:#fff
    style DP fill:#10b981,stroke:#0d8a63,color:#fff
    style DE fill:#10b981,stroke:#0d8a63,color:#fff
    style GFD fill:#10b981,stroke:#0d8a63,color:#fff
    style OV fill:#10b981,stroke:#0d8a63,color:#fff
    style NODE fill:#fbbc04,stroke:#c99603,color:#000

진단 명령어

# ClusterPolicy 상태
kubectl get clusterpolicy -A
kubectl describe clusterpolicy gpu-cluster-policy

# 각 컴포넌트 파드 상태
kubectl get pods -n gpu-operator

# Driver 파드 로그 (설치 실패 시)
kubectl logs -n gpu-operator nvidia-driver-daemonset-<pod-id>
# 에러: "Kernel headers not found" → AMI에 kernel-devel 필요
# 에러: "nouveau driver is loaded"  → nouveau 블랙리스트 필요

# Device Plugin 로그
kubectl logs -n gpu-operator nvidia-device-plugin-daemonset-<pod-id>
# 정상: "Detected NVIDIA devices: 8"

Auto Mode에서의 GPU 워크로드

제약 내용
devicePlugin=false 필수 Auto Mode는 GPU Driver 자동 관리. GPU Operator 설치 시 Device Plugin 충돌 - ClusterPolicy에서 반드시 비활성화
레이블 기반 격리 Auto Mode 노드에는 GPU Operator 스케줄 방지. MNG 노드에만 GPU Operator 배포 + Taint로 GPU 워크로드 격리
하이브리드 구성 (권장) Auto Mode = 일반 워크로드 / MNG (GPU) = GPU 전용. DCGM · GFD 메트릭은 정상 수집 가능

Auto Mode + GPU 하이브리드 설정

# ClusterPolicy: Device Plugin 비활성화 필수
apiVersion: nvidia.com/v1
kind: ClusterPolicy
spec:
  driver:
    enabled: true
  devicePlugin:
    enabled: false    # ← Auto Mode 충돌 방지 핵심 설정
  dcgm:
    enabled: true     # 메트릭 수집 가능
  gfd:
    enabled: true     # GPU Feature Discovery 가능

# MNG 노드에 Taint 추가
# nvidia.com/gpu=true:NoSchedule
# GPU 파드에 Toleration 필수

GPU 진단 체크리스트

Step 1. GPU 인식 확인

Step 2. 스케줄링 확인

Step 3. vLLM OOM

Step 4. NCCL Timeout (멀티노드)

VIII. Auto Mode vs Standard Mode

개요

항목 Standard Mode Auto Mode 디버깅 영향
노드 관리 사용자 (MNG / Karpenter) AWS 관리 (NodePool) NodePool CRD로 상태 확인
VPC CNI 수동 설정 / 업그레이드 자동 관리 Custom CNI 설정 불가
GPU Driver GPU Operator 설치 AWS 관리 devicePlugin=false 필수
스토리지 EBS CSI 별도 설치 내장 (gp3) io2 BE 미지원, EFS 별도
CoreDNS Add-on 관리 자동 관리 Custom 설정 제한
노드 SSH 가능 (MNG) 제한적 (SSM) kubectl debug node 필수
Auto Scaling Karpenter / CA NodePool Spot 중단 자동 처리

핵심: Auto Mode는 편리하지만 커스터마이징 제한 - GPU, 고성능 스토리지, Custom CNI가 필요하면 하이브리드 구성 필수

NodePool & NodeClaim

리소스 역할 특징
NodePool CRD Auto Mode의 노드 그룹 정의 인스턴스 타입 · 용량 타입 · AZ 제약 설정 / Karpenter NodePool과 유사
인스턴스 타입 선택 requirements에서 허용 인스턴스 지정 Spot + On-Demand 폴백 설정, 다양한 타입으로 가용성 확보
NodeClaim 실제 노드 요청 (EC2 인스턴스 1:1) Phase: Pending → Launched → Ready / Instance ID ↔ Node Name 매핑

진단 명령어

# NodePool 목록 및 상태
kubectl get nodepools
kubectl describe nodepool default

# NodeClaim 목록 (실제 노드 요청)
kubectl get nodeclaims -o wide

# NodeClaim과 Node 매핑
kubectl get nodeclaims -o json | \
  jq -r '.items[] | "\(.metadata.name) → \(.status.nodeName)"'

# 인스턴스 타입 선택 실패 시: Pod 리소스 vs NodePool requirements 확인
kubectl describe pod <pending-pod>
kubectl get nodepool <name> -o yaml | grep -A 10 requirements

하이브리드 구성 시 주의점

이슈 핵심 대응
MNG 추가 시 충돌 Auto Mode NodePool과 MNG가 같은 Pod를 경쟁 스케줄링 → 반드시 Taint/Toleration으로 분리
레이블 전략 MNG에 workload=gpu 레이블 → Pod nodeSelector로 명확 타겟팅. Auto Mode 노드에는 일반 워크로드만
테인트 분리 GPU MNG: nvidia.com/gpu=true:NoSchedule → GPU Pod만 Toleration으로 스케줄, 일반 Pod 침범 방지
하이브리드 패턴 Auto Mode = 웹 서버 · API · 배치 / GPU MNG = vLLM · 학습 Job · GPU Operator

GPU MNG 생성 예시

aws eks create-nodegroup \
  --cluster-name <cluster> \
  --nodegroup-name gpu-nodes \
  --instance-types g5.2xlarge g5.4xlarge \
  --taints key=nvidia.com/gpu,value=true,effect=NO_SCHEDULE

NodeClaim 라이프사이클

flowchart LR
    P[Pending]
    L[Launched]
    R[Registered]
    I[Initialized]
    RDY[Ready]
    D[Drifted]
    C[Consolidation]
    T[Terminating]
    DEL[Deleted]

    P -->|EC2 시작| L
    L -->|kubelet| R
    R -->|Taints| I
    I -->|Node Ready| RDY
    RDY -->|AMI 변경| D
    RDY -->|유휴 / 저활용| C
    C --> D
    D --> T
    T --> DEL

    style P fill:#fbbc04,stroke:#c99603,color:#000
    style L fill:#4286f4,stroke:#2a6acf,color:#fff
    style R fill:#4286f4,stroke:#2a6acf,color:#fff
    style I fill:#4286f4,stroke:#2a6acf,color:#fff
    style RDY fill:#10b981,stroke:#0d8a63,color:#fff
    style D fill:#fbbc04,stroke:#c99603,color:#000
    style C fill:#fbbc04,stroke:#c99603,color:#000
    style T fill:#ff4444,stroke:#cc3636,color:#fff
    style DEL fill:#ff4444,stroke:#cc3636,color:#fff

NodeClaim 상태 모니터링

# NodeClaim 상태 확인
kubectl get nodeclaims -o wide
# NAME           TYPE          ZONE          CAPACITY  READY  AGE
# default-abc    c6i.2xlarge   us-east-1a    8         True   2d

# Drift 상태 확인
kubectl get nodeclaims -o json | jq -r '.items[] |
  select(.status.conditions[] | select(.type=="Drifted" and .status=="True"))
  | .metadata.name'

# 교체 진행 모니터링
watch -n 5 'kubectl get nodeclaims -o wide'