Chapter 01 - 강사용 답안

VPC 네트워크 구축 - 정답 및 해설

이 문서의 내용

  • 각 실습 단계의 웹 콘솔 상세 절차AWS CLI 명령어
  • 각 단계별 해설 (왜 이렇게 하는지)
  • 검증 스크립트로 학생들의 작업 결과 확인
  • 학생들이 자주 겪는 트러블슈팅 가이드

답안 개요

이 챕터에서 생성하는 AWS 리소스의 최종 상태입니다:

리소스이름주요 설정
VPCShopEasy-VPCCIDR: 10.0.0.0/16
퍼블릭 서브넷ShopEasy-Public-A10.0.1.0/24, ap-northeast-2a, 자동 IP 할당 ON
퍼블릭 서브넷ShopEasy-Public-C10.0.2.0/24, ap-northeast-2c, 자동 IP 할당 ON
프라이빗 서브넷ShopEasy-Private-A10.0.100.0/24, ap-northeast-2a
프라이빗 서브넷ShopEasy-Private-C10.0.101.0/24, ap-northeast-2c
인터넷 게이트웨이ShopEasy-IGWShopEasy-VPC에 연결됨
NAT GatewayShopEasy-NATShopEasy-Public-A에 위치, 탄력적 IP 할당됨
라우트 테이블ShopEasy-Public-RT0.0.0.0/0 → IGW, 퍼블릭 서브넷 2개 연결
라우트 테이블ShopEasy-Private-RT0.0.0.0/0 → NAT GW, 프라이빗 서브넷 2개 연결
CLI 사용 전 준비사항

AWS CLI 명령어를 사용하려면 사전에 aws configure로 자격 증명이 설정되어 있어야 합니다. 리전은 ap-northeast-2로 설정하세요. CLI 방법은 학생들에게 웹 콘솔 실습이 끝난 후 보충 학습으로 제공하는 것을 권장합니다.

Step 1: VPC 생성

정답

  1. AWS 콘솔 상단 검색창에 "VPC" 입력 → VPC 서비스 클릭
  2. 왼쪽 메뉴에서 "VPC" 클릭
  3. 오른쪽 상단 "VPC 생성" 버튼 클릭
  4. 설정 입력:
    • 생성할 리소스: "VPC만" 선택
    • 이름 태그: ShopEasy-VPC
    • IPv4 CIDR 블록: "IPv4 CIDR 수동 입력" 선택
    • IPv4 CIDR: 10.0.0.0/16
    • IPv6 CIDR 블록: "IPv6 CIDR 블록 없음" (기본값)
    • 테넌시: "기본값" (기본값)
  5. "VPC 생성" 버튼 클릭
  6. VPC ID가 생성되었는지 확인 (예: vpc-0abc1234def56789)
학생 실수 주의

"VPC 등" 옵션을 선택하면 서브넷, IGW, NAT GW까지 한 번에 만들어져서 학습 효과가 떨어집니다. 반드시 "VPC만"을 선택하도록 안내하세요.

bash
# 1. VPC 생성
aws ec2 create-vpc \
  --cidr-block 10.0.0.0/16 \
  --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=ShopEasy-VPC}]' \
  --region ap-northeast-2

응답에서 VpcId를 확인하고, 이후 명령어에서 사용합니다.

bash
# VPC ID를 변수에 저장 (이후 명령어에서 활용)
VPC_ID=$(aws ec2 describe-vpcs \
  --filters "Name=tag:Name,Values=ShopEasy-VPC" \
  --query "Vpcs[0].VpcId" \
  --output text \
  --region ap-northeast-2)

echo "VPC ID: $VPC_ID"
bash
# DNS 호스트 이름 활성화 (EC2 인스턴스에 DNS 이름 부여)
aws ec2 modify-vpc-attribute \
  --vpc-id $VPC_ID \
  --enable-dns-hostnames '{"Value":true}' \
  --region ap-northeast-2

해설

VPC는 AWS 계정 내에서 논리적으로 격리된 가상 네트워크입니다. 10.0.0.0/16 CIDR 블록은 RFC 1918 프라이빗 IP 주소 범위에 해당하며, 65,536개의 IP 주소를 제공합니다. 이는 여러 서브넷을 생성하고 리소스를 배치하기에 충분한 크기입니다.

