켜기, 노드 설정, 용량, 진단, 비용, 마이그레이션, 그리고 무엇을 고를까
| 역할 | 필요한 것 |
|---|---|
| 클러스터 역할 | 신뢰: sts:AssumeRole + sts:TagSession정책 ( AmazonEKS 접두사): ClusterPolicy, ComputePolicy, BlockStoragePolicyV2, LoadBalancingPolicy, NetworkingPolicy |
| 노드 역할 | AmazonEKSWorkerNodeMinimalPolicy, AmazonEC2ContainerRegistryPullOnly |
| 워크로드 | Pod Identity로 따로 부여. OIDC provider 없이 활성화 가능 |
CONFIG_MAP에서 API_AND_CONFIG_MAP 전환은 단방향. 기존 클러스터의 클러스터 역할 ARN은 교체 불가# 기존 클러스터: 세 기능을 한 요청에서 함께 aws eks update-cluster-config --name $CLUSTER \ --compute-config '{"enabled":true, "nodePools":["general-purpose","system"], "nodeRoleArn":"'$NODE_ROLE_ARN'"}' \ --kubernetes-network-config \ '{"elasticLoadBalancing":{"enabled":true}}' \ --storage-config '{"blockStorage":{"enabled":true}}' # eksctl: 새 클러스터 create cluster --enable-auto-mode # 기존 클러스터 update auto-mode-config -f cluster.yaml kubectl wait nodepool/general-purpose nodepool/system \ --for=condition=Ready --timeout=300s
| NodePool | 아키텍처 | 용량, 인스턴스 | 누가 올라가나 |
|---|---|---|---|
general-purpose | amd64 | On-Demand, C/M/R, 5세대 이상 | 일반 워크로드 |
system | amd64, arm64 | On-Demand, C/M/R, 5세대 이상 | CriticalAddonsOnly taint를 tolerate하는 Pod |
Balanced입니다.computeConfig.nodePools에서 이름을 지우면 그 풀의 노드가 drain, 종료됩니다. 새 Pod만 막는 설정이 아닙니다.kubectl get nodepool general-purpose system -o yaml, kubectl get nodeclass default -o yaml로 실제 disruption과 taint 값을 확인합니다.apiVersion: eks.amazonaws.com/v1 kind: NodeClass spec: role: AmazonEKSAutoNodeRole # 또는 instanceProfile subnetSelectorTerms: - tags: {kubernetes.io/role/internal-elb: "1"} securityGroupSelectorTerms: - tags: {Type: worker-node} ephemeralStorage: size: 100Gi iops: 3000 throughput: 125 advancedNetworking: associatePublicIPAddress: false advancedCompute: kernel: sysctl: {vm.max_map_count: 262144} tags: {Environment: production}
role과 instanceProfile은 하나만AmazonEKSComputePolicy가 eks* 이름의 instance profile에만 권한을 주므로 이름을 eks로 시작합니다. 새 역할에는 access entry가 필요합니다.tags는 클러스터 역할 권한 필요CreateLaunchTemplate 권한 오류로 확인했습니다.| 필드 | 하는 일 | 주의 |
|---|---|---|
ephemeralStorage.kmsKeyID | 노드 root, data EBS를 고객 관리 키로 암호화 | 같은 리전 키. NVMe instance store와 앱 PVC에는 적용 안 됨 |
certificateBundles[].data | 사설 CA를 노드 신뢰 저장소에 추가 (base64) | 앱 컨테이너의 trust store는 바뀌지 않음 |
podSubnetSelectorTerms | Pod IP를 노드와 다른 subnet에서 할당 | podSecurityGroupSelectorTerms와 반드시 함께. namespace 단위가 아니라 NodeClass 단위 |
podSecurityGroupSelectorTerms | Pod 네트워크에 붙일 security group | |
advancedNetworking.associatePublicIPAddress | false면 노드에 공인 IP 없음 | outbound 경로(NAT, endpoint)는 따로 필요 |
amiFamily, amiSelectorTerms, blockDeviceMappings, userData, metadataOptions. OS는 AWS가 고르는 Bottlerocket 변형입니다.ephemeralStorage, 부팅 sysctl은 advancedCompute.kernel.sysctl, IMDS는 고정값(다음 장)hostNetwork Pod는 예외이니 앱 권한은 Pod Identity로 주고 리전 같은 값은 명시합니다.WorkerNodeMinimalPolicy와 ContainerRegistryPullOnly. 앱 권한을 노드 역할에 넣지 않습니다.weight는 Spot 비율을 정하지 않습니다.capacity-type: on-demand nodeSelector는 예약 용량을 제외합니다. preferred affinity는 비율을 보장하지 않습니다.preStop: sleep 90은 예산 대부분을 소비하는 안티패턴입니다.# NodeClass spec: capacityReservationSelectorTerms: - id: cr-0123456789abcdef0 # NodePool requirements: - key: karpenter.sh/capacity-type operator: In values: ["reserved"]
capacityReservationSelectorTerms를 쓰면 클러스터의 모든 NodeClass가 open ODCR 자동 사용을 멈춥니다. 예약은 쓰지 않아도 과금됩니다.apiVersion: karpenter.sh/v1 kind: NodePool spec: replicas: 4 # Pod 수요와 무관하게 유지 limits: nodes: 6 # 교체 여유 template: spec: nodeClassRef: {group: eks.amazonaws.com, kind: NodeClass, name: default} requirements: - {key: node.kubernetes.io/instance-type, operator: In, values: ["m5.xlarge"]}
limits는 nodes만, weight 설정 불가, consolidation 없음. replicas는 지울 수 없어 동적 풀로 되돌릴 수 없습니다.requirements: - key: eks.amazonaws.com/instance-gpu-manufacturer operator: In values: ["nvidia"] - key: node.kubernetes.io/instance-type operator: In values: ["g5.2xlarge", "g5.4xlarge"] taints: - key: nvidia.com/gpu effect: NoSchedule limits: nvidia.com/gpu: "4" disruption: consolidationPolicy: WhenEmpty consolidateAfter: 10m
amiFamily 지정도 없습니다.| 유형 | GPU | vCPU / RAM |
|---|---|---|
| g5.xlarge | A10G 1개 | 4 / 16 GiB |
| g5.2xlarge | A10G 1개 | 8 / 32 GiB |
| g5.12xlarge | A10G 4개 | 48 / 192 GiB |
advancedNetworking: networkInterfaces: - {networkCardIndex: 0, deviceIndex: 0, interfaceType: interface, secondaryIPv4PrefixCount: 1} - {networkCardIndex: 0, deviceIndex: 1, interfaceType: efa-only} - {networkCardIndex: 1, deviceIndex: 0, interfaceType: efa-only} placementGroupSelector: name: ml-training-pg
efa-only는 Pod IP를 쓰지 않음interface와 prefix가 맡습니다. Pod는 vpc.amazonaws.com/efa를 요청합니다.associatePublicIPAddress 조합 불가, 같은 NodeClass에 static hugepages 불가, EFA DRA 경로 미지원zonal-shift-config를 켜면 끝. 플래그, IAM 변경 없음. autoshift는 ARC에서 따로DoNotSchedule 같은 엄격한 AZ 제약은 그대로입니다. replica와 topology spread가 먼저입니다.karpenter-crd와 controller chart를 함께, 버전 문자열은 1.15.0ValidationSucceeded, 대시보드 label 변경UnhealthyⓘNDB = NodePool Disruption Budget (spec.disruption.budgets)
Unhealthy: reasons: [Unhealthy]로 repair 속도만 제한. reasons 없는 budget(기본 10%)도 적용NodeRepairBlocked 이벤트Unhealthy가 추가되어 karpenter-crd를 같이 올려야 함NodeRepair gate (alpha, 기본 off), Auto Mode는 내장InvalidKubeletConfiguration 으로 NotReadypodsPerCore, clusterDNS 2개 이상은 UnsupportedKubeletConfiguration reason 소문자화, consolidation_type 은 empty, single, multi, 미분류 error는 unknownBalanced 반영 여부 결정ContainerCreating에 머물지 않는지| log type | 무엇의 판단인가 |
|---|---|
AUTO_MODE_COMPUTE_LOGS | 관리형 Karpenter: 프로비저닝, disruption |
AUTO_MODE_BLOCK_STORAGE_LOGS | EBS CSI |
AUTO_MODE_LOAD_BALANCING_LOGS | Load Balancer controller |
AUTO_MODE_IPAM_LOGS | IP 주소 관리 |
PutDeliverySource, PutDeliveryDestination, CreateDelivery 순서. 목적지는 CloudWatch Logs, S3, FirehoseapiVersion: eks.amazonaws.com/v1alpha1 kind: NodeDiagnostic metadata: name: i-0abc1234def567890 # 노드 이름 spec: logCapture: destination: "https://...presigned S3 PUT URL"
.status.captureStatuses의 Success, SuccessWithErrors, Failuredestination: node도 받습니다.kubectl debug 디버그 컨테이너, 부팅 문제는 aws ec2 get-console-output. agent는 node condition과 event를 내고 자동 repair에 쓰입니다.# Auto Mode 노드만 kubectl get nodes -L eks.amazonaws.com/compute-type # NodeClaim condition (phase 필드는 없음) kubectl get nodeclaims -o wide kubectl describe nodeclaim <name> # 못 뜬 Pod kubectl get events -A \ --field-selector reason=FailedScheduling
LaunchedRegisteredInitializedReadyDriftedDisruptionBlockedUnconsolidatableFailedSchedulingNodeClassNotReadykarpenter_* 메트릭을 가정하지 않음Karpenter CloudWatch namespace가 자동으로 생기지 않습니다.eks-auto-mode/computeinclude-managed-resources로 조회| 서울, 시간당 | 관리비 | On-Demand | Spot (AZ별) | 관리비 비율 |
|---|---|---|---|---|
| m5.large | $0.01416 | $0.118 | $0.0195 ~ 0.0250 | OD의 12%, Spot의 57 ~ 73% |
| m7g.large | $0.01204 | $0.1003 | $0.0194 ~ 0.0324 | OD의 12%, Spot의 37 ~ 62% |
| 할인 수단 | EC2 요금 | Auto Mode 관리비 |
|---|---|---|
| Compute Savings Plans | 적용 (최대 66%) | 미적용 |
| EC2 Instance Savings Plans | 적용 (최대 72%) | 미적용 |
| Reserved Instances | 적용 | 미적용 |
| Spot | Spot 가격 (SP 대상 아님) | 미적용 |
aws:eks:cluster-name*EKS-Auto:*-management-hours인 항목으로 거릅니다.tags로 팀 태그를 붙이거나 Kubecost 같은 도구로 Pod requests 기준 배분합니다.| 리소스 | 직접 설치한 controller | Auto Mode |
|---|---|---|
| StorageClass provisioner | ebs.csi.aws.com | ebs.csi.eks.amazonaws.com |
Service loadBalancerClass (NLB) | service.k8s.aws/nlb | eks.amazonaws.com/nlb |
| IngressClass controller (ALB) | ingress.k8s.aws/alb | eks.amazonaws.com/alb |
| TargetGroupBinding, IngressClassParams | elbv2.k8s.aws/v1beta1 | eks.amazonaws.com/v1 |
| NodeClass | karpenter.k8s.aws/v1 EC2NodeClass | eks.amazonaws.com/v1 NodeClass |
nodePools: []. 무제한 general-purpose가 Pending Pod를 먼저 가져가지 않게compute-type: auto selector. 저위험부터--force, --delete-emptydir-data로 오류를 덮지 않기eksctl delete nodegroup이 노드를 drain한 뒤 삭제합니다.eks.amazonaws.com/compute-type: auto selectornodepools.karpenter.sh, nodeclaims.karpenter.sh를 바꾸거나 지우지 않기karpenter.k8s.aws/instance-*를 eks.amazonaws.com/instance-*로 바꿉니다. 공존 중에는 양쪽 compute와 LB가 함께 과금됩니다.advancedCompute 지원 필드를 벗어남