Theme:

두 개의 컨테이너를 띄웠는데 서로 통신이 안 됩니다. 같은 머신에서 돌고 있는데 왜 연결이 안 되는 걸까요?

Docker 네트워크의 기본 개념

Docker는 각 컨테이너에 독립적인 네트워크 환경을 제공합니다. 리눅스의 네트워크 네임스페이스를 활용하여 컨테이너마다 별도의 IP, 라우팅 테이블, 포트 공간을 가집니다.

BASH
# 현재 존재하는 네트워크 확인
docker network ls

# NETWORK ID     NAME      DRIVER    SCOPE
# a1b2c3d4e5f6   bridge    bridge    local
# g7h8i9j0k1l2   host      host      local
# m3n4o5p6q7r8   none      null      local

Docker를 설치하면 위 세 개의 네트워크가 기본으로 생성됩니다.

bridge — 기본 네트워크 드라이버

컨테이너를 생성할 때 네트워크를 지정하지 않으면 기본 bridge 네트워크에 연결됩니다.

동작 원리

PLAINTEXT
호스트 머신
┌─────────────────────────────────────┐
│           docker0 (172.17.0.1)      │
│              │                      │
│     ┌────────┼────────┐             │
│     │        │        │             │
│  ┌──┴──┐  ┌──┴──┐  ┌──┴──┐        │
│  │veth1│  │veth2│  │veth3│        │
│  └──┬──┘  └──┬──┘  └──┬──┘        │
│     │        │        │             │
│  ┌──┴──┐  ┌──┴──┐  ┌──┴──┐        │
│  │ C1  │  │ C2  │  │ C3  │        │
│  │.0.2 │  │.0.3 │  │.0.4 │        │
│  └─────┘  └─────┘  └─────┘        │
└─────────────────────────────────────┘
  • Docker는 호스트에 docker0이라는 가상 브릿지를 생성합니다.
  • 각 컨테이너는 veth pair(가상 이더넷 쌍)로 docker0에 연결됩니다.
  • 컨테이너는 172.17.0.x 대역의 IP를 자동으로 할당받습니다.
BASH
# 컨테이너 실행 (기본 bridge에 연결)
docker run -d --name web nginx

# IP 주소 확인
docker inspect web --format '{{.NetworkSettings.IPAddress}}'
# 172.17.0.2

# 호스트에서 브릿지 확인
ip link show docker0
brctl show docker0

기본 bridge의 한계

BASH
# 컨테이너 두 개 실행
docker run -d --name web nginx
docker run -d --name app node:20-alpine sleep 3600

# app에서 web으로 이름으로 접근 → 실패!
docker exec app ping web
# ping: bad address 'web'

# IP로는 가능
docker exec app ping 172.17.0.2
# PING 172.17.0.2: 64 bytes ...

기본 bridge 네트워크에서는 컨테이너 이름으로 DNS 해석이 되지 않습니다. IP 주소를 직접 사용해야 하는데, IP는 컨테이너를 재시작할 때마다 바뀔 수 있어서 실용적이지 않습니다.

사용자 정의 bridge 네트워크

실무에서는 거의 항상 사용자 정의 bridge 네트워크를 사용합니다.

BASH
# 사용자 정의 네트워크 생성
docker network create my-network

# 네트워크를 지정하여 컨테이너 실행
docker run -d --name web --network my-network nginx
docker run -d --name app --network my-network node:20-alpine sleep 3600

# 이름으로 접근 → 성공!
docker exec app ping web
# PING web (172.18.0.2): 56 data bytes
# 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.089 ms

기본 bridge vs 사용자 정의 bridge

기능기본 bridge사용자 정의 bridge
자동 DNS 해석XO
네트워크 격리모든 컨테이너가 같은 네트워크네트워크별 격리
동적 연결/해제XO
서브넷/게이트웨이 설정XO
--link 필요컨테이너 연결 시 필요불필요

네트워크 옵션 지정

BASH
# 서브넷과 게이트웨이 직접 설정
docker network create \
    --subnet 10.0.0.0/24 \
    --gateway 10.0.0.1 \
    my-custom-network

# 컨테이너에 고정 IP 할당
docker run -d --name db \
    --network my-custom-network \
    --ip 10.0.0.100 \
    postgres:16-alpine

다중 네트워크 연결

하나의 컨테이너를 여러 네트워크에 동시에 연결할 수 있습니다.

BASH
docker network create frontend
docker network create backend

# 웹 서버는 프론트엔드와 백엔드 모두 연결
docker run -d --name web --network frontend nginx

