iptables NAT와 Docker 네트워크 — 컨테이너 트래픽 흐름

Docker가 iptables를 이용해 컨테이너 NAT(MASQUERADE)와 포트 포워딩(DNAT)을 구현하는 원리, DOCKER 커스텀 체인, ip_forward 설정을 설명합니다.

· 5 min read · PALDYN Team

지난 글에서 QEMU의 에뮬레이션과 가상화 가속 원리를 살펴봤습니다. 이번에는 컨테이너 네트워킹의 핵심 — Docker가 iptables NAT 규칙을 어떻게 설정해 컨테이너와 외부 세계를 연결하는지 들여다봅니다.

왜 iptables인가

Docker 컨테이너는 docker0라는 가상 브리지에 veth 페어로 연결됩니다. 컨테이너의 기본 IP는 172.17.0.0/16 대역이라 외부에서 직접 라우팅할 수 없습니다. Docker는 Linux 커널의 Netfilter(iptables) 를 이용해 두 가지 NAT를 자동 구성합니다.

  • MASQUERADE: 컨테이너 → 외부 트래픽에서 출발지 IP를 호스트 IP로 치환
  • DNAT: 외부 → 컨테이너 포트 포워딩(-p)에서 목적지 IP:포트를 컨테이너 IP:포트로 변환

Docker 컨테이너 트래픽 흐름

Docker 브리지 네트워크 구조

# docker0 브리지 확인
ip addr show docker0
# inet 172.17.0.1/16

# 컨테이너 실행 후 veth 페어 확인
docker run -d --name web nginx
ip link show type veth
# veth abc123@if3: ... master docker0

# 컨테이너 내부 IP 확인
docker inspect web | grep IPAddress
# "IPAddress": "172.17.0.2"

iptables 규칙 확인

# nat 테이블 전체 보기
sudo iptables -t nat -L -n -v

# POSTROUTING: MASQUERADE 규칙
sudo iptables -t nat -L POSTROUTING -n
# MASQUERADE  all -- 172.17.0.0/16  !172.17.0.0/16

# PREROUTING: 포트 포워딩 DNAT
sudo iptables -t nat -L DOCKER -n
# DNAT  tcp -- 0.0.0.0/0  0.0.0.0/0  tcp dpt:8080 to:172.17.0.2:80

# filter 테이블: FORWARD 허용
sudo iptables -t filter -L FORWARD -n

Docker 커스텀 체인

Docker는 기본 체인에 직접 규칙을 추가하지 않고 커스텀 체인을 만들어 관리합니다.

iptables 체인과 Docker 커스텀 체인

체인테이블역할
DOCKERnatDNAT 포트 포워딩 규칙
DOCKERfilter컨테이너로의 연결 허용
DOCKER-USERfilter사용자 커스텀 규칙 삽입 위치
DOCKER-ISOLATION-STAGE-1filter네트워크 간 격리 1단계
DOCKER-ISOLATION-STAGE-2filter네트워크 간 격리 2단계

사용자 정의 방화벽 규칙

Docker 컨테이너에 방화벽 규칙을 추가할 때는 반드시 DOCKER-USER 체인에 추가해야 합니다. Docker가 재시작되면 DOCKER 체인은 재생성되지만 DOCKER-USER 체인은 보존됩니다.

# 특정 IP만 컨테이너 포트 접근 허용
sudo iptables -I DOCKER-USER -i eth0 \
    ! -s 203.0.113.0/24 \
    -j DROP

# 특정 포트 외부 접근 차단
sudo iptables -I DOCKER-USER \
    -p tcp --dport 5432 \
    -j DROP

# 규칙 저장 (Ubuntu)
sudo apt install iptables-persistent
sudo netfilter-persistent save

포트 포워딩 원리 상세

# docker run -p 8080:80 시 생성되는 규칙
# 1. PREROUTING DNAT: 목적지 포트 8080 → 172.17.0.2:80
# 2. FORWARD ACCEPT: docker0 → eth0 양방향 허용
# 3. POSTROUTING MASQUERADE: 응답 패킷 변환

# 규칙 수동 추가 예 (Docker 없이 NAT 구성)
sudo iptables -t nat -A PREROUTING \
    -p tcp --dport 8080 \
    -j DNAT --to-destination 172.17.0.2:80

sudo iptables -t nat -A POSTROUTING \
    -s 172.17.0.0/16 ! -d 172.17.0.0/16 \
    -j MASQUERADE

sudo iptables -A FORWARD -i docker0 -j ACCEPT
sudo iptables -A FORWARD -o docker0 -j ACCEPT

# ip_forward 활성화 (필수)
echo 1 > /proc/sys/net/ipv4/ip_forward
# 영구 설정: /etc/sysctl.conf → net.ipv4.ip_forward = 1

iptables vs nftables

Docker 최신 버전(23+)은 시스템에 따라 nftables 백엔드를 사용할 수 있습니다. iptables-nft가 설치된 환경에서는 nftables 규칙이 생성됩니다.

# nftables로 확인
sudo nft list ruleset | grep docker

# Docker가 iptables-legacy 사용하도록 강제 (호환성)
sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
sudo systemctl restart docker

네트워크 격리 확인

# 서로 다른 Docker 네트워크 간 격리 확인
docker network create net1
docker network create net2
docker run -d --network net1 --name c1 alpine sleep 3600
docker run -d --network net2 --name c2 alpine sleep 3600

# c2에서 c1으로 ping 불가 (DOCKER-ISOLATION 체인이 차단)
docker exec c2 ping -c 1 c1

# 두 네트워크를 연결하려면
docker network connect net2 c1

지난 글: QEMU 개요 — 범용 에뮬레이터이자 가상화 가속기

다음 글: Linux 부팅 과정 — BIOS에서 systemd까지


읽어주셔서 감사합니다. 😊