# PV 실습 자료 <1> 명령서버, eksctl로 eks 생성 1 클라우드 포메이션으로 명령서버 EC2 1대 생성 EC2 키페어 Access-key, Secret-key 미리 준비 CloudFormation 서울 리전으로 변경 My-VPC 생성됨, EC2 생성됨 2 EC2 Login 3 # EKS 생성할수 있는 권한 부여 aws configure AWS Access Key ID [None]: AKIA2ESLMQ AWS Secret Access Key [None]: JGgwvJFIQS2d35bM Default region name [None]: ap-northeast-2 Default output format [None]: < 엔터> [root@kops-ec2 environment]# aws s3 ls 2026-01-11 17:23:29 cf-templates-1m33dxyu90t4w-ap-northeast-2 EKS 생성 vpc는 eks-ctl-vpc 형식이 만들어진다. 4 cd mkdir 9 cd 9 export AWS_REGION=ap-northeast-2 echo ${AWS_REGION} 5 # eks 생성하기1 무료 계정으로 생성가능한 인스턴스 instanceType: m7i-flex.large 생성 cat << EOF > eks-demo-cluster.yaml --- apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: eks-demo # 생성할 EKS 클러스터명 region: ${AWS_REGION} # 클러스터를 생성할 리젼 version: "1.34" vpc: cidr: "192.168.0.0/16" # 클러스터에서 사용할 VPC의 CIDR managedNodeGroups: - name: node-group # 클러스터의 노드 그룹명 instanceType: m7i-flex.large # 클러스터 워커 노드의 인스턴스 타입 desiredCapacity: 2 # 클러스터 워커 노드의 갯수 volumeSize: 20 # 클러스터 워커 노드의 EBS 용량 (단위: GiB) iam: withAddonPolicies: imageBuilder: true # AWS ECR에 대한 권한 추가 albIngress: true # albIngress에 대한 권한 추가 cloudWatch: true # cloudWatch에 대한 권한 추가 autoScaler: true # auto scaling에 대한 권한 추가 cloudWatch: clusterLogging: enableTypes: ["*"] EOF eksctl create cluster -f eks-demo-cluster.yaml (13분 소요 됨) # 참고 사항 # 무료 계정으로 가능한 서버 t3.micro t3.small c7i-flex.large 2/4 m7i-flex.large 2/8 # eks 생성하기2 - m5.large로 생성 # 무료 계정에서 m5.large 는 워커 노드의 인스턴스 타입 생성 불가 4 # 터미널 2 watch -d kubectl get no,ing,pv,pvc,svc,pods,no,sc,deploy # 터미널 1 5 2단계: AWS 인프라 재구축 (보안 그룹 및 EFS) 변수를 사용하여 오타를 방지하고 VPC 환경에 맞게 생성합니다. # 1. 환경 변수 설정 (본인의 환경에 맞게 확인) 1 # $NODE_SG aws ec2 describe-instances \ --region ap-northeast-2 \ --filters "Name=instance-state-name,Values=running" "Name=tag:Name,Values=*node*" \ --query "Reservations[*].Instances[*].SecurityGroups[*].[GroupId,GroupName]" \ --output table # 수동입력 export NODE_SG="sg-0087f02b3347ce373" echo $NODE_SG 2 # vpc id aws ec2 describe-vpcs \ --region ap-northeast-2 \ --query "Vpcs[*].[VpcId,Tags[?Key=='Name'].Value | [0]]" \ --output table # 참고 eksctl-eks-demo-cluster/VPC 확인 - 예) vpc-0a9afb3f33167dca0 # 수동입력 vpc-0f9da6f6a242e8172 export MY_VPC_ID="vpc-0f9da6f6a242e8172" echo $MY_VPC_ID # 2. EFS 전용 보안 그룹 생성 export EFS_SG=$(aws ec2 create-security-group \ --group-name efs-final-sg-v2 \ --description "EFS Security Group for 2048" \ --vpc-id $MY_VPC_ID \ --region ap-northeast-2 \ --query 'GroupId' --output text) ----------------- # 3. 보안 그룹에 NFS(2049) 포트 허용 aws ec2 authorize-security-group-ingress \ --group-id $EFS_SG \ --protocol tcp --port 2049 \ --source-group $NODE_SG \ --region ap-northeast-2 # 4. EFS 파일 시스템 생성 export EFS_ID=$(aws efs create-file-system \ --creation-token game-2048-efs-v2 \ --region ap-northeast-2 \ --query 'FileSystemId' --output text) # 5. 모든 서브넷에 마운트 타겟 생성 for subnet in $(aws ec2 describe-subnets --filters "Name=vpc-id,Values=$MY_VPC_ID" --region ap-northeast-2 --query "Subnets[*].SubnetId" --output text); do aws efs create-mount-target \ --file-system-id $EFS_ID \ --subnet-id $subnet \ --security-groups $EFS_SG \ --region ap-northeast-2 done 6 3단계: 노드 IAM 권한 재설정 노드가 EFS를 제어할 수 있도록 정책을 확실히 붙여줍니다. "나는 이 EFS를 마운트할 자격이 있어! # 실제 노드 Role 이름 추출법 aws iam list-instance-profiles --query 'InstanceProfiles[*].InstanceProfileName' --output text | tr '\t' '\n' | grep eks eks-10ce30a5-ac3b-09d0-c187-801bbd5d5d80 # 수동 입력 export ROLE_NAME=$(aws iam get-instance-profile \ --instance-profile-name eks-10ce30a5-ac3b-09d0-c187-801bbd5d5d80 \ --query 'InstanceProfile.Roles[0].RoleName' --output text) echo $ROLE_NAME # 정책 연결 aws iam attach-role-policy \ --role-name $ROLE_NAME \ --policy-arn arn:aws:iam::aws:policy/service-role/AmazonEFSCSIDriverPolicy 7 4단계: 쿠버네티스 리소스 배포 (PV/PVC/Deploy) 여기서 가장 중요한 건 새로 생성된 $EFS_ID를 PV에 넣는 것입니다. kubectl create namespace game-2048 # 1. PV 생성 (ID 자동 입력) cat < /usr/share/nginx/html/test.txt" (10초후) # 2. 두 번째 Pod에서 해당 파일이 보이는지 확인 kubectl exec -n game-2048 -it pod/deployment-2048-7f4dfbb974-hlzvg -- cat /usr/share/nginx/html/test.txt EFS Storage Test 9 로드밸런서 접속 403 Forbidden nginx/1.29.5 드디어 Pod가 Running 상태가 되었는데 403 Forbidden이 뜨는 이유는, 현재 사용 중인 Nginx 이미지의 기본 경로 설정과 EFS 마운트가 충돌했기 때문입니다. 표준 Nginx 이미지는 /usr/share/nginx/html/ 경로에서 파일을 읽어 화면을 보여줍니다. 하지만 이 경로에 빈 EFS 볼륨을 마운트하는 순간, 원래 컨테이너 안에 들어있던 index.html 파일이 가려지고 텅 빈 EFS 내부가 나타나게 됩니다. Nginx는 보여줄 파일이 없어서 "접근 거부(403 Forbidden)" 에러를 보낸 것입니다. # 실행 중인 2048 Pod 중 하나를 선택해 index.html 파일을 생성합니다. kubectl exec -n game-2048 $(kubectl get pod -n game-2048 -o jsonpath='{.items[0].metadata.name}') -- sh -c "echo '

