Skip to content

운영 및 관리

지원 버전: EKS 1.29+, EKS Auto Mode GA 마지막 업데이트: 2026년 2월 19일

< 이전: Spot 전략 | 목차 | 다음: 비용 관리 >


이 문서에서는 EKS Auto Mode 클러스터의 Day-2 운영, 모니터링, 문제 해결, 그리고 보안 모범 사례를 다룹니다.

Disruption Budget 설정

안전한 노드 교체를 위한 예산을 설정합니다.

yaml
# disruption-budget.yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: production-pool
spec:
  template:
    spec:
      requirements:
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["m", "c", "r"]
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["on-demand"]
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        name: default
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 5m
    budgets:
      # 기본: 전체 노드의 10%만 동시 중단
      - nodes: "10%"

      # 업무 시간: 중단 최소화
      - nodes: "1"
        schedule: "0 9-18 * * mon-fri"  # 월-금 9-18시 (KST)
        duration: 9h

      # 주말: 더 적극적인 통합 허용
      - nodes: "30%"
        schedule: "0 0 * * sat-sun"
        duration: 48h

      # 긴급 유지보수 윈도우: 중단 금지
      - nodes: "0"
        schedule: "0 0 1 * *"  # 매월 1일
        duration: 24h

롤링 교체 전략

yaml
# rolling-replacement-strategy.yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: rolling-replacement
spec:
  template:
    spec:
      requirements:
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["m"]
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        name: default
      # 노드 만료 시간
      expireAfter: 168h  # 7일
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 2m
    budgets:
      # 순차적 교체를 위해 동시 중단 노드 제한
      - nodes: "1"

PodDisruptionBudget과의 연동

yaml
# pdb-example.yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: web-app-pdb
spec:
  # 최소 가용 Pod 수
  minAvailable: 3
  # 또는 최대 비가용 Pod 수
  # maxUnavailable: 1
  selector:
    matchLabels:
      app: web-app
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 5
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
        - name: web
          image: nginx:latest
          resources:
            requests:
              cpu: 500m
              memory: 256Mi
      # 노드 교체 시 graceful shutdown
      terminationGracePeriodSeconds: 60

Zone 장애 대응

yaml
# multi-az-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: high-availability-app
spec:
  replicas: 6
  selector:
    matchLabels:
      app: ha-app
  template:
    metadata:
      labels:
        app: ha-app
    spec:
      # 가용 영역 분산
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: DoNotSchedule
          labelSelector:
            matchLabels:
              app: ha-app
        # 노드 분산
        - maxSkew: 1
          topologyKey: kubernetes.io/hostname
          whenUnsatisfiable: ScheduleAnyway
          labelSelector:
            matchLabels:
              app: ha-app
      containers:
        - name: app
          image: my-app:latest
          resources:
            requests:
              cpu: 500m
              memory: 512Mi
---
# Zone별 최소 노드 보장을 위한 NodePool
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: multi-az-pool
spec:
  template:
    spec:
      requirements:
        - key: topology.kubernetes.io/zone
          operator: In
          values: ["ap-northeast-2a", "ap-northeast-2b", "ap-northeast-2c"]
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["m", "c"]
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        name: default
  # Zone당 최소 용량 보장
  limits:
    cpu: 1000

CloudWatch 지표 모니터링

EKS Auto Mode는 다음 지표를 CloudWatch에 자동으로 전송합니다.

bash
# CloudWatch 메트릭 네임스페이스
# - AWS/EKS
# - Karpenter

# 주요 지표
# - karpenter_nodes_total: 총 노드 수
# - karpenter_pods_pending: Pending Pod 수
# - karpenter_nodeclaims_created: 생성된 NodeClaim 수
# - karpenter_nodeclaims_terminated: 종료된 NodeClaim 수

CloudWatch 대시보드 설정

json
{
  "widgets": [
    {
      "type": "metric",
      "properties": {
        "title": "Auto Mode 노드 수",
        "metrics": [
          ["Karpenter", "karpenter_nodes_total", "cluster", "my-cluster"]
        ],
        "period": 60
      }
    },
    {
      "type": "metric",
      "properties": {
        "title": "Pending Pods",
        "metrics": [
          ["Karpenter", "karpenter_pods_pending", "cluster", "my-cluster"]
        ],
        "period": 60
      }
    },
    {
      "type": "metric",
      "properties": {
        "title": "노드 프로비저닝 시간",
        "metrics": [
          ["Karpenter", "karpenter_nodeclaims_startup_duration_seconds", "cluster", "my-cluster"]
        ],
        "stat": "p99",
        "period": 300
      }
    }
  ]
}

kubectl 기반 진단

bash
# NodePool 상태 확인
kubectl get nodepools
kubectl describe nodepool general-purpose

