Subnet
서브넷
IP 네트워크의 논리적 분할. CIDR로 표기. VPC 구성 요소.
서브넷
IP 네트워크의 논리적 분할. CIDR로 표기. VPC 구성 요소.
Subnet(서브넷)은 하나의 큰 IP 네트워크를 더 작은 논리적 네트워크 세그먼트로 분할하는 기술입니다. 예를 들어, 회사에서 10.0.0.0/16 네트워크를 할당받았다면, 이를 10.0.1.0/24(개발팀), 10.0.2.0/24(운영팀), 10.0.3.0/24(DB서버)처럼 분리하여 네트워크 관리 효율성과 보안성을 높일 수 있습니다.
서브넷은 CIDR(Classless Inter-Domain Routing) 표기법으로 표현합니다. 10.0.1.0/24에서 /24는 서브넷 마스크를 의미하며, 앞의 24비트가 네트워크 주소, 나머지 8비트(2^8 = 256개, 실제 사용 가능 254개)가 호스트 주소입니다. /24는 255.255.255.0과 동일하며, /16은 65,536개, /28은 16개의 IP를 할당받습니다.
클라우드 환경에서 서브넷은 VPC(Virtual Private Cloud)의 핵심 구성 요소입니다. AWS, GCP, Azure 모두 Public Subnet(인터넷 직접 연결)과 Private Subnet(내부 통신 전용)을 구분합니다. 웹 서버는 Public Subnet에, 데이터베이스는 Private Subnet에 배치하여 보안을 강화합니다. Private Subnet의 아웃바운드 인터넷 접근은 NAT Gateway를 통해 처리합니다.
고가용성(HA) 아키텍처에서는 최소 2개 이상의 가용영역(AZ)에 서브넷을 분산 배치합니다. 예를 들어, ap-northeast-2a와 ap-northeast-2c에 각각 Public/Private Subnet을 만들어 총 4개의 서브넷을 구성합니다. 이렇게 하면 한 AZ에 장애가 발생해도 서비스가 중단되지 않습니다. CIDR 블록은 향후 확장을 고려해 /24보다 여유 있는 /20 ~ /22 크기로 설계하는 것이 권장됩니다.
# AWS VPC와 서브넷 구성 (Terraform)
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = { Name = "production-vpc" }
}
# Public Subnet (AZ-a) - 웹 서버, ALB 배치
resource "aws_subnet" "public_a" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24" # 254개 IP
availability_zone = "ap-northeast-2a"
map_public_ip_on_launch = true
tags = { Name = "public-subnet-a", Type = "public" }
}
# Public Subnet (AZ-c) - HA 구성용
resource "aws_subnet" "public_c" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.2.0/24"
availability_zone = "ap-northeast-2c"
map_public_ip_on_launch = true
tags = { Name = "public-subnet-c", Type = "public" }
}
# Private Subnet (AZ-a) - DB, 애플리케이션 서버
resource "aws_subnet" "private_a" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.10.0/24"
availability_zone = "ap-northeast-2a"
tags = { Name = "private-subnet-a", Type = "private" }
}
# Private Subnet (AZ-c) - HA 구성용
resource "aws_subnet" "private_c" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.11.0/24"
availability_zone = "ap-northeast-2c"
tags = { Name = "private-subnet-c", Type = "private" }
}
# Internet Gateway - Public Subnet용
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = { Name = "main-igw" }
}
# NAT Gateway - Private Subnet 아웃바운드용
resource "aws_eip" "nat" {
domain = "vpc"
}
resource "aws_nat_gateway" "main" {
allocation_id = aws_eip.nat.id
subnet_id = aws_subnet.public_a.id # Public Subnet에 배치
tags = { Name = "main-nat-gateway" }
}
import boto3
import ipaddress
# CIDR 계산 유틸리티
def calculate_cidr(cidr_block):
"""CIDR 블록 정보 계산"""
network = ipaddress.ip_network(cidr_block, strict=False)
print(f"네트워크 주소: {network.network_address}")
print(f"브로드캐스트: {network.broadcast_address}")
print(f"서브넷 마스크: {network.netmask}")
print(f"총 IP 수: {network.num_addresses}")
print(f"사용 가능 IP: {network.num_addresses - 5}") # AWS는 5개 예약
print(f"IP 범위: {list(network.hosts())[0]} ~ {list(network.hosts())[-1]}")
return network
# 예제: /24 블록 분석
calculate_cidr("10.0.1.0/24")
# 네트워크 주소: 10.0.1.0
# 총 IP 수: 256
# 사용 가능 IP: 251 (AWS는 5개 예약: .0, .1, .2, .3, .255)
# boto3로 VPC 서브넷 생성
ec2 = boto3.client('ec2', region_name='ap-northeast-2')
# VPC 생성
vpc_response = ec2.create_vpc(
CidrBlock='10.0.0.0/16',
TagSpecifications=[{
'ResourceType': 'vpc',
'Tags': [{'Key': 'Name', 'Value': 'production-vpc'}]
}]
)
vpc_id = vpc_response['Vpc']['VpcId']
# Public Subnet 생성
public_subnet = ec2.create_subnet(
VpcId=vpc_id,
CidrBlock='10.0.1.0/24',
AvailabilityZone='ap-northeast-2a',
TagSpecifications=[{
'ResourceType': 'subnet',
'Tags': [
{'Key': 'Name', 'Value': 'public-subnet-a'},
{'Key': 'Type', 'Value': 'public'}
]
}]
)
# Private Subnet 생성
private_subnet = ec2.create_subnet(
VpcId=vpc_id,
CidrBlock='10.0.10.0/24',
AvailabilityZone='ap-northeast-2a',
TagSpecifications=[{
'ResourceType': 'subnet',
'Tags': [
{'Key': 'Name', 'Value': 'private-subnet-a'},
{'Key': 'Type', 'Value': 'private'}
]
}]
)
print(f"Public Subnet ID: {public_subnet['Subnet']['SubnetId']}")
print(f"Private Subnet ID: {private_subnet['Subnet']['SubnetId']}")
# AWS CLI로 VPC 서브넷 관리
# VPC 생성
aws ec2 create-vpc \
--cidr-block 10.0.0.0/16 \
--tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=production-vpc}]'
# VPC ID 확인
VPC_ID=$(aws ec2 describe-vpcs \
--filters "Name=tag:Name,Values=production-vpc" \
--query 'Vpcs[0].VpcId' --output text)
# Public Subnet 생성 (AZ-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=public-subnet-a},{Key=Type,Value=public}]'
# Private Subnet 생성 (AZ-a)
aws ec2 create-subnet \
--vpc-id $VPC_ID \
--cidr-block 10.0.10.0/24 \
--availability-zone ap-northeast-2a \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=private-subnet-a},{Key=Type,Value=private}]'
# 서브넷 목록 조회
aws ec2 describe-subnets \
--filters "Name=vpc-id,Values=$VPC_ID" \
--query 'Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone,Public:MapPublicIpOnLaunch}' \
--output table
# Internet Gateway 생성 및 연결
IGW_ID=$(aws ec2 create-internet-gateway \
--query 'InternetGateway.InternetGatewayId' --output text)
aws ec2 attach-internet-gateway --vpc-id $VPC_ID --internet-gateway-id $IGW_ID
# CIDR 계산 (Linux ipcalc)
ipcalc 10.0.1.0/24
# Network: 10.0.1.0/24
# Netmask: 255.255.255.0
# HostMin: 10.0.1.1
# HostMax: 10.0.1.254
# Hosts/Net: 254
# 서브넷 내 사용 가능 IP 수 확인
aws ec2 describe-subnets \
--subnet-ids subnet-xxxxx \
--query 'Subnets[0].AvailableIpAddressCount'
"프로덕션 VPC는 10.0.0.0/16으로 잡고, Public Subnet은 /24로 2개 AZ에 배치합시다. Private Subnet은 RDS Multi-AZ 때문에 최소 2개 필요하고, EKS 노드용으로 /20 크기 서브넷을 별도로 만들어야 Pod IP가 부족하지 않습니다. 총 6개 서브넷 구성이 적절해 보입니다."
"DB 서버가 Public Subnet에 있으면 안 됩니다. Private Subnet으로 이동하고, 웹 서버에서만 3306 포트 접근 가능하도록 Security Group을 설정해야 합니다. 외부 API 호출이 필요하면 NAT Gateway를 통해 나가도록 라우팅 테이블을 수정하겠습니다."
"EC2에서 인터넷 연결이 안 된다고요? 먼저 서브넷이 Public인지 Private인지 확인해주세요. Private Subnet이라면 NAT Gateway가 있는지, 라우트 테이블에 0.0.0.0/0 → NAT 경로가 있는지 체크해야 합니다. Public이면 IGW 연결과 퍼블릭 IP 할당 여부를 확인하세요."
/28(11개 IP)로 만들었다가 서비스 확장 시 IP가 부족합니다. 서브넷 CIDR은 나중에 변경 불가하므로 처음부터 /24 이상으로 여유 있게 잡으세요. EKS 사용 시 /20 권장입니다.
ap-northeast-2a에만 서브넷을 만들면, 해당 AZ 장애 시 전체 서비스가 중단됩니다. RDS Multi-AZ, ALB는 최소 2개 AZ의 서브넷이 필수입니다. 항상 짝수 개로 구성하세요.
데이터베이스, 백엔드 서버를 Public Subnet에 두면 외부 공격에 노출됩니다. 인터넷 직접 연결이 필요한 ALB, Bastion만 Public에 두고, 나머지는 반드시 Private Subnet에 배치하세요.
VPC /16 → Public /24 x 2 AZ + Private /24 x 2 AZ 구성이 표준입니다. CIDR 블록은 겹치지 않게 계획하고(VPC Peering 대비), 용도별로 태그를 명확히 붙이세요. 서브넷당 AWS 예약 IP 5개를 감안한 용량 산정이 필요합니다.