포스팅은 CloudNet@팀 서종호(Gasida)님이 진행하시는 AWS EKS Workshop Study 내용을 참고하여 작성합니다.
안녕하세요!
오늘은 파드를 관리하는 EKS 관리형 노드 그룹의
종류에 대해서 학습하는 시간을 갖도록 하겠습니다.
01. On-Demand 노드 그룹
먼저 온디맨드가 기준선이라서 먼저 소개하도록 하겠습니다.
EKS 관리형 노드 그룹의 기본 동작 방식을 이해해야 ARM과 Spot의 차이점을 알 수 있습니다.
📌 EKS 관리형 노드 그룹이란?
노드 프로비저닝 / 업그레이드 / 교체를 AWS가 대신 해줍니다 → ASG(AutoScalingGroup) 위에서 동작
vanilla k8s 에서는 직접 EC2를 띄우고 kubelet을 설정해야 했던 것을 AWS가 흡수함.
'eksctl get nodegroup' 출력의 TYPE: managed가 이걸 증명하는 근거입니다.
주목할 컬럼은 아래와 같습니다.
MIN SIZE / MAX SIZE / DESIRED : ASG 스케일링 범위 입니다. 현재 노드 2개가 떠있는 이유죠. INSTANCE TYPE : t3.medium을 사용중이며, 단일 인스턴스 타입이 지정됨 (Spot과 달리 하나만) TYPE : managed라고 적혀있는 것이 AWS 관리형 노드 그룹임을 명시하는 것입니다.
1) 노드 레이블 확인
'--label-columns' 옵션은 보통 'kubectl get nodes'에서는 보이지 않는 레이블 값을 컬럼으로 출력하는 옵션임.
NODEGROUP: myeks-ng-1 → 두 노드 모두 같은 노드 그룹에 속함 ARCH: amd64 → x86_64 계열 인텔/AMD 프로세서 CAPACITYTYPE: ON_DEMAND → 온디맨드 인스턴스
이 세 레이블은 EKS가 노드 프로비저닝 시 자동으로 붙여주는 것이고 사용자가 직접 label로 붙이는 것이 아님.
EKS관리형 노드 그룹이 노드를 등록할 때 노드 그룹 메타데이터를 읽어서 자동으로 주입합니다.
capacityType: ON_DEMAND → Spot이 아님을 명시하는 필드이며, Terraform으로 배포할 때 capacity_type을 지정하지 않으면 기본값이 온디맨드 입니다.
updateConfig: maxUnavailablePercentage: 33 → 노드 업그레이드 시 동시에 최대 33%의 노드까지 unavailable 상태를 허용한다는 설정이며, 노드가 2개라면 최대 1개씩 교체하는 롤링 업그레이드 전략입니다.
launchTemplate → Terraform이 생성한 런치 템플릿입니다. userdata, security group, hop limit 설정 등이 여기에 담기며, EKS가 새 노드를 프로비저닝할 때 이 템플릿을 참조함.
즉 요약하자면, 온디맨드는 EKS 관리형 노드 그룹이며 EC2 ASG + AWS 관리 라이프 사이클 중 기본값 입니다.
(온디맨드 특성 상 비용이 고정적이고 중단이 없습니다 → Stateful 서비스나 중단 허용이 안되는 워크로드의 기본 값)
02. AWS Graviton (ARM) 노드 그룹
이 섹션에서 두 가지 레이어를 설명할 예정입니다.
온디맨드와 가격을 비교하는 다이어그램과, ARM에서 어떻게 격리를 시키는지에 대한 다이어그램으로 나뉩니다.
📌 왜 온디맨드보다 ARM이 저렴할까?
Graviton = AWS가 직접 설계한 64-bit ARM 칩 → x86 라이선스 비용 없음 + 전력 효율
컨테이너 워크로드는 단순 반복 연산이 많아 RISC 코어에 더 잘 맞음
가격 대비 성능 20~40% 향상이라는 수치의 근거: 인텔 라이선스 제거 + 칩 설계 최적화
뭔가 잘 와닿지 않을 수 있기 때문에 딥하게 한번 말씀드려보겠습니다.
x86(인텔/AMD)은 수십 년간 하위 호환성을 유지하면서 명령어가 계속 쌓여 있습니다. 칩 안에 이 복잡한 명령어들을 해석하는 디코더가 커야 하고, 그만큼 전력을 많이 씁니다. 여기에 인텔/AMD 라이선스 비용도 포함
하지만, AWS Graviton은 처음부터 서버 워크로드만을 위해서 설계되어서 하위 호환 부담이 없고, "컨테이너가 주로 뭘 하나"를 분석해서 그 연산에 최적화된 명령어 세트로만 구현이 되었습니다. + 라이선스 비용 X
컨테이너 워크로드가 주로 하는 일은 네트워크 I/O 처리, HTTP 요청 파싱, JSON 직렬화/역직렬화, 메모리 복사 같은 단순 반복 연산입니다. x86의 복잡한 명령어가 필요한 순간이 거의 없습니다. 그래서 단순한 Graviton 코어가 더 낮은 전력으로 같은 일을 처리할 수 있는 것입니다.
ARM 노드에 x86 파드가 잘못 스케줄되면 실행 자체가 안되기 때문에 'taint로 강제 격리' 합니다.
📌 Taint / Toleration 원리
taint는 노드에 "이 조건을 수용 못하면 오지 마"라는 표시이며, 3가지 effect가 있습니다.
NoSchedule : 새 파드 배치 불가
PreferNoSchedule : 가급적 파드 배치 배제
NoExecute : 배치 불가 + 기존 파드 즉시 축출
nodeSelector + toleration 조합
toleration만 있으면 "갈 수 있다"는 허가일 뿐, ARM 노드로 반드시 가도록 강제하지는 않음.
nodeSelector: kubernetes.io/arch: arm64까지 함께 써야 ARM 전용으로 핀 가능.
ARM 바이너리와 x86 바이너리는 서로 실행이 안됩니다.
x86용으로 빌드된 컨테이너 이미지가 ARM 노드에 스케줄되면 파드가 그냥 crash 합니다.
그래서 위 원리로 taint를 걸어서 "이 노드는 ARM이니까, ARM을 명시적으로 인지하고 toleration을 선언한
파드만 와라"라고 일종의 실수 방지 장치를 거는 것 입니다.
1) ARM 노드그룹 추가.
ARCH: arm64의 'myeks-ng-2' 노드 그룹을 추가해보았습니다.
인스턴스 타입이 t4g.medium으로 t4g의 g가 Graviton을 의미합니다. IMAGE ID도 ARM 전용 AMI가 올라가 있습니다.
2) 온디맨드와 다른점
노드그룹 1번 출력에는 taints 필드 자체가 없었습니다.
해당 노드 그룹에 effect가 NoExecute로 걸려있습니다. 위에서 말씀드렸다 싶이, ARM 바이너리와 x86은 서로 실행 불가하여 파드의 크래시 상태를 방지하기 위한 강제 격리 조치.
Taint 확인 방법은 총 세 가지가 있습니다.
# 방법 1: AWS API로 노드 그룹 레벨 확인
aws eks describe-nodegroup --cluster-name myeks --nodegroup-name myeks-ng-2 \
| jq .nodegroup.taints
# 방법 2: 레이블로 ARM 노드만 필터링
kubectl get node -l kubernetes.io/arch=arm64
# 방법 3: 노드에 실제 적용된 taint 확인
kubectl describe node -l tier=secondary | grep -i taint