안동민 개발노트 아이콘

안동민 개발노트

4장 : IP 주소와 서브넷

서브넷과 CIDR

클래스 기반 주소 체계의 가장 큰 문제는 유연성이 없다는 것이었습니다. 호스트가 300대 필요한 조직에 클래스 C(254대)를 주면 부족하고, 클래스 B(65,534대)를 주면 65,000개 이상의 주소가 낭비됩니다.

이 문제를 해결하기 위해 등장한 것이 서브넷(Subnet)CIDR(Classless Inter-Domain Routing)입니다.


서브넷 마스크의 역할

서브넷 마스크(Subnet Mask)는 IP 주소에서 어디까지가 네트워크부이고 어디서부터가 호스트부인지를 알려주는 값입니다.

IP 주소와 서브넷 마스크를 비트 단위로 AND 연산하면 네트워크 주소가 나옵니다. 반대로 마스크에서 0으로 남은 비트가 호스트부이며, 이 범위 안에서 호스트 주소와 브로드캐스트 주소가 결정됩니다.


CIDR 표기법

CIDR은 클래스에 얽매이지 않고, 네트워크부의 비트 수를 자유롭게 지정하는 방식입니다.

192.168.1.0/24앞 24비트가 네트워크부라는 뜻입니다. 서브넷 마스크 255.255.255.0과 같은 의미이지만, 표기가 훨씬 간결합니다.

CIDR서브넷 마스크호스트부 비트사용 가능 호스트용도 예시
/8255.0.0.02416,777,214대형 ISP
/16255.255.0.01665,534기업 VPC
/20255.255.240.0124,094대규모 서브넷
/24255.255.255.08254일반 LAN
/25255.255.255.1287126중간 서브넷
/26255.255.255.192662소규모 서브넷
/27255.255.255.224530서버 팜
/28255.255.255.240414소규모 DMZ
/30255.255.255.25222포인트투포인트 링크
/31255.255.255.25412포인트투포인트 링크
/32255.255.255.25501단일 호스트

일반적인 IPv4 브로드캐스트 서브넷에서 호스트 수에서 2를 빼는 이유는, 호스트부가 모두 0인 주소(네트워크 주소)와 모두 1인 주소(브로드캐스트 주소)는 호스트에 할당할 수 없기 때문입니다.

호스트수=2(32n)2\text{호스트수} = 2^{(32 - n)} - 2

nn은 프리픽스 길이입니다. 다만 /31은 포인트투포인트 링크에서 두 주소를 모두 사용할 수 있고, /32는 단일 호스트 경로를 나타내므로 위 공식의 예외로 다룹니다.


서브넷 분할 계산

192.168.1.0/24 네트워크를 4개의 서브넷으로 나누어야 합니다.

4개의 서브넷이 필요하므로 22=42^2 = 4, 즉 호스트부에서 2비트를 빌려 네트워크부를 확장합니다.

서브넷네트워크 주소호스트 범위브로드캐스트게이트웨이 (관례)
1192.168.1.0/26.1 ~ .62.63.1
2192.168.1.64/26.65 ~ .126.127.65
3192.168.1.128/26.129 ~ .190.191.129
4192.168.1.192/26.193 ~ .254.255.193
subnet_calculator.py
"""서브넷 분할 계산기"""
import ipaddress

def subnet_divide(network_str, new_prefix):
    """네트워크를 지정된 프리픽스로 분할"""
    network = ipaddress.ip_network(network_str, strict=False)
    subnets = list(network.subnets(new_prefix=new_prefix))

    print(f"원래 네트워크: {network}")
    print(f"서브넷 마스크: {network.netmask}")
    print(f"사용 가능 호스트: {len(list(network.hosts()))}\n")
    print(f"분할 결과 ({len(subnets)}개 /{new_prefix} 서브넷):")
    print(f"{'서브넷':<22} {'호스트 범위':<35} {'BC':<16} {'호스트수'}")
    print("-" * 90)

    for i, subnet in enumerate(subnets, 1):
        hosts = list(subnet.hosts())
        if hosts:
            first, last = hosts[0], hosts[-1]
            print(f"{str(subnet):<22} {str(first)} ~ {str(last):<20} "
                  f"{str(subnet.broadcast_address):<16} {len(hosts)}")

# 실습
subnet_divide("192.168.1.0/24", 26)   # 4개 분할
print()
subnet_divide("10.0.0.0/16", 20)      # 16개 분할

# 두 IP가 같은 서브넷에 있는지 확인
def same_subnet(ip1, ip2, prefix):
    """두 IP가 같은 서브넷에 있는지 확인"""
    net = ipaddress.ip_network(f"{ip1}/{prefix}", strict=False)
    return ipaddress.ip_address(ip2) in net

print(f"\n같은 서브넷? {same_subnet('192.168.1.100', '192.168.1.200', 24)}")
print(f"같은 서브넷? {same_subnet('192.168.1.100', '192.168.1.200', 25)}")

슈퍼넷팅 (경로 집약)

서브넷 분할이 큰 네트워크를 작게 나누는 것이라면, 슈퍼넷팅(Supernetting)은 반대로 여러 네트워크를 하나로 합치는 것입니다.

경로 집약은 아무 네트워크나 합칠 수 있는 것이 아닙니다. 네트워크들이 연속된 주소 범위여야 하고, 합친 범위가 프리픽스 경계에 맞게 정렬되어 있어야 합니다. 또한 집약 대상 경로가 같은 방향으로 나가거나 같은 정책으로 처리될 수 있어야 합니다. 예를 들어 192.168.0.0/24부터 192.168.3.0/24까지 네 개의 연속된 네트워크는 192.168.0.0/22 하나로 표현할 수 있습니다.


클라우드 VPC 서브넷 설계

AWS VPC를 설계할 때 CIDR 계산이 직접적으로 필요합니다.

설계 원칙이유
VPC CIDR은 넉넉하게 선택기본 CIDR 크기는 나중에 변경할 수 없음
보조 CIDR 확장 가능성 고려필요 시 secondary IPv4 CIDR을 추가 가능
AZ별로 균등 분할가용성 확보
Public/Private/DB 분리보안 계층화
서브넷당 예약 IP 5개 고려AWS가 첫 4개와 마지막 1개 주소를 예약
EKS/컨테이너 IP 예산 확보노드와 Pod ENI/IP 소진 방지

AWS에서 IPv4 서브넷 크기는 /16부터 /28 범위 안에서 선택합니다. 각 서브넷에서는 첫 네 개 주소와 마지막 주소를 사용할 수 없으므로, 예를 들어 /24는 256개 주소가 있어도 실제 할당 가능한 주소는 251개입니다.

network_info.sh
# Linux에서 서브넷 정보 확인
ip addr show eth0 | grep inet

# 네트워크 주소 계산 (ipcalc)
ipcalc 192.168.1.100/26
# 출력: Network, HostMin, HostMax, Broadcast, Hosts

# Docker 네트워크의 서브넷 확인
docker network inspect bridge | grep -A 5 IPAM

다음 절에서는 사설 IP를 사용하는 장치들이 어떻게 인터넷과 통신하는지, NAT와 DHCP의 동작 원리를 살펴보겠습니다.