Welcome to 2048 with EFS

Storage is working correctly.

' > /usr/share/nginx/html/index.html" (1분후) Welcome to 2048 with EFS Storage is working correctly. 10 # 진짜 2048 게임으로 변경해보기 kubectl exec -n game-2048 $(kubectl get pod -n game-2048 -l app.kubernetes.io/name=app-2048 -o jsonpath='{.items[0].metadata.name}') -- sh -c " apt-get update && \ apt-get install -y wget unzip && \ wget https://github.com/gabrielecirulli/2048/archive/refs/heads/master.zip -O /tmp/2048.zip && \ unzip -o /tmp/2048.zip -d /tmp && \ cp -rf /tmp/2048-master/* /usr/share/nginx/html/ && \ rm -rf /tmp/2048.zip /tmp/2048-master " kubectl delete pod -n game-2048 --all <2> 트러블 슈팅 1 # 수동입력 = pod 이름 확인후 입력 kubectl describe pod/deployment-2048-6bf5cc59dd-6lsdc -n game-2048 AI에 확인 2 k ns k ns game-2048 3 드라이버 설치는 아주 완벽하게 되었습니다! 모든 efs-csi 포드들이 Running 상태이고 3/3 준비가 완료되었네요. 이제 시스템이 EFS를 마운트할 준비가 끝난 상태입니다. 그럼에도 불구하고 아까 띄워둔 2048 Pod가 여전히 ContainerCreating 상태라면, 이전에 발생했던 "Driver not found" 에러 기록 때문에 쿠버네티스가 재시도를 잠시 멈춘 상태일 수 있습니다. 상태를 갱신하기 위해 Pod를 재시작해주는 것이 가장 빠릅니다. 2048 Pod 재시작 (강제 갱신) 아래 명령어로 기존 Pod를 삭제하세요. Deployment에 의해 즉시 새 Pod가 생성되면서 드라이버를 통해 다시 마운트를 시도합니다. 4 kubectl delete pod -n game-2048 --all 5 # 수동입력 = pod 이름 kubectl describe pod/deployment-2048-6bf5cc59dd-8zsxr -n game-2048 드라이버 설치 후 발생한 이 에러 메시지는 문제의 핵심을 아주 명확하게 짚어주고 있습니다. please create a mount target in ap-northeast-2d 🚨 문제의 원인 현재 2048 Pod가 배포된 노드가 ap-northeast-2d 가용 영역(AZ)에 있는데, 해당 가용 영역에 EFS의 마운트 타겟(Mount Target)이 생성되어 있지 않아서 발생하는 문제입니다. EFS는 각 서브넷(가용 영역)마다 연결 통로인 마운트 타겟이 있어야 노드가 접근할 수 있습니다. 해결 CLI에서 현재 사용 중인 EFS(fs-050f65693023566ce) 설정으로 이동하여, ap-northeast-2d 가용 영역의 서브넷에 마운트 타겟을 추가 aws ec2 describe-subnets \ --filters "Name=availability-zone,Values=ap-northeast-2d" \ --query "Subnets[0].SubnetId" --output text subnet-0c7329c49f0c50f85 # 1. 서브넷 ID 변수 설정 export MY_SUBNET_ID=subnet-0c7329c49f0c50f85 # 2. 기존 마운트 타겟의 보안 그룹 ID 가져오기 export MY_SG_ID=$(aws efs describe-mount-target-security-groups \ --mount-target-id $(aws efs describe-mount-targets \ --file-system-id fs-050f65693023566ce \ --query "MountTargets[0].MountTargetId" --output text) \ --query "SecurityGroups[0]" --output text) # 3. 마운트 타겟 생성 aws efs create-mount-target \ --file-system-id fs-050f65693023566ce \ --subnet-id $MY_SUBNET_ID \ --security-groups $MY_SG_ID 1. 마운트 타겟 상태 모니터링 상태가 creating에서 available로 바뀔 때까지 10~20초 간격으로 아래 명령어를 확인하세요. Bash aws efs describe-mount-targets \ --file-system-id fs-050f65693023566ce \ --query "MountTargets[?AvailabilityZoneName=='ap-northeast-2d'].LifeCycleState" \ --output text 6 # 보안그룹 확인 보안 그룹(Security Group) 확인 필수! 마운트 타겟이 available이 되어도 노드에서 접속이 안 된다면 보안 그룹 문제입니다. 목록을 보니 efs-final-sg-v2 (sg-0516303dab170bff2)가 EFS용 보안 그룹으로 보입니다. 해당 보안 그룹에 노드의 통신이 허용되어 있는지 확인해야 합니다. 대상 보안 그룹: sg-0516303dab170bff2 (efs-final-sg-v2) 허용 규칙: Inbound, NFS (2049 포트), 소스(Source)는 sg-0e3509e26dfac6987 (ClusterSharedNodeSecurityGroup) aws ec2 describe-security-group-rules \ --filters "Name=group-id,Values=sg-0516303dab170bff2" \ --query 'SecurityGroupRules[?FromPort==`2049`].{Protocol:IpProtocol, Source:ReferencedGroupInfo.GroupId, Port:FromPort}' \ --output table 7 kubectl delete pod -n game-2048 --all kubectl get pod -n game-2048 -w 8 kubectl describe pod/deployment-2048-6bf5cc59dd-q2hdd -n game-2048 kubectl describe pod/deployment-2048-6bf5cc59dd-hvh7m -n game-2048 바로 실행 cat << 'EOF' > create-efs-mounts.sh #!/bin/bash # 1. 설정 변수 EFS_ID="fs-050f65693023566ce" SG_ID="sg-0516303dab170bff2" VPC_ID="vpc-0a9afb3f33167dca0" echo "🔎 VPC($VPC_ID) 내의 모든 서브넷을 검색합니다..." # 2. VPC 내의 모든 서브넷 ID 가져오기 SUBNET_IDS=$(aws ec2 describe-subnets \ --filters "Name=vpc-id,Values=$VPC_ID" \ --query "Subnets[*].SubnetId" \ --output text) # 3. 각 서브넷별로 마운트 타겟 생성 루프 for SUBNET in $SUBNET_IDS; do AZ=$(aws ec2 describe-subnets --subnet-ids $SUBNET --query "Subnets[0].AvailabilityZone" --output text) echo "🚀 생성 시도: 가용영역($AZ), 서브넷($SUBNET)..." aws efs create-mount-target \ --file-system-id $EFS_ID \ --subnet-id $SUBNET \ --security-groups $SG_ID 2>/dev/null if [ $? -eq 0 ]; then echo "✅ $AZ 영역에 마운트 타겟 생성 요청 성공!" else echo "⚠️ $AZ 영역은 이미 존재하거나 생성 중입니다. (Pass)" fi done echo "---------------------------------------------------" echo "⏳ 마운트 타겟이 'available' 상태가 될 때까지 기다립니다..." aws efs describe-mount-targets --file-system-id $EFS_ID --query "MountTargets[*].{AZ:AvailabilityZoneName, State:LifeCycleState}" --output table EOF # 스크립트 실행 권한 부여 및 실행 chmod +x create-efs-mounts.sh ./create-efs-mounts.sh 9 kubectl describe pod/deployment-2048-f5b9597f7-25ntr -n game-2048 kubectl delete pod -n game-2048 --all 10 브라우저 주소창에 아래 주소를 복사해서 붙여넣으세요: http://a03e02a6c8ef24ff5ba89ed35d9cfdff-1614511123.ap-northeast-2.elb.amazonaws.com 11 # eks 클러스터 삭제 eksctl delete cluster --name eks-demo --region ap-northeast-2