VPC 생성 시 자동으로 기본 라우트 테이블, 기본 NACL, 기본 보안 그룹이 함께 생성됩니다. 하지만 우리는 명시적으로 라우트 테이블을 생성하여 사용할 것입니다.

Step 2: 퍼블릭 서브넷 2개 생성

정답

  1. VPC 대시보드 왼쪽 메뉴에서 "서브넷" 클릭
  2. "서브넷 생성" 버튼 클릭
  3. VPC 선택: ShopEasy-VPC
  4. 첫 번째 서브넷 설정:
    • 서브넷 이름: ShopEasy-Public-A
    • 가용 영역: ap-northeast-2a
    • IPv4 서브넷 CIDR 블록: 10.0.1.0/24
  5. "새 서브넷 추가" 버튼 클릭
  6. 두 번째 서브넷 설정:
    • 서브넷 이름: ShopEasy-Public-C
    • 가용 영역: ap-northeast-2c
    • IPv4 서브넷 CIDR 블록: 10.0.2.0/24
  7. "서브넷 생성" 버튼 클릭

퍼블릭 IP 자동 할당 활성화

  1. 서브넷 목록에서 ShopEasy-Public-A 체크박스 선택
  2. 상단 "작업" 드롭다운 → "서브넷 설정 편집"
  3. "퍼블릭 IPv4 주소 자동 할당 활성화" 체크
  4. "저장" 클릭
  5. ShopEasy-Public-C도 동일하게 반복
bash
# 퍼블릭 서브넷 A 생성
SUBNET_PUB_A=$(aws ec2 create-subnet \
  --vpc-id $VPC_ID \
  --cidr-block 10.0.1.0/24 \
  --availability-zone ap-northeast-2a \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=ShopEasy-Public-A}]' \
  --query 'Subnet.SubnetId' \
  --output text \
  --region ap-northeast-2)

echo "Public Subnet A: $SUBNET_PUB_A"
bash
# 퍼블릭 서브넷 C 생성
SUBNET_PUB_C=$(aws ec2 create-subnet \
  --vpc-id $VPC_ID \
  --cidr-block 10.0.2.0/24 \
  --availability-zone ap-northeast-2c \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=ShopEasy-Public-C}]' \
  --query 'Subnet.SubnetId' \
  --output text \
  --region ap-northeast-2)

echo "Public Subnet C: $SUBNET_PUB_C"
bash
# 퍼블릭 IP 자동 할당 활성화
aws ec2 modify-subnet-attribute \
  --subnet-id $SUBNET_PUB_A \
  --map-public-ip-on-launch \
  --region ap-northeast-2

aws ec2 modify-subnet-attribute \
  --subnet-id $SUBNET_PUB_C \
  --map-public-ip-on-launch \
  --region ap-northeast-2

해설

서브넷을 두 개의 가용 영역(AZ-a, AZ-c)에 분산 배치하는 이유는 고가용성입니다. AWS의 가용 영역은 물리적으로 분리된 데이터센터 그룹이므로, 한 AZ에 장애가 발생해도 다른 AZ에서 서비스를 계속할 수 있습니다.

"퍼블릭 IPv4 주소 자동 할당"을 활성화하면, 이 서브넷에 생성되는 EC2 인스턴스가 자동으로 공인 IP 주소를 받습니다. 이 설정을 하지 않으면 인스턴스에 수동으로 탄력적 IP(EIP)를 할당해야 합니다.

학생 실수 포인트
  • 퍼블릭 IP 자동 할당을 잊는 경우가 많습니다. Chapter 02에서 EC2 생성 시 공인 IP가 없으면 접속이 불가합니다.
  • CIDR 블록이 VPC 범위(10.0.0.0/16)를 벗어나면 오류가 발생합니다.
  • 같은 AZ에 두 서브넷을 모두 만드는 실수가 있습니다. AZ를 꼭 확인시키세요.

Step 3: 프라이빗 서브넷 2개 생성