# NodeClaim 상태 확인 (프로비저닝 중인 노드)
kubectl get nodeclaims
kubectl describe nodeclaim <name>

# 노드 상태 및 레이블 확인
kubectl get nodes -o wide -L karpenter.sh/nodepool,karpenter.sh/capacity-type

# Pending Pod 확인
kubectl get pods -A --field-selector=status.phase=Pending

# 이벤트 확인
kubectl get events --sort-by='.lastTimestamp' | grep -E "karpenter|nodepool|nodeclaim"

# 노드 리소스 사용량
kubectl top nodes

# 노드별 Pod 분포
kubectl get pods -A -o wide | awk '{print $8}' | sort | uniq -c | sort -rn

일반적인 문제와 해결 방법

문제 1: Pod가 Pending 상태로 유지됨

bash
# 원인 분석
kubectl describe pod <pending-pod>

# 일반적인 원인:
# 1. 리소스 요청이 너무 큼
# 2. NodePool 제한 초과
# 3. nodeSelector/affinity 조건 불일치
# 4. taint/toleration 불일치

# 해결: NodePool 제한 확인
kubectl get nodepool -o yaml | grep -A5 limits

# 해결: nodeSelector 조건 확인
kubectl get pod <pending-pod> -o yaml | grep -A10 nodeSelector

문제 2: 노드 프로비저닝 실패

bash
# NodeClaim 상태 확인
kubectl describe nodeclaim <name>

# 이벤트에서 오류 메시지 확인
kubectl get events --field-selector reason=FailedProvisioning

# 일반적인 원인:
# 1. 인스턴스 용량 부족
# 2. 서브넷 IP 부족
# 3. IAM 권한 문제
# 4. 보안 그룹 설정 오류

# 해결: 더 다양한 인스턴스 타입 허용
# NodePool의 requirements를 확장

문제 3: 노드 Consolidation이 작동하지 않음

bash
# Consolidation 상태 확인
kubectl get nodeclaims -o custom-columns=\
NAME:.metadata.name,\
NODEPOOL:.metadata.labels.karpenter\\.sh/nodepool,\
PHASE:.status.phase,\
AGE:.metadata.creationTimestamp

# PodDisruptionBudget 확인
kubectl get pdb -A

# 해결: PDB 조정 또는 budgets 설정 확인

문제 4: Spot 인터럽트 후 Pod 재스케줄 지연

bash
# Spot 인터럽트 이벤트 확인
kubectl get events --sort-by='.lastTimestamp' | grep -i "spot\|interrupt"

# 해결: 빠른 재프로비저닝을 위한 설정
# 1. 다양한 인스턴스 타입 허용
# 2. consolidateAfter 시간 단축
# 3. Spot과 On-Demand 혼합 사용

보안 모범 사례

yaml
# security-best-practices.yaml
apiVersion: eks.amazonaws.com/v1
kind: NodeClass
metadata:
  name: secure-nodeclass
spec:
  amiFamily: Bottlerocket  # 보안 강화 OS

  # IMDSv2 필수
  metadataOptions:
    httpEndpoint: enabled
    httpProtocolIPv6: disabled
    httpPutResponseHopLimit: 1  # Pod의 IMDS 접근 차단
    httpTokens: required

  # EBS 암호화
  blockDeviceMappings:
    - deviceName: /dev/xvda
      ebs:
        volumeSize: 100Gi
        volumeType: gp3
        encrypted: true
        kmsKeyId: arn:aws:kms:ap-northeast-2:123456789:key/xxx

  # 프라이빗 서브넷만 사용
  subnetSelectorTerms:
    - tags:
        kubernetes.io/role/internal-elb: "1"

  # 제한적인 보안 그룹
  securityGroupSelectorTerms:
    - tags:
        Type: worker-restricted
---
# Pod 보안 표준 적용
apiVersion: v1
kind: Namespace
metadata:
  name: secure-namespace
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/warn: restricted

Day-2 운영 체크리스트

효과적인 Auto Mode 운영을 위한 일일/주간/월간 체크리스트입니다.

일일 체크리스트

항목확인 명령어정상 기준
Pending Pod 확인kubectl get pods -A --field-selector=status.phase=Pending0개 (또는 일시적)
NodeClaim 상태kubectl get nodeclaims모두 Ready 상태
노드 리소스 사용량kubectl top nodesCPU/메모리 < 80%
최근 이벤트 확인kubectl get events --sort-by='.lastTimestamp' -A에러 없음

주간 체크리스트

항목설명
비용 분석AWS Cost Explorer에서 EC2 비용 트렌드 확인
Consolidation 효율저사용률 노드 비율 확인
Spot 인터럽트 빈도CloudWatch 메트릭에서 Spot 중단 이벤트 검토
노드 수명 분포오래된 노드 비율 확인 (expireAfter 동작 검증)

