Docker 네트워킹 가이드 — bridge, host, overlay

Docker 네트워크 개요

Docker 컨테이너는 기본적으로 격리된 네트워크 환경에서 실행됩니다. 컨테이너 간 통신, 외부 네트워크 접근, 서비스 디스커버리를 위해 Docker는 다양한 네트워크 드라이버를 제공합니다.

비유하면, 각 컨테이너는 독립된 아파트 호실이고, Docker 네트워크는 아파트 단지 내 통신 시스템입니다. 같은 네트워크(단지)에 속한 컨테이너(호실)끼리만 직접 통신할 수 있습니다.

드라이버설명주요 용도
bridge호스트 내부 가상 브리지 (기본값)단일 호스트에서 컨테이너 간 통신
host호스트 네트워크 직접 사용네트워크 성능이 중요한 경우
none네트워크 비활성화완전 격리가 필요한 경우
overlay여러 호스트를 연결하는 가상 네트워크Docker Swarm, 멀티 호스트
macvlan컨테이너에 물리 MAC 주소 할당물리 네트워크에 직접 연결

bridge 네트워크

Docker 설치 시 docker0라는 기본 브리지 네트워크가 생성됩니다. 그러나 기본 브리지는 DNS 기반 서비스 디스커버리를 지원하지 않으므로, 사용자 정의 브리지 네트워크를 만들어 사용하는 것이 권장됩니다.

# 기본 네트워크 목록 확인
docker network ls
# NETWORK ID     NAME      DRIVER    SCOPE
# a1b2c3d4e5f6   bridge    bridge    local
# f6e5d4c3b2a1   host      host      local
# 1234567890ab   none      null      local

# 사용자 정의 브리지 네트워크 생성
docker network create \
  --driver bridge \
  --subnet 172.20.0.0/16 \
  --gateway 172.20.0.1 \
  my-app-network

# 네트워크 상세 정보 확인
docker network inspect my-app-network
# [{ "Name": "my-app-network",
#    "Driver": "bridge",
#    "IPAM": { "Config": [{ "Subnet": "172.20.0.0/16", "Gateway": "172.20.0.1" }] }
# }]

사용자 정의 브리지에서는 컨테이너 이름으로 DNS 조회가 가능합니다.

# 같은 네트워크에 두 컨테이너 실행
docker run -d --name web --network my-app-network nginx:alpine
docker run -d --name api --network my-app-network node:22-alpine sleep 3600

# api 컨테이너에서 web 컨테이너로 이름으로 접근
docker exec api ping -c 3 web
# PING web (172.20.0.2): 56 data bytes
# 64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.089 ms

# DNS 조회 확인
docker exec api nslookup web
# Name:      web
# Address 1: 172.20.0.2 web.my-app-network

# 기본 bridge에서는 컨테이너 이름 DNS가 작동하지 않음
docker run -d --name test1 nginx:alpine
docker run -it --rm alpine ping -c 1 test1
# ping: bad address 'test1'  ← 실패

기본 bridge와 사용자 정의 bridge의 차이점입니다.

기능기본 bridge사용자 정의 bridge
DNS 서비스 디스커버리지원 안 함컨테이너 이름으로 통신
자동 연결지정 안 하면 자동 연결명시적 연결 필요
격리 수준모든 컨테이너가 같은 네트워크네트워크 단위 격리
실행 중 네트워크 변경불가docker network connect/disconnect

host 네트워크

host 네트워크는 컨테이너가 호스트의 네트워크 스택을 직접 사용합니다. 포트 매핑 없이 호스트의 포트를 그대로 사용하므로 네트워크 오버헤드가 없습니다.

# host 네트워크로 실행 (포트 매핑 불필요)
docker run -d --name web --network host nginx:alpine

# 호스트의 80 포트로 직접 접근
curl http://localhost:80
# <!DOCTYPE html>
# <html>
# <head><title>Welcome to nginx!</title></head>

# 컨테이너의 네트워크 인터페이스 확인 (호스트와 동일)
docker exec web ip addr
# 호스트의 eth0, lo 등이 그대로 보임

host 네트워크는 다음 경우에 사용합니다.

  • 네트워크 성능이 중요한 경우 (NAT 오버헤드 제거)
  • 컨테이너가 많은 포트를 사용하는 경우
  • 호스트의 네트워크 설정에 직접 접근해야 하는 경우

단, 호스트의 포트를 직접 점유하므로 포트 충돌에 주의해야 하며, 컨테이너 간 네트워크 격리가 불가능합니다.

Docker Compose 네트워킹

Docker Compose는 프로젝트별로 자동으로 네트워크를 생성합니다. {프로젝트명}_default라는 이름의 브리지 네트워크가 만들어지고, 서비스 이름으로 DNS 통신이 가능합니다.

# docker-compose.yml
# 프론트엔드, 백엔드, DB를 네트워크로 분리