정답

  1. VPC 대시보드 → "서브넷""서브넷 생성"
  2. VPC 선택: ShopEasy-VPC
  3. 첫 번째 서브넷 설정:
    • 서브넷 이름: ShopEasy-Private-A
    • 가용 영역: ap-northeast-2a
    • IPv4 서브넷 CIDR 블록: 10.0.100.0/24
  4. "새 서브넷 추가" 클릭
  5. 두 번째 서브넷 설정:
    • 서브넷 이름: ShopEasy-Private-C
    • 가용 영역: ap-northeast-2c
    • IPv4 서브넷 CIDR 블록: 10.0.101.0/24
  6. "서브넷 생성" 클릭
프라이빗 서브넷은 자동 IP 할당 불필요

프라이빗 서브넷의 리소스는 공인 IP가 필요 없으므로, "퍼블릭 IPv4 주소 자동 할당"을 활성화하지 않습니다. 기본값(비활성화)을 그대로 두세요.

bash
# 프라이빗 서브넷 A 생성
SUBNET_PRIV_A=$(aws ec2 create-subnet \
  --vpc-id $VPC_ID \
  --cidr-block 10.0.100.0/24 \
  --availability-zone ap-northeast-2a \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=ShopEasy-Private-A}]' \
  --query 'Subnet.SubnetId' \
  --output text \
  --region ap-northeast-2)

echo "Private Subnet A: $SUBNET_PRIV_A"
bash
# 프라이빗 서브넷 C 생성
SUBNET_PRIV_C=$(aws ec2 create-subnet \
  --vpc-id $VPC_ID \
  --cidr-block 10.0.101.0/24 \
  --availability-zone ap-northeast-2c \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=ShopEasy-Private-C}]' \
  --query 'Subnet.SubnetId' \
  --output text \
  --region ap-northeast-2)

echo "Private Subnet C: $SUBNET_PRIV_C"

해설

프라이빗 서브넷의 CIDR을 100번대(10.0.100.0/24, 10.0.101.0/24)로 설정한 것은 네이밍 컨벤션입니다. 퍼블릭은 1~99번대, 프라이빗은 100번대 이상을 사용하면 IP 주소만 보고도 네트워크 유형을 즉시 파악할 수 있어 운영 및 디버깅이 편리합니다.

RDS는 DB 서브넷 그룹 생성 시 최소 2개의 AZ에 걸친 서브넷을 요구합니다. Chapter 03에서 RDS를 생성할 때 이 두 프라이빗 서브넷을 사용합니다.

Step 4: 인터넷 게이트웨이 생성 및 VPC에 연결

정답

4-1. 인터넷 게이트웨이 생성

  1. VPC 대시보드 왼쪽 메뉴 → "인터넷 게이트웨이"
  2. "인터넷 게이트웨이 생성" 버튼 클릭
  3. 이름 태그: ShopEasy-IGW
  4. "인터넷 게이트웨이 생성" 클릭

4-2. VPC에 연결

  1. 생성 완료 후 상단에 표시되는 초록색 배너의 "VPC에 연결" 링크 클릭
    (또는 IGW 선택 → 작업 → "VPC에 연결")
  2. 사용 가능한 VPC: ShopEasy-VPC 선택
  3. "인터넷 게이트웨이 연결" 클릭
  4. 상태가 "Attached"로 변경되었는지 확인
bash
# 인터넷 게이트웨이 생성
IGW_ID=$(aws ec2 create-internet-gateway \
  --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=ShopEasy-IGW}]' \
  --query 'InternetGateway.InternetGatewayId' \
  --output text \
  --region ap-northeast-2)

echo "IGW ID: $IGW_ID"
bash
# VPC에 인터넷 게이트웨이 연결
aws ec2 attach-internet-gateway \
  --internet-gateway-id $IGW_ID \
  --vpc-id $VPC_ID \
  --region ap-northeast-2

echo "IGW $IGW_ID attached to VPC $VPC_ID"

해설

인터넷 게이트웨이는 VPC당 1개만 연결할 수 있습니다. 이미 다른 VPC에 연결된 IGW를 사용하려 하면 오류가 발생합니다.

IGW는 네트워크 주소 변환(NAT)을 수행합니다: VPC 내부의 프라이빗 IP를 퍼블릭 IP로 변환하여 인터넷과 통신합니다. 이 과정은 자동으로 처리됩니다.

