이 글은 CloudNet@팀의 AWS EKS Workshop Study(AEWS) 3기 스터디 내용을 바탕으로 작성되었습니다.
AEWS는 CloudNet@의 '가시다'님께서 진행하는 스터디로, EKS를 학습하는 과정입니다.
EKS를 깊이 있게 이해할 기회를 주시고, 소중한 지식을 나눠주시는 가시다님께 다시 한번 감사드립니다.
이 글이 EKS를 학습하는 분들께 도움이 되길 바랍니다.
이 실습은 AWS에서 제공하는 EKS Auto Mode 샘플 레포지토리를 사용하여 Terraform을 통해 Auto Mode 기반의 EKS 클러스터를 배포하는 과정입니다.
기존 EC2 또는 Fargate 기반과는 다르게, Auto Mode는 노드 구성/운영 자동화, Karpenter 기반 동적 노드 생성, 세분화된 정책 관리 등의 특성을 지닙니다.
# Get the code
git clone https://github.com/aws-samples/sample-aws-eks-auto-mode.git
cd sample-aws-eks-auto-mode/terraform

region ap-northeast-2, vpc_cidr 10.20.0.0/16 로 변경합니다.
...
variable "region" {
description = "region"
default = "ap-northeast-2"
type = string
}
...
# VPC with 65536 IPs (10.0.0.0/16) for 3 AZs
variable "vpc_cidr" {
description = "VPC CIDR. This should be a valid private (RFC 1918) CIDR range"
default = "10.20.0.0/16"
type = string
}

# eks.tf : "system" 은 '전용인스턴스'로 추가하지 않는다
...
cluster_compute_config = {
enabled = true
node_pools = ["general-purpose"]
}
...
system 노드는 생성하지 않고, general-purpose NodePool만 사용addons 구성은 포함되어 있지 않음(Auto Mode가 관리하기 때문)
# Initialize and apply Terraform
terraform init
terraform plan
terraform apply -auto-approve
...
null_resource.create_nodepools_dir: Creating...
null_resource.create_nodepools_dir: Provisioning with 'local-exec'...
null_resource.create_nodepools_dir (local-exec): Executing: ["/bin/sh" "-c" "mkdir -p ./../nodepools"]
...
null_resource.create_nodepools_dir 작업에서 ../nodepools 디렉토리가 생성됨


# Configure kubectl
cat setup.tf
ls -l ../nodepools
$(terraform output -raw configure_kubectl)
# kubectl context 이름 변경
kubectl ctx
kubectl config rename-context "arn:aws:eks:ap-northeast-2:$(aws sts get-caller-identity --query 'Account' --output text):cluster/automode-cluster" "automode-lab"
kubectl ns default
# 아래 IP의 ENI 찾아보자
kubectl get svc,ep
# 출력 예시
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 172.20.0.1 <none> 443/TCP 27m
NAME ENDPOINTS AGE
endpoints/kubernetes 10.20.22.204:443,10.20.40.216:443 27m
#
terraform state list
terraform show
terraform state show 'module.eks.aws_eks_cluster.this[0]'
# 출력 예시
...
compute_config {
enabled = true
node_pools = [
"general-purpose",
]
node_role_arn = "arn:aws:iam::911283464785:role/automode-cluster-eks-auto-20250316042752605600000003"
}
...
172.20.0.110.20.26.9, 10.20.6.61




=> 노드와 파드에 아무것도 뜨지 않습니다.