월간 체크리스트

항목설명
NodePool 설정 검토요구사항 변화에 따른 설정 조정
AMI 업데이트 확인최신 AMI 적용 여부 확인
보안 패치 상태노드 보안 업데이트 상태 검토
용량 계획limits 설정 적절성 검토

노드 교체 전략 비교

Rolling vs Aggressive 교체

전략설정사용 시나리오장점단점
Rollingbudgets: nodes: "1"프로덕션 환경서비스 영향 최소화교체 시간 김
Aggressivebudgets: nodes: "30%"개발/테스트 환경빠른 교체순간적 용량 감소
Scheduledschedule: "0 2 * * *"비즈니스 비활성 시간업무 영향 없음유연성 제한

교체 전략 선택 가이드

yaml
# 프로덕션 환경: 보수적 롤링 교체
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: production
spec:
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 10m
    budgets:
      - nodes: "1"
      - nodes: "0"
        schedule: "0 9-21 * * mon-fri"  # 업무 시간 중단 금지
        duration: 12h
---
# 개발 환경: 적극적 통합
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: development
spec:
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 1m
    budgets:
      - nodes: "50%"

가용 영역 장애 대응 패턴

Multi-AZ Awareness 설정

yaml
# multi-az-resilient.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: az-resilient-app
spec:
  replicas: 9  # 3 AZ x 3 replicas
  selector:
    matchLabels:
      app: az-resilient
  template:
    metadata:
      labels:
        app: az-resilient
    spec:
      topologySpreadConstraints:
        # AZ 균등 분배 (필수)
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: DoNotSchedule
          labelSelector:
            matchLabels:
              app: az-resilient
      affinity:
        podAntiAffinity:
          # 같은 노드에 배치 금지
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchLabels:
                  app: az-resilient
              topologyKey: kubernetes.io/hostname
      containers:
        - name: app
          image: my-app:latest

Capacity Reservation 활용

yaml
# 특정 AZ에 용량 보장
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: reserved-capacity
spec:
  template:
    spec:
      requirements:
        - key: topology.kubernetes.io/zone
          operator: In
          values: ["ap-northeast-2a"]
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["on-demand"]
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        name: default
  limits:
    cpu: 200  # AZ당 최소 보장 용량

운영 자동화

노드 교체 알림 설정

yaml
# CloudWatch 알람을 통한 노드 교체 알림
# AWS CLI로 생성
# aws cloudwatch put-metric-alarm \
#   --alarm-name "EKS-Auto-Mode-Node-Replacement" \
#   --metric-name karpenter_nodeclaims_terminated \
#   --namespace Karpenter \
#   --statistic Sum \
#   --period 300 \
#   --threshold 5 \
#   --comparison-operator GreaterThanThreshold \
#   --evaluation-periods 1 \
#   --alarm-actions arn:aws:sns:ap-northeast-2:123456789:alerts

PDB 준수 모니터링

bash
#!/bin/bash
# pdb-compliance-check.sh
# PDB 위반 상태 확인 스크립트

echo "=== PDB Compliance Check ==="
kubectl get pdb -A -o json | jq -r '
  .items[] |
  select(.status.disruptionsAllowed == 0) |
  "\(.metadata.namespace)/\(.metadata.name): No disruptions allowed (current: \(.status.currentHealthy)/\(.status.desiredHealthy))"
'

용량 모니터링 대시보드

yaml
# Prometheus 알림 규칙
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: karpenter-alerts
spec:
  groups:
    - name: karpenter
      rules:
        - alert: HighPendingPods
          expr: karpenter_pods_pending > 10
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: "많은 수의 Pending Pod 감지"
            description: "{{ $value }}개의 Pod가 5분 이상 Pending 상태입니다."

        - alert: NodeProvisioningFailed
          expr: increase(karpenter_nodeclaims_terminated{reason="ProvisioningFailed"}[10m]) > 0
          labels:
            severity: critical
          annotations:
            summary: "노드 프로비저닝 실패"
            description: "최근 10분간 노드 프로비저닝 실패가 발생했습니다."

운영 체크리스트 요약

영역체크 항목
설정NodePool limits 설정 완료
Disruption Budget 구성
NodeClass 보안 설정 검토
모니터링CloudWatch 대시보드 생성
알람 설정 (Pending Pod, 프로비저닝 실패)
비용 모니터링 설정
가용성PodDisruptionBudget 설정
멀티 AZ 분산 검증
Spot/On-Demand 혼합 비율 검토
비용Spot 인스턴스 비율 최적화
Consolidation 정책 검토
리소스 요청/제한 적절성 검토

< 이전: Spot 전략 | 목차 | 다음: 비용 관리 >