IGW를 생성하고 VPC에 연결했다고 해서 바로 인터넷이 되는 것은 아닙니다. 라우트 테이블에 IGW로의 경로를 추가해야 비로소 해당 서브넷이 인터넷에 연결됩니다. (Step 6에서 수행)

Step 5: NAT Gateway 생성

정답

  1. VPC 대시보드 왼쪽 메뉴 → "NAT 게이트웨이"
  2. "NAT 게이트웨이 생성" 버튼 클릭
  3. 설정 입력:
    • 이름: ShopEasy-NAT
    • 서브넷: ShopEasy-Public-A (반드시 퍼블릭 서브넷!)
    • 연결 유형: 퍼블릭 (기본값)
    • 탄력적 IP 할당 ID: "탄력적 IP 할당" 버튼 클릭 (새 EIP 자동 생성)
  4. "NAT 게이트웨이 생성" 클릭
  5. 상태가 "Pending"에서 "Available"로 변경될 때까지 대기 (약 2~3분)
반드시 확인!

NAT Gateway의 상태가 "Available"이 된 후에 Step 7의 프라이빗 라우트 테이블을 설정해야 합니다. "Pending" 상태에서도 라우트 추가는 가능하지만, 트래픽이 정상적으로 흐르지 않습니다.

bash
# 탄력적 IP 할당
EIP_ALLOC=$(aws ec2 allocate-address \
  --domain vpc \
  --tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=Name,Value=ShopEasy-NAT-EIP}]' \
  --query 'AllocationId' \
  --output text \
  --region ap-northeast-2)

echo "Elastic IP Allocation ID: $EIP_ALLOC"
bash
# NAT Gateway 생성 (퍼블릭 서브넷 A에 배치)
NAT_GW_ID=$(aws ec2 create-nat-gateway \
  --subnet-id $SUBNET_PUB_A \
  --allocation-id $EIP_ALLOC \
  --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=ShopEasy-NAT}]' \
  --query 'NatGateway.NatGatewayId' \
  --output text \
  --region ap-northeast-2)

echo "NAT Gateway ID: $NAT_GW_ID"
bash
# NAT Gateway가 Available 상태가 될 때까지 대기
aws ec2 wait nat-gateway-available \
  --nat-gateway-ids $NAT_GW_ID \
  --region ap-northeast-2

echo "NAT Gateway is now available!"

해설

NAT(Network Address Translation) Gateway는 프라이빗 서브넷의 리소스가 인터넷에 아웃바운드 연결을 할 수 있게 해줍니다. 하지만 인터넷에서 NAT Gateway를 통해 프라이빗 서브넷으로 인바운드 연결을 시작하는 것은 불가능합니다.

NAT Gateway를 퍼블릭 서브넷에 배치하는 이유: NAT Gateway 자체가 인터넷과 통신해야 프라이빗 서브넷의 트래픽을 중계할 수 있기 때문입니다. 퍼블릭 서브넷은 IGW 경로가 있으므로 NAT Gateway가 인터넷에 접근할 수 있습니다.

비용 관련 강사 안내

학생들에게 반드시 NAT Gateway의 비용을 안내하세요:

  • 시간당 $0.059 (서울 리전 기준)
  • 처리 데이터 GB당 $0.059
  • 월 상시 가동 시 약 $43 (데이터 전송 제외)
  • 탄력적 IP는 NAT GW에 연결되어 있는 동안 무료, NAT GW 삭제 후 미해제 시 과금

실습 종료 후 NAT Gateway 삭제 → 탄력적 IP 해제 순서로 정리해야 합니다.

Step 6: 퍼블릭 라우트 테이블 생성 및 설정

정답

6-1. 라우트 테이블 생성

  1. VPC 대시보드 왼쪽 메뉴 → "라우트 테이블"
  2. "라우트 테이블 생성" 버튼 클릭
  3. 설정:
    • 이름: ShopEasy-Public-RT
    • VPC: ShopEasy-VPC
  4. "라우트 테이블 생성" 클릭