kubectl get crd
# 출력 예시
NAME CREATED AT
cninodes.eks.amazonaws.com 2025-03-14T12:27:23Z
cninodes.vpcresources.k8s.aws 2025-03-14T12:23:31Z
ingressclassparams.eks.amazonaws.com 2025-03-14T12:27:23Z
nodeclaims.karpenter.sh 2025-03-14T12:27:23Z
nodeclasses.eks.amazonaws.com 2025-03-14T12:27:23Z
nodediagnostics.eks.amazonaws.com 2025-03-14T12:27:23Z
nodepools.karpenter.sh 2025-03-14T12:27:23Z
policyendpoints.networking.k8s.aws 2025-03-14T12:23:31Z
securitygrouppolicies.vpcresources.k8s.aws 2025-03-14T12:23:31Z
targetgroupbindings.eks.amazonaws.com 2025-03-14T12:27:23Z
kubectl api-resources | grep -i node
# 출력 예시
nodes no v1 false Node
cninodes cni,cnis eks.amazonaws.com/v1alpha1 false CNINode
nodeclasses eks.amazonaws.com/v1 false NodeClass
nodediagnostics eks.amazonaws.com/v1alpha1 false NodeDiagnostic
nodeclaims karpenter.sh/v1 false NodeClaim
nodepools karpenter.sh/v1 false NodePool
runtimeclasses node.k8s.io/v1 false RuntimeClass
csinodes storage.k8s.io/v1 false CSINode
cninodes cnd vpcresources.k8s.aws/v1alpha1 false CNINode
# 노드에 Access가 불가능하니, 분석 지원(CRD)제공
kubectl explain nodediagnostics
# 출력 예시
GROUP: eks.amazonaws.com
KIND: NodeDiagnostic
VERSION: v1alpha1
DESCRIPTION:
The name of the NodeDiagnostic resource is meant to match the name of the
node which should perform the diagnostic tasks

kubectl get nodeclasses.eks.amazonaws.com
NAME ROLE READY AGE
default automode-cluster-eks-auto-20250314121820950800000003 True 29m
kubectl get nodeclasses.eks.amazonaws.com -o yaml
...
spec:
ephemeralStorage:
iops: 3000
size: 80Gi
throughput: 125
networkPolicy: DefaultAllow
networkPolicyEventLogs: Disabled
role: automode-cluster-eks-auto-20250314121820950800000003
securityGroupSelectorTerms:
- id: sg-05d210218e5817fa1
snatPolicy: Random # ???
subnetSelectorTerms:
- id: subnet-0539269140458ced5
- id: subnet-055dc112cdd434066
- id: subnet-0865f60e4a6d8ad5c
status:
...
instanceProfile: eks-ap-northeast-2-automode-cluster-4905473370491687283
securityGroups:
- id: sg-05d210218e5817fa1
name: eks-cluster-sg-automode-cluster-2065126657
subnets:
- id: subnet-0539269140458ced5
zone: ap-northeast-2a
zoneID: apne2-az1
- id: subnet-055dc112cdd434066
zone: ap-northeast-2b
zoneID: apne2-az2
- id: subnet-0865f60e4a6d8ad5c
zone: ap-northeast-2c
zoneID: apne2-az3
#
kubectl get nodepools
NAME NODECLASS NODES READY AGE
general-purpose default 0 True 33m
kubectl get nodepools -o yaml
...
spec:
disruption:
budgets:
- nodes: 10%
consolidateAfter: 30s
consolidationPolicy: WhenEmptyOrUnderutilized
template:
metadata: {}
spec:
expireAfter: 336h # 14일
nodeClassRef:
group: eks.amazonaws.com
kind: NodeClass
name: default
requirements:
- key: karpenter.sh/capacity-type
operator: In
values:
- on-demand
- key: eks.amazonaws.com/instance-category
operator: In
values:
- c
- m
- r
- key: eks.amazonaws.com/instance-generation
operator: Gt
values:
- "4"
- key: kubernetes.io/arch
operator: In
values:
- amd64
- key: kubernetes.io/os
operator: In
values:
- linux
terminationGracePeriod: 24h0m0s
...


kubectl get mutatingwebhookconfiguration
kubectl get validatingwebhookconfiguration

eks-node-viewer --node-sort=eks-node-viewer/node-cpu-usage=dsc --extra-labels eks-node-viewer/node-age
watch -d kubectl get node,pod -A
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set env.TZ="Asia/Seoul" --namespace kube-system
kubectl get events -w --sort-by '.lastTimestamp' # 출력 이벤트 로그 분석해보자




