EKS 트러블슈팅 - Node Group 생성 실패 및 vpc-cni addon 누락
문제 상황#
EKS 1.34 클러스터 구축 중 발생한 두 가지 주요 이슈와 해결 과정 정리.
1. Node Group 생성 실패 - kubelet 라벨 문제#
증상#
- Node Group 상태:
CREATE_FAILED - 에러 메시지:
NodeCreationFailure - Unhealthy nodes in the kubernetes cluster - EC2 인스턴스는 실행 중이지만 클러스터에 조인 안 됨
원인 분석#
SSM으로 노드에 접속하여 kubelet 로그 확인:
sudo journalctl -u kubelet -n 50
kubelet 에러:
unknown 'kubernetes.io' or 'k8s.io' labels specified with --node-labels
근본 원인#
Terraform EKS 모듈에서 노드그룹 라벨에 node-role.kubernetes.io/infra 사용:
labels = {
"node-role.kubernetes.io/infra" = "true" # <- 이게 문제!
"role" = "infra"
}
왜 문제인가?
- kubelet은
kubernetes.io또는k8s.io네임스페이스의 라벨을 노드 등록 시 사용하는 것을 금지함 - 이는 보안상의 이유로, 해당 네임스페이스는 쿠버네티스 시스템이 관리하는 예약된 네임스페이스
- 노드가 스스로 이 네임스페이스의 라벨을 설정하면 권한 상승 등의 보안 문제 발생 가능
해결#
node-role.kubernetes.io/* 라벨 제거:
# 수정된 코드
labels = {
"arch" = "amd64"
"role" = "infra" # 일반 라벨 사용
"capacity-type" = "on-demand"
"workload" = "infra"
"owner" = var.owner_name
}
영향받은 파일#
modules/eks/main.tf- monitoring, infra, apps 노드그룹 라벨staging/charts/karpenter/templates/nodepool.yaml- Karpenter NodePool 라벨
2. Node NotReady - vpc-cni addon 누락#
증상#
- 모든 노드가
NotReady상태 kubectl describe node에서:NetworkNotReady: network is not ready: container runtime network not ready NetworkPluginNotReady: cni plugin not initialized
원인 분석#
kube-system pods 확인:
kubectl get pods -n kube-system
aws-node (vpc-cni) pods가 없음!
addon 목록 확인:
aws eks list-addons --cluster-name goormgb-staging-eks --profile wonny
결과:
{
"addons": ["aws-ebs-csi-driver"] // vpc-cni, kube-proxy, coredns 없음!
}
근본 원인#
Terraform apply 과정에서 cluster_addons 블록의 addon들이 생성되지 않음.
cluster_addons = {
vpc-cni = { most_recent = true }
kube-proxy = { most_recent = true }
coredns = { most_recent = true }
}
terraform state 확인 시:
terraform state list | grep addon
data.aws_eks_addon_version.this["vpc-cni"]- 버전 데이터만 존재aws_eks_addon.this["vpc-cni"]- 실제 리소스 없음
해결#
EKS destroy 후 다시 apply:
terraform destroy -target=module.eks
terraform apply -target=module.eks
필수 EKS Addons#
| Addon | 역할 |
|---|---|
| vpc-cni | Pod 네트워킹 (ENI 할당) - 없으면 노드 NotReady |
| kube-proxy | Service 네트워킹 (iptables/ipvs) |
| coredns | DNS 서비스 |
| ebs-csi-driver | EBS 볼륨 프로비저닝 |
추가 설정 - Addon Tolerations#
taint가 있는 노드에서 addon이 실행되려면 toleration 필요:
cluster_addons = {
vpc-cni = {
most_recent = true
configuration_values = jsonencode({
tolerations = [{
key = "role"
operator = "Exists"
effect = "NoSchedule"
}]
})
}
coredns = {
most_recent = true
configuration_values = jsonencode({
tolerations = [{
key = "role"
operator = "Equal"
value = "infra"
effect = "NoSchedule"
}]
nodeSelector = {
role = "infra"
}
})
}
}
교훈#
kubernetes.io 네임스페이스 라벨 금지: kubelet이 거부함. 일반 라벨(
role,workload등) 사용할 것.EKS Addon 확인 필수:
aws eks list-addons로 필수 addon 존재 여부 확인.SSM 디버깅 활용: 노드 문제 시 SSM으로 접속하여
journalctl -u kubelet확인.terraform state 확인: plan에서 보이는 것과 실제 생성된 것이 다를 수 있음.
참고 명령어#
# 노드 상태 확인
kubectl get nodes -w
kubectl describe node <node-name>
# Addon 확인
aws eks list-addons --cluster-name <cluster> --profile <profile>
aws eks describe-addon --cluster-name <cluster> --addon-name vpc-cni
# SSM 접속
aws ssm start-session --target <instance-id> --profile <profile>
# kubelet 로그
sudo journalctl -u kubelet -n 100
# EC2 콘솔 출력 (부팅 로그)
aws ec2 get-console-output --instance-id <id> --latest --output text
EKS Addons 완전 가이드#
Addon이란?#
EKS Addon은 쿠버네티스 클러스터의 핵심 운영 기능을 제공하는 소프트웨어 컴포넌트다. AWS가 관리하며, 버전 호환성 검증과 보안 패치가 자동으로 적용된다.
Addon 사용 장점:
- AWS 관리형: 버전 업데이트, 보안 패치 자동화
- EKS 버전 호환성 보장
- IAM Role for Service Account (IRSA) 통합
- 구성 값 커스터마이징 가능
필수 Addons (클러스터 동작에 반드시 필요)#
1. Amazon VPC CNI (vpc-cni)#
역할: Pod 네트워킹 담당. 각 Pod에 VPC의 실제 IP 주소를 할당.
동작 방식:
- ENI(Elastic Network Interface)를 노드에 연결
- ENI의 Secondary IP를 Pod에 할당
- Pod가 VPC 내 다른 리소스와 직접 통신 가능
없으면?
- 노드가
NotReady상태 유지 - Pod가 IP를 받지 못해 스케줄링 불가
- 컨테이너 네트워크 초기화 실패
DaemonSet으로 배포: 모든 노드에서 aws-node Pod 실행
# 주요 설정
configuration_values:
env:
ENABLE_PREFIX_DELEGATION: "true" # Pod 밀도 증가
WARM_IP_TARGET: "5" # 예약 IP 수
tolerations:
- operator: Exists # 모든 노드에서 실행
2. CoreDNS (coredns)#
역할: 클러스터 내 DNS 서비스. Service 이름을 IP로 해석.
동작 방식:
kube-dns서비스로 노출 (기본 ClusterIP: 10.100.0.10)- Pod의
/etc/resolv.conf가 이 DNS 서버 참조 - Service 이름 → ClusterIP 해석
- External 도메인은 upstream DNS로 포워딩
없으면?
curl http://my-service같은 서비스 디스커버리 불가- Pod 간 통신 시 IP 직접 사용해야 함
- 외부 도메인 해석도 불가 (설정에 따라)
Deployment로 배포: 보통 2개 replica (HA)
# 주요 설정
configuration_values:
replicaCount: 2
tolerations:
- key: "role"
value: "infra"
effect: "NoSchedule"
nodeSelector:
role: infra
3. kube-proxy (kube-proxy)#
역할: Service 네트워킹 담당. Service ClusterIP → Pod IP 라우팅.
동작 방식:
- 각 노드에서 iptables/ipvs 규칙 관리
- Service의 ClusterIP로 들어온 트래픽을 backend Pod로 분산
- NodePort, LoadBalancer 타입 Service도 처리
없으면?
- ClusterIP Service 접근 불가
- Service → Pod 로드밸런싱 안 됨
- 네트워크 정책 일부 동작 안 함
DaemonSet으로 배포: 모든 노드에서 실행
# 주요 설정
configuration_values:
mode: "iptables" # 또는 "ipvs"
tolerations:
- operator: Exists
권장 Addons (운영에 필요)#
4. Amazon EBS CSI Driver (aws-ebs-csi-driver)#
역할: EBS 볼륨의 동적 프로비저닝. PersistentVolumeClaim → EBS 볼륨 자동 생성.
동작 방식:
- CSI (Container Storage Interface) 표준 구현
- StorageClass 기반 볼륨 프로비저닝
- gp3, io1, io2 등 EBS 타입 지원
- 스냅샷, 리사이즈 지원
없으면?
- PVC 생성 시 볼륨 프로비저닝 안 됨 (Pending 상태)
- StatefulSet 사용 불가
- 데이터 영속성 확보 불가
구성:
- Controller: Deployment (2 replica)
- Node: DaemonSet (각 노드)
# 주요 설정
configuration_values:
controller:
tolerations:
- key: "role"
value: "infra"
effect: "NoSchedule"
nodeSelector:
role: infra
node:
tolerations:
- operator: Exists # 모든 노드에서 실행
5. Amazon EFS CSI Driver (aws-efs-csi-driver)#
역할: EFS 파일시스템 마운트. 여러 Pod에서 동시에 읽기/쓰기 가능.
사용 사례:
- 공유 파일 스토리지 (ReadWriteMany)
- 컨테이너 간 파일 공유
- 정적 콘텐츠 서빙
없으면?
- EFS 마운트 불가
- ReadWriteMany 볼륨 사용 불가
6. AWS Load Balancer Controller (별도 설치)#
역할: ALB/NLB 자동 프로비저닝. Ingress, Service(type: LoadBalancer) 처리.
주의: EKS Addon이 아닌 Helm Chart로 별도 설치 필요!
# Helm으로 설치
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=<cluster-name>
선택적 Addons#
7. Amazon CloudWatch Observability (amazon-cloudwatch-observability)#
역할: 컨테이너 메트릭, 로그를 CloudWatch로 전송.
구성 요소:
- CloudWatch Agent: 메트릭 수집
- Fluent Bit: 로그 수집
- ADOT Collector: 트레이싱 (선택)
8. Amazon GuardDuty Agent (aws-guardduty-agent)#
역할: 런타임 위협 탐지. 컨테이너 이상 행동 모니터링.
9. AWS Distro for OpenTelemetry (adot)#
역할: 분산 트레이싱, 메트릭 수집. X-Ray, CloudWatch, Prometheus 등으로 전송.
10. Karpenter (별도 설치)#
역할: 노드 오토스케일링. Pending Pod 감지 → 최적 인스턴스 프로비저닝.
EKS Addon 아님! Helm으로 별도 설치:
helm install karpenter oci://public.ecr.aws/karpenter/karpenter \
--namespace karpenter
Addon 관리 명령어#
# 사용 가능한 addon 목록
aws eks describe-addon-versions --kubernetes-version 1.34 \
--query 'addons[].{name:addonName,versions:addonVersions[0].addonVersion}' \
--output table
# 클러스터에 설치된 addon 목록
aws eks list-addons --cluster-name <cluster>
# addon 상세 정보
aws eks describe-addon --cluster-name <cluster> --addon-name vpc-cni
# addon 설치
aws eks create-addon --cluster-name <cluster> --addon-name vpc-cni
# addon 업데이트
aws eks update-addon --cluster-name <cluster> --addon-name vpc-cni \
--addon-version v1.21.1-eksbuild.5
# addon 삭제
aws eks delete-addon --cluster-name <cluster> --addon-name vpc-cni
Terraform에서 Addon 설정#
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.0"
cluster_addons = {
# 필수
vpc-cni = {
most_recent = true
configuration_values = jsonencode({
tolerations = [{ operator = "Exists" }]
})
}
kube-proxy = {
most_recent = true
}
coredns = {
most_recent = true
configuration_values = jsonencode({
tolerations = [{
key = "role"
value = "infra"
effect = "NoSchedule"
}]
})
}
# 권장
aws-ebs-csi-driver = {
most_recent = true
service_account_role_arn = module.ebs_csi_irsa.iam_role_arn
}
}
}
Addon 버전 호환성 확인#
# 특정 K8s 버전에서 지원되는 addon 버전
aws eks describe-addon-versions \
--addon-name vpc-cni \
--kubernetes-version 1.34 \
--query 'addons[].addonVersions[].addonVersion'
주의사항:
- EKS 버전 업그레이드 전 addon 호환성 확인
most_recent = true사용 시 자동으로 최신 호환 버전 선택- 프로덕션에서는 버전 고정 권장
Addon 문제 해결#
Addon이 Degraded 상태일 때:
# 상태 확인
aws eks describe-addon --cluster-name <cluster> --addon-name vpc-cni \
--query 'addon.health'
# Pod 상태 확인
kubectl get pods -n kube-system -l k8s-app=aws-node
kubectl describe pod -n kube-system <aws-node-pod>
# 이벤트 확인
kubectl get events -n kube-system --sort-by='.lastTimestamp'
흔한 문제:
- IRSA 역할 권한 부족 → IAM 정책 확인
- toleration 없음 → 모든 노드에 taint가 있으면 실행 불가
- 리소스 부족 → requests/limits 조정
- 이미지 pull 실패 → ECR 권한 또는 네트워크 확인