6-2. 인터넷 라우트 추가

  1. 생성된 ShopEasy-Public-RT 선택
  2. 하단의 "라우트" 탭 클릭
  3. "라우트 편집" 버튼 클릭
  4. "라우트 추가" 버튼 클릭
  5. 설정:
    • 대상: 0.0.0.0/0
    • 대상: "인터넷 게이트웨이" 선택 → ShopEasy-IGW
  6. "변경 사항 저장" 클릭

6-3. 퍼블릭 서브넷 연결

  1. ShopEasy-Public-RT 선택 상태에서 "서브넷 연결" 탭 클릭
  2. "서브넷 연결 편집" 클릭
  3. ShopEasy-Public-AShopEasy-Public-C 체크
  4. "연결 저장" 클릭
bash
# 퍼블릭 라우트 테이블 생성
PUB_RT_ID=$(aws ec2 create-route-table \
  --vpc-id $VPC_ID \
  --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=ShopEasy-Public-RT}]' \
  --query 'RouteTable.RouteTableId' \
  --output text \
  --region ap-northeast-2)

echo "Public Route Table ID: $PUB_RT_ID"
bash
# 인터넷 게이트웨이로의 라우트 추가
aws ec2 create-route \
  --route-table-id $PUB_RT_ID \
  --destination-cidr-block 0.0.0.0/0 \
  --gateway-id $IGW_ID \
  --region ap-northeast-2
bash
# 퍼블릭 서브넷 2개를 라우트 테이블에 연결
aws ec2 associate-route-table \
  --route-table-id $PUB_RT_ID \
  --subnet-id $SUBNET_PUB_A \
  --region ap-northeast-2

aws ec2 associate-route-table \
  --route-table-id $PUB_RT_ID \
  --subnet-id $SUBNET_PUB_C \
  --region ap-northeast-2

echo "Public subnets associated with Public RT"

해설

라우트 테이블은 서브넷에서 나가는 트래픽의 경로를 결정합니다. VPC 생성 시 자동으로 만들어진 기본(Main) 라우트 테이블에는 10.0.0.0/16 → local 라우트만 있어 VPC 내부 통신만 가능합니다.

우리가 추가한 0.0.0.0/0 → IGW 라우트는 "VPC 내부가 아닌 모든 목적지로의 트래픽은 인터넷 게이트웨이로 보내라"는 의미입니다. 이 라우트가 연결된 서브넷이 바로 "퍼블릭 서브넷"이 됩니다.

라우트 매칭 규칙 (가장 긴 접두사 매칭)

트래픽의 목적지가 10.0.100.5라면:

  • 10.0.0.0/16 (local) - 매칭됨! (/16 = 16비트 일치)
  • 0.0.0.0/0 (IGW) - 매칭됨! (/0 = 0비트 일치)

더 구체적인(긴 접두사) 규칙이 우선하므로 /16 > /0, 따라서 local 라우트가 적용됩니다. VPC 내부 트래픽은 IGW를 거치지 않습니다.

Step 7: 프라이빗 라우트 테이블 생성 및 설정

정답

7-1. 라우트 테이블 생성

  1. VPC 대시보드 → "라우트 테이블""라우트 테이블 생성"
  2. 설정:
    • 이름: ShopEasy-Private-RT
    • VPC: ShopEasy-VPC
  3. "라우트 테이블 생성" 클릭

7-2. NAT Gateway 라우트 추가

  1. 생성된 ShopEasy-Private-RT 선택
  2. 하단의 "라우트" 탭 → "라우트 편집"
  3. "라우트 추가" 클릭
  4. 설정:
    • 대상: 0.0.0.0/0
    • 대상: "NAT 게이트웨이" 선택 → ShopEasy-NAT
  5. "변경 사항 저장" 클릭

7-3. 프라이빗 서브넷 연결

  1. ShopEasy-Private-RT 선택 → "서브넷 연결"
  2. "서브넷 연결 편집" 클릭
  3. ShopEasy-Private-AShopEasy-Private-C 체크
  4. "연결 저장" 클릭
bash
# 프라이빗 라우트 테이블 생성
PRIV_RT_ID=$(aws ec2 create-route-table \
  --vpc-id $VPC_ID \
  --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=ShopEasy-Private-RT}]' \
  --query 'RouteTable.RouteTableId' \
  --output text \
  --region ap-northeast-2)