# 확인
kubectl get nodeclaims
NAME TYPE CAPACITY ZONE NODE READY AGE
general-purpose-528mt c5a.large on-demand ap-northeast-2c i-09cf206aee76f0bee True 54s
# OS, KERNEL, CRI 확인
kubectl get node -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
i-09cf206aee76f0bee Ready <none> 2m14s v1.31.4-eks-0f56d01 10.20.44.40 <none> Bottlerocket (EKS Auto) 2025.3.9 (aws-k8s-1.31) 6.1.129 containerd://1.7.25+bottlerocket
# CNI 노드 확인
kubectl get cninodes.eks.amazonaws.com
NAME AGE
i-09cf206aee76f0bee 3m24s

#[신규 터미널] 포트 포워딩
kubectl port-forward deployment/kube-ops-view -n kube-system 8080:8080 &

# 접속 주소 확인 : 각각 1배, 1.5배, 3배 크기
echo -e "KUBE-OPS-VIEW URL = http://localhost:8080"
echo -e "KUBE-OPS-VIEW URL = http://localhost:8080/#scale=1.5"
echo -e "KUBE-OPS-VIEW URL = http://localhost:8080/#scale=3"
open "http://127.0.0.1:8080/#scale=1.5" # macOS


kube-ops-view로 표시되는 노드는 EC2 인스턴스로 자동 생성된 EKS Auto Mode 노드이며, 콘솔의 EC2 > 인스턴스 목록에서 확인 가능합니다.i-로 시작하는 EC2 Instance ID 형식이며, Karpenter가 생성한 NodeClaim과 일치합니다.Amazon EKS Auto Mode 클러스터에서 Karpenter의 동작 방식인 Workload 기반 자동 노드 프로비저닝 기능을 확인하기 위한 것입니다. Deployment를 통해 리소스를 요청하면, Karpenter는 Auto Mode 노드를 자동으로 생성하여 스케줄링할 수 있도록 처리합니다.
# Step 1: Review existing compute resources (optional)
kubectl get nodepools
general-purpose

# Step 2: Deploy a sample application to the cluster
# eks.amazonaws.com/compute-type: auto selector requires the workload be deployed on an Amazon EKS Auto Mode node.
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: inflate
spec:
replicas: 1
selector:
matchLabels:
app: inflate
template:
metadata:
labels:
app: inflate
spec:
terminationGracePeriodSeconds: 0
nodeSelector:
eks.amazonaws.com/compute-type: auto
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
containers:
- name: inflate
image: public.ecr.aws/eks-distro/kubernetes/pause:3.7
resources:
requests:
cpu: 1
securityContext:
allowPrivilegeEscalation: false
EOF

# Step 3: Watch Kubernetes Events
kubectl get events -w --sort-by '.lastTimestamp'
kubectl get nodes

kubectl scale deployment inflate --replicas 100 && kubectl get events -w --sort-by '.lastTimestamp'
#
kubectl scale deployment inflate --replicas 200 && kubectl get events -w --sort-by '.lastTimestamp'
#
kubectl scale deployment inflate --replicas 50 && kubectl get events -w --sort-by '.lastTimestamp'
eks-node-viewer --node-sort=eks-node-viewer/node-cpu-usage=dsc --extra-labels eks-node-viewer/node-age
watch -d kubectl get node,pod -A
만약 kube-ops-view 파드가 함께 실행 중이라면, 자원 부족 시 Eviction 대상이 될 수 있습니다.
포워딩 중이던 포트 연결이 끊기는 경우 다시 실행 필요:
kubectl port-forward deployment/kube-ops-view -n kube-system 8080:8080 &
PodDisruptionBudget 또는 priorityClass를 미설정했을 때 발생할 수 있는 일반적인 문제이며, 실제 운영 환경에서는 이를 고려한 구성 설계가 필요합니다.실습 종료 후 Deployment를 삭제하여 노드 정리 이벤트 및 스케일 다운 여부를 확인합니다.
# 실습 확인 후 삭제
kubectl delete deployment inflate && kubectl get events -w --sort-by '.lastTimestamp'