# 실행 중인 컨테이너에 네트워크 추가
docker network connect backend web

# DB는 백엔드에만 연결 (프론트엔드에서 직접 접근 불가)
docker run -d --name db --network backend postgres:16-alpine
PLAINTEXT
┌── frontend ──┐    ┌── backend ──┐
│              │    │             │
│   browser ───┼── web ──┼── db  │
│              │    │             │
└──────────────┘    └─────────────┘

이 패턴으로 네트워크 계층을 분리하여 보안을 강화할 수 있습니다.

host — 네트워크 격리 없음

host 모드는 컨테이너가 호스트의 네트워크 스택을 직접 사용합니다.

BASH
# host 네트워크로 실행
docker run -d --network host nginx

# 호스트의 80 포트에서 직접 서비스됨
# -p 포트 매핑이 필요 없음
curl http://localhost:80

특징

  • 네트워크 네임스페이스 격리가 없습니다.
  • 포트 매핑(-p)이 필요 없고 무시됩니다.
  • 네트워크 성능이 가장 좋습니다 (NAT 오버헤드 없음).
  • 포트 충돌 위험이 있습니다 (호스트에서 이미 사용 중인 포트는 사용 불가).
  • Linux에서만 완전히 지원됩니다 (macOS/Windows에서는 VM 안에서 동작).

사용 사례

  • 네트워크 모니터링 도구 (호스트 네트워크 트래픽 직접 관찰)
  • 성능이 매우 중요한 경우
  • 많은 수의 포트를 사용하는 애플리케이션
BASH
# 성능 테스트를 위한 host 모드
docker run --network host \
    --name benchmark \
    fortio/fortio load -qps 0 http://target:8080

none — 네트워크 비활성화

none 모드는 컨테이너에 loopback 인터페이스(lo)만 제공합니다. 외부 네트워크 접근이 완전히 차단됩니다.

BASH
docker run --network none alpine ip addr
# 1: lo: <LOOPBACK,UP,LOWER_UP>
#     inet 127.0.0.1/8 scope host lo
# → 네트워크 인터페이스가 lo만 존재

사용 사례

  • 네트워크가 필요 없는 배치 처리 (데이터 변환, 파일 처리)
  • 보안이 중요한 암호 연산
  • 네트워크 격리가 필요한 테스트
BASH
# 네트워크 없이 파일 처리
docker run --network none \
    -v $(pwd)/data:/data \
    myprocessor:latest

DNS 자동 해석

사용자 정의 네트워크에서 Docker는 내장 DNS 서버(127.0.0.11)를 제공합니다.

BASH
# DNS 설정 확인
docker run --network my-network alpine cat /etc/resolv.conf
# nameserver 127.0.0.11
# options ndots:0

# 컨테이너 이름으로 해석
docker exec app nslookup web
# Server: 127.0.0.11
# Address: 127.0.0.11:53
# Name: web
# Address: 172.18.0.2

네트워크 별칭(alias)

BASH
# 별칭 지정
docker run -d --name postgres-primary \
    --network my-network \
    --network-alias db \
    --network-alias database \
    postgres:16-alpine

# db 또는 database로 접근 가능
docker exec app ping db
docker exec app ping database

여러 컨테이너에 같은 별칭을 주면 라운드 로빈 방식으로 DNS가 해석됩니다(간단한 로드 밸런싱).

네트워크 명령어 정리

BASH
# 네트워크 생성
docker network create my-network

# 네트워크 목록
docker network ls

# 네트워크 상세 정보 (연결된 컨테이너, 서브넷 등)
docker network inspect my-network

# 실행 중인 컨테이너를 네트워크에 연결
docker network connect my-network existing-container

# 네트워크에서 분리
docker network disconnect my-network existing-container

# 사용하지 않는 네트워크 정리
docker network prune

# 네트워크 삭제
docker network rm my-network

정리

  • Docker는 bridge, host, none 세 가지 기본 네트워크 드라이버를 제공합니다.
  • 사용자 정의 bridge 네트워크를 사용해야 컨테이너 이름으로 DNS 해석이 가능합니다. 기본 bridge는 실무에서 권장하지 않습니다.
  • host 모드는 네트워크 성능이 중요할 때, none은 네트워크 격리가 필요할 때 사용합니다.
  • 다중 네트워크를 활용하면 프론트엔드/백엔드 네트워크를 분리하여 보안을 강화할 수 있습니다.
  • Docker의 내장 DNS 서버가 사용자 정의 네트워크에서 서비스 디스커버리 역할을 합니다.
댓글 로딩 중...