echo "Private Route Table ID: $PRIV_RT_ID"
bash
# NAT Gateway로의 라우트 추가
aws ec2 create-route \
  --route-table-id $PRIV_RT_ID \
  --destination-cidr-block 0.0.0.0/0 \
  --nat-gateway-id $NAT_GW_ID \
  --region ap-northeast-2
bash
# 프라이빗 서브넷 2개를 라우트 테이블에 연결
aws ec2 associate-route-table \
  --route-table-id $PRIV_RT_ID \
  --subnet-id $SUBNET_PRIV_A \
  --region ap-northeast-2

aws ec2 associate-route-table \
  --route-table-id $PRIV_RT_ID \
  --subnet-id $SUBNET_PRIV_C \
  --region ap-northeast-2

echo "Private subnets associated with Private RT"

해설

프라이빗 라우트 테이블의 0.0.0.0/0 → NAT Gateway 라우트는 프라이빗 서브넷의 리소스가 인터넷으로 나가는 것만 허용합니다. NAT Gateway가 출발지 IP를 자신의 탄력적 IP로 변환(SNAT)하므로, 외부에서는 요청의 원래 출발지(프라이빗 IP)를 알 수 없습니다.

이 설정이 완료되면, 프라이빗 서브넷의 RDS가 OS 패치나 소프트웨어 업데이트를 인터넷에서 다운로드할 수 있습니다. 하지만 인터넷에서 프라이빗 서브넷의 리소스에 직접 접속하는 것은 여전히 불가능합니다.

검증 스크립트

학생들의 실습 결과를 한 번에 확인할 수 있는 스크립트입니다:

전체 리소스 확인 스크립트

bash
#!/bin/bash
# ShopEasy VPC 네트워크 검증 스크립트
REGION="ap-northeast-2"
echo "========================================="
echo "  ShopEasy VPC 네트워크 검증"
echo "========================================="

# 1. VPC 확인
echo ""
echo "[1] VPC 확인"
VPC_ID=$(aws ec2 describe-vpcs \
  --filters "Name=tag:Name,Values=ShopEasy-VPC" \
  --query "Vpcs[0].VpcId" \
  --output text --region $REGION)

if [ "$VPC_ID" = "None" ] || [ -z "$VPC_ID" ]; then
  echo "  [FAIL] ShopEasy-VPC가 존재하지 않습니다!"
  exit 1
else
  CIDR=$(aws ec2 describe-vpcs --vpc-ids $VPC_ID \
    --query "Vpcs[0].CidrBlock" --output text --region $REGION)
  echo "  [OK] VPC: $VPC_ID (CIDR: $CIDR)"
fi

# 2. 서브넷 확인
echo ""
echo "[2] 서브넷 확인"
for SUBNET_NAME in ShopEasy-Public-A ShopEasy-Public-C ShopEasy-Private-A ShopEasy-Private-C; do
  SUBNET_ID=$(aws ec2 describe-subnets \
    --filters "Name=tag:Name,Values=$SUBNET_NAME" "Name=vpc-id,Values=$VPC_ID" \
    --query "Subnets[0].SubnetId" --output text --region $REGION)
  SUBNET_CIDR=$(aws ec2 describe-subnets --subnet-ids $SUBNET_ID \
    --query "Subnets[0].CidrBlock" --output text --region $REGION 2>/dev/null)
  SUBNET_AZ=$(aws ec2 describe-subnets --subnet-ids $SUBNET_ID \
    --query "Subnets[0].AvailabilityZone" --output text --region $REGION 2>/dev/null)
  if [ "$SUBNET_ID" = "None" ] || [ -z "$SUBNET_ID" ]; then
    echo "  [FAIL] $SUBNET_NAME 없음"
  else
    echo "  [OK] $SUBNET_NAME: $SUBNET_ID ($SUBNET_CIDR, $SUBNET_AZ)"
  fi
done

