<1> 테스트 준비 0 서울리전 ec2 명령서버 eks 설치 access-key, secret-key 준비 aws configure ap-northeast-2 aws s3 ls # EKS 생성 # 아래는 리눅스 용 cat < eks-freetier-setup.yaml apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: free-vpc-cluster region: ap-northeast-2 version: "1.34" vpc: clusterEndpoints: publicAccess: true privateAccess: true nat: gateway: Single # 비용 절감을 위해 NAT 게이트웨이를 1개만 생성 (중요!) managedNodeGroups: - name: standard-nodes # --- 인스턴스 타입 선택 가이드 --- # 1. t3.micro : 프리티어 대상 (단, K8s 시스템 Pod 실행 시 리소스가 매우 부족할 수 있음) # 2. t3.small : 가성비 추천 (시스템 안정성 확보) # 3. c7i-flex.large (2cpu/4gb) : 연산 위주 # 4. m7i-flex.large (2cpu/8gb) : 메모리 여유 instanceType: t3.small minSize: 1 maxSize: 2 desiredCapacity: 1 # 비용 절감을 위해 노드 수를 1대로 시작 (필요 시 증가) privateNetworking: true iam: withAddonPolicies: imageBuilder: true autoScaler: true cloudWatch: true # 필수 애드온만 설치 addons: - name: vpc-cni - name: coredns - name: kube-proxy EOF # 클러스터 생성 시작 eksctl create cluster -f eks-freetier-setup.yaml # eksctl 로 쿠버네티스 생성시 cloudformation을 이용하여 생성하게 된다. (15분) kubectl get nodes <2> 실습 1 # 터미널 1 k ns default watch -d kubectl get no,nodepool,ec2nodeclass,deployment,rs,pods,svc kubectl get nodepool kubectl get ec2nodeclass 2 # 터미널 2 1단계: 환경 변수 설정 작업 편의를 위해 변수를 먼저 선언합니다. export CLUSTER_NAME="free-vpc-cluster" export AWS_REGION="ap-northeast-2" export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text) # 클러스터 엔드포인트 확인 export CLUSTER_ENDPOINT=$(aws eks describe-cluster --name ${CLUSTER_NAME} --query "cluster.endpoint" --output text) echo $CLUSTER_ENDPOINT https://9E1DC9DD816E84F41558A38948F40BAD.gr7.ap-northeast-2.eks.amazonaws.com 3 2단계: IAM 역할(Role) 및 인스턴스 프로파일 생성 Karpenter 컨트롤러와 노드가 사용할 권한을 만듭니다. (1) 컨트롤러용 IAM 역할 (IRSA 대신 노드 그룹 역할에 권한 부여) 아까 확인했듯이 IRSA가 꼬이는 경우가 많으므로, 현재 노드 그룹 역할에 권한을 직접 주입하는 것이 가장 확실합니다. # 현재 사용 중인 노드 그룹의 역할 이름을 찾습니다. NODE_ROLE_NAME=$(aws iam list-roles --query "Roles[?contains(RoleName, 'nodegroup') && contains(RoleName, '${CLUSTER_NAME}')].RoleName" --output text) # Karpenter에 필요한 모든 권한 주입 aws iam put-role-policy --role-name ${NODE_ROLE_NAME} \ --policy-name KarpenterControllerPolicy \ --policy-document '{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ec2:CreateFleet", "ec2:CreateLaunchTemplate", "ec2:CreateTags", "ec2:DescribeAvailabilityZones", "ec2:DescribeInstanceTypeOfferings", "ec2:DescribeInstanceTypes", "ec2:DescribeInstances", "ec2:DescribeLaunchTemplates", "ec2:DescribeSecurityGroups", "ec2:DescribeSubnets", "ec2:RunInstances", "ec2:TerminateInstances", "iam:PassRole", "iam:GetInstanceProfile", "iam:CreateInstanceProfile", "iam:TagInstanceProfile", "iam:AddRoleToInstanceProfile", "ssm:GetParameter", "pricing:GetProducts", "ec2:DescribeSpotPriceHistory" ], "Resource": "*" } ] }' (2) 신규 노드용 IAM 역할 및 프로파일 생성 # 노드용 역할 생성 cat < node-trust-policy.json {"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ec2.amazonaws.com"},"Action":"sts:AssumeRole"}]} EOF aws iam create-role --role-name "KarpenterNodeRole-${CLUSTER_NAME}" --assume-role-policy-document file://node-trust-policy.json # 필수 정책 연결 aws iam attach-role-policy --role-name "KarpenterNodeRole-${CLUSTER_NAME}" --policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy aws iam attach-role-policy --role-name "KarpenterNodeRole-${CLUSTER_NAME}" --policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy aws iam attach-role-policy --role-name "KarpenterNodeRole-${CLUSTER_NAME}" --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly aws iam attach-role-policy --role-name "KarpenterNodeRole-${CLUSTER_NAME}" --policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore # 인스턴스 프로파일 생성 및 역할 연결 aws iam create-instance-profile --instance-profile-name "KarpenterNodeInstanceProfile-${CLUSTER_NAME}" aws iam add-role-to-instance-profile --instance-profile-name "KarpenterNodeInstanceProfile-${CLUSTER_NAME}" --role-name "KarpenterNodeRole-${CLUSTER_NAME}" 3단계: AWS 리소스 태깅 (Discovery용) Karpenter가 서브넷과 보안 그룹을 찾을 수 있게 이름표를 답니다. # 서브넷 태깅 SUBNET_IDS=$(aws ec2 describe-subnets --filters "Name=tag:alpha.eksctl.io/cluster-name,Values=${CLUSTER_NAME}" --query 'Subnets[*].SubnetId' --output text) aws ec2 create-tags --resources $SUBNET_IDS --tags Key=karpenter.sh/discovery,Value=${CLUSTER_NAME} # 보안 그룹 태깅 SG_IDS=$(aws ec2 describe-security-groups --filters "Name=tag:alpha.eksctl.io/cluster-name,Values=${CLUSTER_NAME}" --query 'SecurityGroups[*].GroupId' --output text) aws ec2 create-tags --resources $SG_IDS --tags Key=karpenter.sh/discovery,Value=${CLUSTER_NAME} 4단계: Karpenter Helm 설치 (v1.0.6) helm upgrade --install karpenter oci://public.ecr.aws/karpenter/karpenter \ --version 1.0.6 \ --namespace karpenter --create-namespace \ --set settings.clusterName=${CLUSTER_NAME} \ --set settings.clusterEndpoint=${CLUSTER_ENDPOINT} \ --set settings.interruptionQueueName=${CLUSTER_NAME} \ --wait 5단계: NodePool & EC2NodeClass 배포 (프리티어 최적화) cat < 3h17m v1.34.3-eks-70ce843 node/ip-192-168-175-38.ap-northeast-2.compute.internal Ready 3h12m v1.34.3-eks-70ce843 NAME NODECLASS NODES READY AGE nodepool.karpenter.sh/default default 0 True 18m NAME READY AGE ec2nodeclass.karpenter.k8s.aws/default True 20s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.100.0.1 443/TCP 3h24m 6단계: 중요! EKS 노드 인증(Access Entry) 등록 새 노드가 클러스터에 합류할 수 있게 권한을 엽니다. eksctl create iamidentitymapping \ --cluster ${CLUSTER_NAME} \ --region ${AWS_REGION} \ --arn arn:aws:iam::${AWS_ACCOUNT_ID}:role/KarpenterNodeRole-${CLUSTER_NAME} \ --group system:bootstrappers \ --group system:nodes \ --username system:node:{{EC2PrivateDNSName}} 7단계: 테스트 # 부하 생성 kubectl create deployment karpenter-test --image=registry.k8s.io/pause:3.9 kubectl patch deployment karpenter-test -p '{"spec":{"template":{"spec":{"containers":[{"name":"pause","image":"registry.k8s.io/pause:3.9","resources":{"requests":{"cpu":"1"}}}]}}}}' kubectl scale deployment karpenter-test --replicas=5 # 모니터링 kubectl get nodes -w <3> 삭제 삭제후 재설치 0단계: 기존 리소스 완전 삭제 먼저 꼬여있는 리소스를 깨끗하게 지웁니다. # 1. Karpenter Helm 삭제 helm uninstall karpenter -n karpenter # 2. 관련 리소스 강제 삭제 (Finalizer 제거 포함) kubectl patch ec2nodeclass default --type merge -p '{"metadata":{"finalizers":null}}' 2>/dev/null kubectl delete nodepool default --ignore-not-found kubectl delete ec2nodeclass default --ignore-not-found # 3. 네임스페이스 삭제 kubectl delete namespace karpenter # 노드테스트 부하 삭제 kubectl delete deployment karpenter-test # 인스턴스를 꺼도 Karpenter가 "어? 노드가 부족하네?" 하고 다시 띄울 수 있습니다. 이를 막기 위해 노드 생성 규칙 자체를 삭제합니다. kubectl delete nodepool default kubectl delete ec2nodeclass default