services:
  # 프론트엔드: 외부 네트워크 + 백엔드 네트워크
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    networks:
      - frontend
      - backend
    depends_on:
      - api

  # 백엔드 API: 백엔드 네트워크 + DB 네트워크
  api:
    build: ./api
    environment:
      # 서비스 이름 'db'로 접근 (DNS 자동 해석)
      DATABASE_URL: "postgres://user:pass@db:5432/myapp"
      REDIS_URL: "redis://cache:6379"
    networks:
      - backend
      - database

  # 데이터베이스: DB 네트워크만 (외부 접근 차단)
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - pgdata:/var/lib/postgresql/data
    networks:
      - database

  # Redis 캐시: 백엔드 네트워크만
  cache:
    image: redis:7-alpine
    networks:
      - backend

# 네트워크 정의
networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
  database:
    driver: bridge
    # 내부 전용 네트워크 (외부 접근 불가)
    internal: true

volumes:
  pgdata:
# Compose 실행
docker compose up -d

# 생성된 네트워크 확인
docker network ls
# NETWORK ID     NAME                  DRIVER
# ...            myproject_frontend    bridge
# ...            myproject_backend     bridge
# ...            myproject_database    bridge

# api 컨테이너에서 db 접근 확인
docker compose exec api ping -c 1 db
# PING db (172.22.0.3): 56 data bytes
# 64 bytes from 172.22.0.3: time=0.056 ms

# nginx에서 db 접근 시도 (네트워크가 다르므로 실패)
docker compose exec nginx ping -c 1 db
# ping: bad address 'db'  ← 격리 작동

이 구성에서 database 네트워크에 internal: true를 설정하면 외부 인터넷 접근이 차단되어 데이터베이스 보안이 강화됩니다.

overlay 네트워크

overlay 네트워크는 여러 Docker 호스트에 걸쳐 컨테이너를 연결합니다. Docker Swarm 모드에서 주로 사용합니다.

# Swarm 초기화 (매니저 노드)
docker swarm init

# overlay 네트워크 생성
docker network create \
  --driver overlay \
  --attachable \
  --subnet 10.0.10.0/24 \
  my-overlay-network

# 서비스 배포 (overlay 네트워크 사용)
docker service create \
  --name web \
  --network my-overlay-network \
  --replicas 3 \
  nginx:alpine

# 다른 호스트의 컨테이너와도 이름으로 통신 가능
# 10.0.10.2 (호스트 A의 web.1)
# 10.0.10.3 (호스트 B의 web.2)
# 10.0.10.4 (호스트 C의 web.3)

--attachable 옵션을 추가하면 Swarm 서비스뿐만 아니라 일반 컨테이너(docker run)도 overlay 네트워크에 접속할 수 있습니다.

네트워크 디버깅

네트워크 문제를 진단하는 명령어입니다.

# 컨테이너의 IP 주소 확인
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' web
# 172.20.0.2

# 컨테이너 간 연결 테스트
docker exec api curl -s http://web:80
# <!DOCTYPE html>...

# 컨테이너의 네트워크 인터페이스 확인
docker exec web ip addr show eth0
# inet 172.20.0.2/16 scope global eth0

# 네트워크에 연결된 컨테이너 목록
docker network inspect my-app-network --format '{{range .Containers}}{{.Name}} {{.IPv4Address}}{{"\n"}}{{end}}'
# web 172.20.0.2/16
# api 172.20.0.3/16

# 포트 매핑 확인
docker port web
# 80/tcp -> 0.0.0.0:8080

# DNS 해석 테스트
docker exec api getent hosts web
# 172.20.0.2  web

실전 팁

  • 사용자 정의 네트워크 사용: 기본 bridge 네트워크 대신 항상 사용자 정의 네트워크를 생성하세요. DNS 서비스 디스커버리, 더 나은 격리, 실행 중 네트워크 변경이 가능합니다.
  • 네트워크 분리로 보안 강화: 위의 Compose 예제처럼 프론트엔드, 백엔드, 데이터베이스 네트워크를 분리하면 DB가 외부에 직접 노출되지 않습니다. internal: true로 외부 인터넷 접근도 차단하세요.
  • 포트 바인딩 주의: -p 3000:3000은 모든 인터페이스(0.0.0.0)에 바인딩합니다. 로컬에서만 접근해야 하면 -p 127.0.0.1:3000:3000으로 제한하세요.
  • 네트워크 정리: 사용하지 않는 네트워크는 docker network prune으로 정리합니다. 특히 테스트 후 남은 네트워크가 쌓이면 IP 대역 충돌이 발생할 수 있습니다.
  • DNS 캐시: Docker의 내장 DNS 서버(127.0.0.11)는 컨테이너 이름 해석을 담당합니다. 컨테이너가 재시작되어 IP가 바뀌어도 이름으로 접근하면 자동으로 새 IP를 해석합니다. IP 하드코딩을 피하고 항상 서비스 이름을 사용하세요.

이 글이 도움이 되었나요?