# 3. 퍼블릭 서브넷 자동 IP 할당 확인
echo ""
echo "[3] 퍼블릭 IP 자동 할당 확인"
for SUBNET_NAME in ShopEasy-Public-A ShopEasy-Public-C; do
  SUBNET_ID=$(aws ec2 describe-subnets \
    --filters "Name=tag:Name,Values=$SUBNET_NAME" "Name=vpc-id,Values=$VPC_ID" \
    --query "Subnets[0].SubnetId" --output text --region $REGION)
  AUTO_IP=$(aws ec2 describe-subnets --subnet-ids $SUBNET_ID \
    --query "Subnets[0].MapPublicIpOnLaunch" --output text --region $REGION 2>/dev/null)
  if [ "$AUTO_IP" = "True" ]; then
    echo "  [OK] $SUBNET_NAME: 자동 IP 할당 활성화"
  else
    echo "  [WARN] $SUBNET_NAME: 자동 IP 할당 비활성화!"
  fi
done

# 4. 인터넷 게이트웨이 확인
echo ""
echo "[4] 인터넷 게이트웨이 확인"
IGW_ID=$(aws ec2 describe-internet-gateways \
  --filters "Name=tag:Name,Values=ShopEasy-IGW" "Name=attachment.vpc-id,Values=$VPC_ID" \
  --query "InternetGateways[0].InternetGatewayId" --output text --region $REGION)
if [ "$IGW_ID" = "None" ] || [ -z "$IGW_ID" ]; then
  echo "  [FAIL] ShopEasy-IGW가 VPC에 연결되지 않았습니다!"
else
  echo "  [OK] IGW: $IGW_ID (VPC에 연결됨)"
fi

# 5. NAT Gateway 확인
echo ""
echo "[5] NAT Gateway 확인"
NAT_ID=$(aws ec2 describe-nat-gateways \
  --filter "Name=tag:Name,Values=ShopEasy-NAT" "Name=state,Values=available" \
  --query "NatGateways[0].NatGatewayId" --output text --region $REGION)
if [ "$NAT_ID" = "None" ] || [ -z "$NAT_ID" ]; then
  echo "  [FAIL] ShopEasy-NAT가 Available 상태가 아닙니다!"
else
  NAT_SUBNET=$(aws ec2 describe-nat-gateways --nat-gateway-ids $NAT_ID \
    --query "NatGateways[0].SubnetId" --output text --region $REGION)
  echo "  [OK] NAT GW: $NAT_ID (서브넷: $NAT_SUBNET)"
fi

# 6. 라우트 테이블 확인
echo ""
echo "[6] 라우트 테이블 확인"
for RT_NAME in ShopEasy-Public-RT ShopEasy-Private-RT; do
  RT_ID=$(aws ec2 describe-route-tables \
    --filters "Name=tag:Name,Values=$RT_NAME" "Name=vpc-id,Values=$VPC_ID" \
    --query "RouteTables[0].RouteTableId" --output text --region $REGION)
  if [ "$RT_ID" = "None" ] || [ -z "$RT_ID" ]; then
    echo "  [FAIL] $RT_NAME 없음"
  else
    ROUTES=$(aws ec2 describe-route-tables --route-table-ids $RT_ID \
      --query "RouteTables[0].Routes[?DestinationCidrBlock=='0.0.0.0/0'].{Target:GatewayId||NatGatewayId}" \
      --output text --region $REGION)
    ASSOC_COUNT=$(aws ec2 describe-route-tables --route-table-ids $RT_ID \
      --query "length(RouteTables[0].Associations[?!Main])" --output text --region $REGION)
    echo "  [OK] $RT_NAME: $RT_ID (0.0.0.0/0 -> $ROUTES, 서브넷 ${ASSOC_COUNT}개 연결)"
  fi
done

echo ""
echo "========================================="
echo "  검증 완료!"
echo "========================================="

트러블슈팅

자주 발생하는 문제 & 해결 방법

VPC 생성 시 "VPC limit exceeded" 오류

AWS 계정에는 리전당 VPC 생성 제한이 있습니다 (기본 5개). 해결: 사용하지 않는 VPC를 삭제하거나, AWS Support에 한도 증가를 요청합니다. 기본 VPC를 삭제하지 않도록 주의하세요.

서브넷 CIDR 블록 충돌 오류

같은 VPC 내에서 서브넷 CIDR 블록이 겹치면 생성할 수 없습니다. 해결: 이미 생성된 서브넷의 CIDR 블록을 확인하고 겹치지 않는 범위를 사용합니다. 잘못 만든 서브넷은 삭제 후 다시 생성하세요.

인터넷 게이트웨이 "already attached" 오류

IGW가 이미 다른 VPC에 연결되어 있거나, 해당 VPC에 다른 IGW가 연결된 경우입니다. 해결: VPC당 IGW는 1개만 가능합니다. 기존 연결을 해제(Detach)하거나 새 IGW를 생성하세요.

NAT Gateway 생성 시 "Elastic IP address limit exceeded"

계정당 탄력적 IP 수가 제한되어 있습니다 (기본 5개). 해결: 사용하지 않는 탄력적 IP를 해제(Release)합니다. EC2 → 네트워크 & 보안 → 탄력적 IP에서 확인할 수 있습니다.

NAT Gateway 상태가 계속 "Pending"

NAT Gateway 생성에는 보통 2~3분이 소요됩니다. 5분 이상 Pending이면 문제가 있을 수 있습니다. 해결: NAT Gateway를 삭제하고 다시 생성합니다. 서브넷이 퍼블릭 서브넷인지, IGW가 VPC에 연결되어 있는지 확인하세요.

라우트 테이블에 NAT Gateway가 타겟으로 표시되지 않음

NAT Gateway가 아직 "Available" 상태가 아니거나, 다른 VPC의 NAT Gateway일 수 있습니다. 해결: NAT Gateway가 같은 VPC에 있는지, 상태가 "Available"인지 확인합니다. 올바른 NAT Gateway를 선택하세요.

서브넷 연결 시 "이미 다른 라우트 테이블에 연결됨" 메시지

모든 서브넷은 항상 하나의 라우트 테이블에 연결되어 있습니다. 명시적으로 연결하지 않으면 VPC의 기본(Main) 라우트 테이블에 암시적으로 연결됩니다. 해결: 이것은 정상입니다. 새 라우트 테이블에 연결하면 기존 연결이 자동으로 해제됩니다.

리전이 서울(ap-northeast-2)이 아닌 경우

실습을 다른 리전에서 진행하면 이후 챕터와의 연결이 끊어집니다. 해결: AWS 콘솔 오른쪽 상단의 리전 선택기에서 "아시아 태평양 (서울)"을 선택합니다. 다른 리전에 만든 리소스는 삭제하세요.

강의 팁

진행 순서 권장
  1. (10분) 건물 비유로 VPC 개념 설명 - 화이트보드에 건물 그림을 그리며 설명하면 효과적
  2. (5분) CIDR 표기법 간단 설명 - /16, /24 의 IP 개수만 이해하면 충분
  3. (5분) 아키텍처 다이어그램 설명 - 학생용 가이드의 다이어그램 활용
  4. (20분) 실습 진행 - 학생들이 직접 따라하도록 순회 지도
  5. (5분) 체크리스트로 결과 확인 - 빠진 설정이 없는지 점검
학생 질문 대비
  • "기본 VPC랑 뭐가 다른가요?" - 기본 VPC는 AWS가 자동 생성한 것으로, 실습에는 우리가 직접 만든 VPC를 사용해야 구조를 이해할 수 있습니다.
  • "VPC 등으로 한 번에 만들면 안 되나요?" - 가능하지만, 하나씩 만들어야 각 리소스의 역할과 관계를 이해할 수 있습니다.
  • "NAT Gateway 없으면 어떻게 되나요?" - 프라이빗 서브넷의 리소스가 인터넷에 접근할 수 없습니다. 패키지 업데이트 등이 불가합니다.
  • "서브넷이 왜 2개씩 필요한가요?" - RDS, ALB 등이 최소 2개 AZ를 요구합니다. 한 AZ 장애 시 서비스 연속성을 위함입니다.
주의할 점
  • 학생들이 "VPC 등" 옵션으로 한 번에 만들지 않도록 미리 안내
  • NAT Gateway 생성에 시간이 걸리므로, 대기 시간 동안 개념 복습 진행
  • 퍼블릭 서브넷의 자동 IP 할당을 빠뜨리지 않도록 강조
  • 라우트 테이블에서 퍼블릭 RT의 타겟이 IGW인지, 프라이빗 RT의 타겟이 NAT GW인지 혼동하지 않도록 주의