웹 컨테이너에서 curl http://db:5432를 실행했는데 이름을 찾지 못한다는 에러가 났습니다. 두 컨테이너는 같은 서버에 있었지만 기본 bridge 네트워크에서는 컨테이너 이름을 DNS로 해석해주지 않았습니다.
IP를 직접 넣어 임시로 해결했더니 재시작 후 IP가 바뀌어 다시 깨졌습니다. 컨테이너 간 통신은 네트워크를 어떻게 만들고 연결하느냐에 따라 안정성이 완전히 달라집니다.
컨테이너 간 통신과 Docker 네트워크
컨테이너는 기본적으로 서로 격리된 환경에서 동작합니다. 웹 서버가 데이터베이스에 접근하고, 마이크로서비스들이 서로 API를 호출하려면 네트워크 설정이 필요합니다. Docker 네트워크를 이해하면 컨테이너 간 통신을 안전하고 효율적으로 구성할 수 있습니다.
컨테이너들이 어떻게 서로를 찾고 통신하는지, 네트워크를 어떻게 격리해야 보안이 강화되는지 직접 실습으로 이해합니다.
- 1Docker 네트워크 드라이버 4종 — bridge / host / none / overlay 비교
- 2기본 bridge 네트워크의 한계와 사용자 정의 bridge 네트워크의 장점
- 3docker network create로 격리된 네트워크 구성 및 컨테이너 연결
- 4사용자 정의 네트워크에서 컨테이너 이름으로 DNS 해석되는 원리
- 5컨테이너 간 통신 허용/차단 설계 — 네트워크 격리 전략
컨테이너 간 통신 실습을 위해 curl 도구가 필요합니다. 호스트에 없더라도 curlimages/curl 컨테이너로 대체할 수 있습니다.
docker pswhich curl || sudo apt-get install -y curldocker network lsdocker pull nginx:alpine && docker pull curlimages/curlDocker 네트워크의 세 가지 기본 드라이버
웹 서버 컨테이너에서 curl http://db:5432를 실행했는데 연결이 안 됩니다. 같은 호스트에서 두 컨테이너를 실행했는데도 서로 찾지 못하는 상황입니다. 컨테이너는 기본적으로 격리된 네트워크 네임스페이스를 가지기 때문에, 어떤 네트워크 드라이버를 통해 연결하느냐에 따라 통신 방식이 완전히 달라집니다. 기본 브릿지(docker0)는 IP 주소로만 통신 가능하고, 사용자 정의 네트워크는 이름으로 통신 가능합니다. Host 모드는 격리를 포기하고 최고 성능을 택하며, None은 네트워크를 완전히 차단합니다. 이 ConceptBlock에서는 Docker가 제공하는 세 가지 기본 네트워크 드라이버와 각각의 동작 방식을 다룹니다.
Docker는 컨테이너 간 통신 방식에 따라 세 가지 핵심 네트워크 드라이버를 제공합니다.

브릿지(Bridge) 네트워크
브릿지 네트워크는 Docker의 기본 네트워크 모드입니다. Docker를 설치하면 docker0라는 가상 브릿지 인터페이스가 자동 생성되고, 별도 설정 없이 실행한 모든 컨테이너는 이 브릿지에 연결됩니다. 호스트의 물리 네트워크 위에 Docker가 만든 가상 스위치로 이해하면 됩니다. 아래 구조를 보면 컨테이너들이 호스트와 분리된 사설 IP 대역에서 동작한다는 것이 명확해집니다.
호스트 머신
├── eth0 (물리 네트워크: 192.168.1.100)
└── docker0 (가상 브릿지: 172.17.0.1)
├── container-A (172.17.0.2)
└── container-B (172.17.0.3)
컨테이너들은 172.17.0.x 대역의 사설 IP를 받아서 서로 통신할 수 있습니다. 단, 기본 브릿지(docker0)에는 내장 DNS가 없습니다. 이것이 핵심 제약사항입니다.
Host 네트워크
--network host 옵션을 사용하면 컨테이너가 호스트의 네트워크 네임스페이스를 그대로 사용합니다. 가상 네트워크 인터페이스가 없으므로 포트 매핑(-p)도 불필요합니다.
# 실습 디렉토리 준비
mkdir -p /tmp/docker/part3/exam_10 && cd /tmp/docker/part3/exam_10
# Host 모드로 nginx 실행 — 호스트의 80포트를 직접 사용
docker run --network host nginx
장점: NAT 오버헤드 없이 최고의 네트워크 성능 단점: 포트 충돌 위험, 컨테이너 격리 약화, macOS/Windows에서 미지원
None 네트워크
--network none은 루프백(127.0.0.1) 외 모든 네트워크 인터페이스를 비활성화합니다. 완전한 네트워크 격리가 필요한 보안 작업이나 배치 처리에 사용합니다.
# 네트워크 없는 완전 격리 컨테이너
docker run --network none alpine sh -c "echo '외부 접근 불가'"
현재 네트워크 목록 확인
docker network ls
# NETWORK ID NAME DRIVER SCOPE
# abc123def456 bridge bridge local ← 기본 docker0
# xyz789uvw012 host host local
# 111aaa222bbb none null local
미사용 Docker 네트워크 삭제
안전한 실행 조건: 삭제 대상이 실습 또는 임시 네트워크뿐임을 확인한 경우에만 실행합니다.
실행 전 반드시 확인
- docker network ls로 네트워크 목록을 확인했다
- 운영 Compose/Swarm 네트워크가 아님을 확인했다
- 연결된 컨테이너가 없는 네트워크만 삭제 대상임을 이해했다
docker network prune위 항목을 모두 확인한 후 복사할 수 있습니다
사용자 정의 네트워크와 내장 DNS
기본 브릿지(docker0)의 가장 큰 단점은 컨테이너 이름으로 통신이 불가능하다는 점입니다. IP는 재시작마다 바뀔 수 있기 때문에, 안정적인 서비스 간 통신을 위해서는 사용자 정의 네트워크를 만들어야 합니다.
사용자 정의 네트워크의 핵심 기능: 내장 DNS
사용자 정의 네트워크에는 Docker가 자동으로 **내장 DNS 서버(127.0.0.11)**를 제공합니다. 이 DNS 서버는 컨테이너 이름을 자동으로 해당 컨테이너의 IP로 변환해줍니다.

사용자 정의 네트워크(my_network)
├── 내장 DNS 서버: 127.0.0.11
├── web 컨테이너 (172.20.0.2) → "web" 이름으로 접근 가능
└── db 컨테이너 (172.20.0.3) → "db" 이름으로 접근 가능
web 컨테이너 내부에서:
$ ping db → 172.20.0.3으로 자동 해석 ✓
$ curl http://db:5432 → 동작 ✓
기본 브릿지 vs 사용자 정의 네트워크 비교
두 네트워크 타입은 겉으로는 비슷해 보이지만 실무에서 차이가 확연합니다. 기본 브릿지는 테스트용으로는 충분하지만, Docker Compose로 여러 서비스를 연결하는 순간 사용자 정의 네트워크가 필수가 됩니다.
| 기능 | 기본 브릿지(docker0) | 사용자 정의 네트워크 |
|---|---|---|
| 컨테이너 이름 DNS | 불가 | 가능 |
| 자동 서비스 디스커버리 | 불가 | 가능 |
| 네트워크 격리 | 모든 컨테이너 공유 | 네트워크별 격리 |
| --link 의존성 | 필요(deprecated) | 불필요 |
| 컨테이너 별칭 설정 | 불가 | --network-alias 가능 |
네트워크 생성과 관리 명령어
# 사용자 정의 브릿지 네트워크 생성
docker network create my_net
# 서브넷과 게이트웨이를 명시적으로 지정
docker network create \
--driver bridge \
--subnet 172.20.0.0/16 \
--gateway 172.20.0.1 \
my_net
# 네트워크 상세 정보 확인
docker network inspect my_net
# 네트워크에 연결된 컨테이너 목록 확인
docker network inspect my_net --format '{{range .Containers}}{{.Name}} {{end}}'
# 사용하지 않는 네트워크 정리
먼저 기본 브릿지에서 컨테이너 이름으로 통신이 안 된다는 것을 직접 확인해봅니다.
실습 전 네트워크 실습용 디렉토리를 준비합니다.
# 실습 디렉토리 준비
mkdir -p /tmp/docker/part2/network-demo && cd /tmp/docker/part2/network-demo
# 멀티 서비스 네트워크 구성 예제 파일 생성
cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
frontend:
image: nginx:alpine
ports:
- "8081:80"
networks:
- frontend-net
backend:
image: python:3.11-slim
command: python -m http.server 8080
networks:
- frontend-net
- backend-net
db:
image: postgres:15-alpine
environment:
POSTGRES_PASSWORD: secret
networks:
- backend-net
networks:
frontend-net:
backend-net:
EOF
1단계: 기본 네트워크에서 두 컨테이너 실행
# 터미널 1: 첫 번째 컨테이너 실행
docker run -d --name container-a alpine sleep 3600
# 터미널 2: 두 번째 컨테이너 실행
docker run -d --name container-b alpine sleep 3600
2단계: 각 컨테이너의 IP 확인
# container-a의 IP 확인
docker inspect container-a --format '{{.NetworkSettings.IPAddress}}'
# 예시 출력: 172.17.0.2
# container-b의 IP 확인
docker inspect container-b --format '{{.NetworkSettings.IPAddress}}'
# 예시 출력: 172.17.0.3
3단계: 이름으로 ping 시도 (실패 예상)
docker exec container-a ping -c 2 container-b
# ping: bad address 'container-b' ← 이름 해석 불가!
# IP로는 통신 가능
docker exec container-a ping -c 2 172.17.0.3
# PING 172.17.0.3: 56 data bytes — 성공
4단계: 정리
네트워크 실습 컨테이너 강제 삭제
안전한 실행 조건: container-a와 container-b가 이 모듈에서 만든 실습용 컨테이너인 경우에만 실행합니다.
실행 전 반드시 확인
- docker ps -a에서 두 컨테이너 이름을 확인했다
- 컨테이너 내부에 보존할 데이터가 없음을 확인했다
- 삭제 후 네트워크 실습을 다시 만들 수 있다
docker rm -f container-a container-b위 항목을 모두 확인한 후 복사할 수 있습니다
기본 브릿지에서는 IP가 아닌 이름으로 통신이 불가능함을 확인했습니다.
- container-a와 container-b의 IP가 서로 다른 172.17.x.x 주소로 표시되는가?
- container-a에서 container-b 이름으로 ping할 때 bad address가 발생하는가?
- IP 주소로 ping하면 통신이 되는가?
- 기본 bridge 네트워크에서는 이름 기반 DNS가 없다는 결론을 설명할 수 있는가?
사용자 정의 네트워크를 만들어 컨테이너 이름으로 통신하는 방법을 실습합니다.
1단계: 사용자 정의 네트워크 생성
docker network create my_net
docker network ls
# my_net이 bridge 드라이버로 생성된 것 확인
2단계: 동일 네트워크에 컨테이너 연결
# --network my_net 으로 사용자 정의 네트워크에 연결
docker run -d --name web --network my_net nginx:alpine
docker run -d --name db --network my_net alpine sleep 3600
3단계: 컨테이너 이름으로 ping 통신
# db 컨테이너에서 web 컨테이너로 이름 기반 ping
docker exec db 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.123 ms ← 성공!
# web 컨테이너에서 db로도 통신 가능
docker exec web ping -c 3 db
# PING db (172.20.0.3): 56 data bytes — 성공
4단계: DNS 서버 확인
# 컨테이너 내부 DNS 설정 확인
docker exec db cat /etc/resolv.conf
# nameserver 127.0.0.11 ← Docker 내장 DNS
# options ndots:0
5단계: 네트워크 검사
docker network inspect my_net
# "Containers" 섹션에서 web, db 컨테이너 확인
6단계: 정리
docker network rm my_net
컨테이너를 다시 시작하지 않고 네트워크에 연결하거나 해제할 수 있습니다.
1단계: 컨테이너와 두 개의 네트워크 생성
docker network create net-frontend
docker network create net-backend
docker run -d --name api-server --network net-frontend alpine sleep 3600
docker run -d --name cache --network net-backend alpine sleep 3600
2단계: api-server를 backend 네트워크에도 연결
# 실행 중인 컨테이너에 네트워크 추가 연결
docker network connect net-backend api-server
# api-server는 이제 두 네트워크 모두에 연결됨
docker inspect api-server --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{end}}'
# net-frontend net-backend
3단계: 통신 확인
# api-server에서 cache(net-backend에만 있음)로 통신
docker exec api-server ping -c 2 cache
# 성공 — api-server가 net-backend에 연결되어 있으므로
4단계: 네트워크 연결 해제
# api-server를 net-backend에서 분리
docker network disconnect net-backend api-server
# 이제 cache로의 통신 불가
docker exec api-server ping -c 2 cache
# ping: bad address 'cache'
5단계: 정리
docker network rm net-frontend net-backend
증상
두 컨테이너를 실행하고 서로 통신을 시도했는데, 컨테이너 이름으로 ping이 실패하거나 connection refused가 발생합니다.
docker exec app ping -c 2 database
# ping: bad address 'database'
원인 진단
1. 같은 네트워크에 있는지 확인
# 각 컨테이너가 어떤 네트워크에 연결되어 있는지 확인
docker inspect app --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}}{{end}}'
docker inspect database --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}}{{end}}'
두 컨테이너가 서로 다른 네트워크에 있으면 통신 불가.
2. 기본 브릿지(docker0) 사용 여부 확인
출력이 bridge(기본값)라면 사용자 정의 네트워크가 아닌 것입니다. 기본 브릿지에는 DNS가 없으므로 이름으로 통신 불가.
해결 방법
방법 1: 사용자 정의 네트워크로 재생성
docker network create my_app_net
docker run -d --name app --network my_app_net my_app_image
docker run -d --name database --network my_app_net postgres:14
방법 2: 실행 중인 컨테이너에 네트워크 연결
# 기존 컨테이너를 중단 없이 네트워크에 추가 연결
docker network connect my_app_net app
docker network connect my_app_net database
검증
docker exec app ping -c 2 database
# PING database: 성공
증상
--network host 옵션으로 컨테이너를 실행했는데, 호스트 IP로 접근이 안 됩니다.
docker run --network host nginx
# 브라우저에서 localhost:80 접근 시도 → 연결 거부
원인
Host 네트워크 모드는 리눅스 전용 기능입니다. macOS와 Windows에서 Docker Desktop은 리눅스 VM 위에서 동작하기 때문에, --network host를 사용해도 컨테이너가 공유하는 것은 VM의 네트워크이지 실제 macOS/Windows 호스트 네트워크가 아닙니다.
# macOS에서 확인
docker run --network host alpine ip addr
# 172.x.x.x 대역 출력 — macOS의 실제 네트워크가 아님
해결 방법
macOS/Windows 환경에서는 Host 모드 대신 포트 매핑을 사용합니다.
# Host 모드 대신 포트 매핑으로 대체
docker run -p 80:80 nginx
리눅스 서버(프로덕션)에서만 Host 모드의 성능 이점을 활용하고, 로컬 개발 환경(macOS/Windows)에서는 포트 매핑 방식을 사용하는 것이 권장됩니다.
환경 감지 스크립트 예시
OS_TYPE=$(uname -s)
if [ "$OS_TYPE" = "Linux" ]; then
NETWORK_FLAG="--network host"
else
NETWORK_FLAG="-p 8080:8080"
fi
docker run $NETWORK_FLAG my_service
실무에서는 서비스 유형에 따라 네트워크를 분리해 보안을 강화합니다. 외부에 노출해야 하는 서비스와 내부 서비스를 다른 네트워크에 배치하는 패턴이 일반적입니다.
실무 네트워크 구성 패턴
[인터넷]
↓
[frontend 네트워크]
├── nginx (리버스 프록시)
└── web-app (React 빌드 파일 서빙)
↓ (api-gateway만 두 네트워크에 연결)
[backend 네트워크]
├── api-gateway
├── auth-service
├── product-service
└── order-service
↓
[data 네트워크]
├── postgres
└── redis
실제 적용 예시
# 네트워크 생성
docker network create net-frontend
docker network create net-backend
docker network create net-data
# 프론트엔드 레이어
docker run -d --name nginx --network net-frontend -p 80:80 nginx
docker run -d --name web-app --network net-frontend my_frontend:latest
# API 게이트웨이 — 두 네트워크에 모두 연결 (브릿지 역할)
docker run -d --name api-gateway --network net-frontend my_gateway:latest
docker network connect net-backend api-gateway
# 백엔드 서비스
docker run -d --name auth-service --network net-backend my_auth:latest
docker run -d --name product-service --network net-backend my_product:latest
# 데이터 레이어
docker run -d --name postgres --network net-data postgres:14
# product-service를 data 네트워크에도 연결
docker network connect net-data product-service
이 패턴의 보안상 이점
- nginx는 인터넷에 노출되어 있지만, 직접 DB에 접근 불가
- postgres는 data 네트워크에만 있어서 외부에서 직접 접근 불가
- 침해사고 발생 시 피해 범위가 해당 네트워크로 제한됨
- Docker Compose의
networks섹션으로 이 구성을 코드로 관리 가능
현업 DevOps 엔지니어는 이런 네트워크 분리를 Docker Compose 파일이나 Kubernetes NetworkPolicy로 선언적으로 관리합니다.
증상
두 컨테이너가 동일한 사용자 정의 네트워크에 있고 ping도 성공하는데, 특정 포트로 연결이 되지 않습니다.
docker exec web curl http://api:8080/health
# curl: (7) Failed to connect to api port 8080: Connection refused
원인 진단
1. 컨테이너가 실제로 해당 포트를 열고 있는지 확인
# api 컨테이너에서 실제 리스닝 포트 확인
docker exec api netstat -tlnp 2>/dev/null || docker exec api ss -tlnp
# tcp 0 0 0.0.0.0:3000 0.0.0.0:* LISTEN (포트 번호 확인)
포트가 8080이 아닌 3000으로 열려 있다면 잘못된 포트를 지정한 것입니다.
2. 애플리케이션이 루프백에만 바인딩되어 있는지 확인
docker exec api ss -tlnp
# tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN
# ↑ 루프백(127.0.0.1)에만 바인딩 → 외부 접근 불가!
애플리케이션이 127.0.0.1:8080에 바인딩되어 있으면 같은 컨테이너 내부에서만 접근 가능합니다. 다른 컨테이너에서 접근하려면 0.0.0.0:8080으로 바인딩해야 합니다.
해결 방법
애플리케이션 설정 변경 (루프백 → 모든 인터페이스)
# Node.js 예시 — 0.0.0.0으로 바인딩 변경
app.listen(8080, '0.0.0.0', () => {
console.log('서버 시작: 0.0.0.0:8080');
});
# Python FastAPI 예시
uvicorn main:app --host 0.0.0.0 --port 8080
확인 방법
# 변경 후 바인딩 재확인
docker exec api ss -tlnp
# tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN ← 올바름
# 연결 테스트
docker exec web curl http://api:8080/health
# {"status": "ok"} ← 성공!
포트 번호 불일치인 경우
# EXPOSE는 문서화 목적일 뿐, 실제 포트와 다를 수 있음
docker inspect api --format '{{.Config.ExposedPorts}}'
# map[8080/tcp:{}] — Dockerfile의 EXPOSE 값
# 실제 리스닝 포트는 별도 확인
docker exec api ss -tlnp | grep LISTEN
네트워크 디버깅 — 컨테이너 통신이 안 될 때 진단하는 법
두 컨테이너가 같은 Compose 파일에 있는데 서로 통신이 안 됩니다. 에러 로그에는 "Connection refused" 또는 "No such host"가 뜹니다. 네트워크 문제는 원인이 여러 개일 수 있어서 무작정 설정을 바꾸면 오히려 혼란이 커집니다. 컨테이너가 같은 네트워크에 속해 있는지, DNS가 이름을 올바르게 해석하는지, 포트가 실제로 열려 있는지 순서대로 좁혀 나가야 빠르게 찾을 수 있습니다. 이 ConceptBlock에서는 컨테이너 간 통신 문제를 5단계로 진단하는 방법을 다룹니다.

단계별 진단 절차
컨테이너 간 통신 문제는 대부분 이 5단계 절차로 원인을 찾을 수 있습니다.
Step 1: 두 컨테이너가 같은 네트워크에 있는지 확인
# 네트워크 상세 정보 확인 — Containers 섹션에 두 컨테이너 모두 있어야 함
docker network inspect my_net
# 출력 예시
{
"Name": "my_net",
"Containers": {
"abc123": { "Name": "web", "IPv4Address": "172.20.0.2/16" },
"def456": { "Name": "db", "IPv4Address": "172.20.0.3/16" }
}
}
# 특정 컨테이너가 속한 네트워크 목록 확인
docker inspect web --format '{{json .NetworkSettings.Networks}}' | python3 -m json.tool
Step 2: 컨테이너 내부에서 DNS 해석 테스트
# nslookup으로 이름 → IP 변환 테스트
docker exec web nslookup db
# Server: 127.0.0.11 ← Docker 내장 DNS
# Address: 127.0.0.11#53
# Name: db
# Address: 172.20.0.3 ← 정상 해석됨
# ping으로 연결 확인
docker exec web ping -c 3 db
# Alpine 기반 이미지는 nslookup 대신 nslookup 패키지 설치 필요
# docker exec -it web sh
# / # nslookup db || apk add --no-cache bind-tools
Step 3: 포트 연결 테스트
# nc(netcat)으로 TCP 포트 열림 확인
docker exec web nc -zv db 5432
# Connection to db 5432 port [tcp/postgresql] succeeded!
# wget으로 HTTP 응답 확인
docker exec web wget -qO- http://api:8080/health
# curl 사용 시
docker exec web curl -s http://api:8080/health
Step 4: 컨테이너 네트워크 인터페이스 확인
# 컨테이너 내부 네트워크 인터페이스
docker exec web ip addr show
# eth0: 172.20.0.2/16 ← 컨테이너 IP
# 라우팅 테이블 확인
docker exec web ip route
# default via 172.20.0.1 dev eth0 ← 게이트웨이
자주 발생하는 네트워크 문제
| 증상 | 원인 | 해결 |
|---|---|---|
ping db 실패 | 다른 네트워크에 있음 | 같은 network에 두 컨테이너 연결 |
| DNS 해석 안 됨 | 기본 bridge(docker0) 사용 중 | 사용자 정의 network로 변경 |
ping 성공, curl :80 실패 | 앱이 127.0.0.1만 리스닝 | 앱 바인딩 주소를 0.0.0.0으로 변경 |
| 컨테이너 재시작 후 IP 변경 | 기본 bridge 사용 | 사용자 정의 network + 이름으로 통신 |
| Compose 서비스 간 통신 안 됨 | 다른 Compose 프로젝트 | external network 공유 설정 |
기본 bridge vs 사용자 정의 network 한 눈에 비교
# 기본 bridge (docker0): 이름으로 통신 불가
docker run -d --name app1 nginx
docker run -d --name app2 nginx
docker exec app1 ping app2 # ❌ 실패! IP 직접 입력해야 함
# 사용자 정의 network: 이름으로 통신 가능
docker network create mynet
docker run -d --name app1 --network mynet nginx
docker run -d --name app2 --network mynet nginx
docker exec app1 ping app2 # ✅ 성공! 이름으로 통신됨
Docker Compose와 네트워크 — 자동 생성 네트워크 이해
docker-compose.yml에 networks를 한 번도 선언하지 않았는데 서비스 이름으로 통신이 됩니다. 왜 그럴까요? Compose는 프로젝트마다 자동으로 기본 네트워크를 만들고 모든 서비스를 거기에 붙입니다. 이 동작을 모르면 "Compose에서는 됐는데 왜 docker run으로 따로 뜬 컨테이너와는 통신이 안 되지?"라는 혼동이 생깁니다. 자동 생성 네트워크의 이름 규칙과 서비스 간 연결 방식을 이해하면, 다중 Compose 프로젝트를 연결하거나 외부 컨테이너를 편입하는 고급 패턴도 자연스럽게 납득됩니다. 이 ConceptBlock에서는 Compose가 네트워크를 자동으로 구성하는 원리를 다룹니다.

Compose가 네트워크를 자동으로 만드는 이유
docker-compose.yml에 networks를 명시하지 않아도 서비스 간 통신이 되는 이유가 있습니다. Compose는 프로젝트마다 프로젝트명_default 네트워크를 자동으로 만들고 모든 서비스를 여기에 연결합니다.
# myapp 디렉토리에서 docker compose up 실행
cd ~/myapp && docker compose up -d
# 자동 생성된 네트워크 확인
docker network ls
# NETWORK ID NAME DRIVER
# abc123def456 myapp_default bridge ← 자동 생성됨
# ↑ 디렉토리명이 프로젝트명이 됨
이 네트워크 안에서 서비스 이름이 곧 DNS 이름이 됩니다.
# 네트워크를 명시하지 않아도 서비스 이름으로 통신 가능
services:
web:
image: myapp
environment:
- DB_HOST=db # 'db' = 서비스 이름 = DNS 이름
db:
image: postgres:16-alpine
여러 Compose 스택 간 네트워크 공유
서로 다른 docker-compose.yml 파일로 실행한 서비스들이 통신해야 할 때, external network를 사용합니다.
# 1. 공유 네트워크 먼저 생성
docker network create shared-net
# stack-a/compose.yml
networks:
shared-net:
external: true # 외부에서 이미 만든 네트워크 사용
services:
api:
image: my-api
networks:
- shared-net
- default # stack-a 내부 통신용
# stack-b/compose.yml
networks:
shared-net:
external: true
services:
frontend:
image: my-frontend
networks:
- shared-net # api 서비스에 접근 가능
docker compose -f stack-a/compose.yml up -d
docker compose -f stack-b/compose.yml up -d
# frontend에서 api로 통신 가능
docker exec stack-b-frontend-1 curl http://api:8080/health
네트워크 격리 전략
services:
web:
networks:
- frontend # 외부와 통신
- backend # DB와 통신
db:
networks:
- backend # backend에만 존재 → 외부 직접 접근 불가
# frontend 네트워크 없음 → web을 통해서만 접근 가능
redis:
networks:
- backend
networks:
frontend: # 외부 트래픽 용
backend: # 내부 서비스 전용 (DB, 캐시 등)
이렇게 네트워크를 분리하면 DB와 캐시는 web 서비스를 통해서만 접근 가능하여 보안이 강화됩니다.
정리
Docker 네트워크의 핵심 원칙을 기억하세요.
| 상황 | 권장 선택 |
|---|---|
| 단일 호스트 컨테이너 간 통신 | 사용자 정의 브릿지 네트워크 |
| 최고 성능이 필요한 리눅스 서버 | Host 네트워크 |
| 네트워크 완전 격리 필요 | None 네트워크 |
| 이름 기반 서비스 디스커버리 | 사용자 정의 네트워크(내장 DNS) |
기본 브릿지(docker0)는 테스트 용도로만 사용하고, 실제 서비스는 항상 docker network create로 만든 사용자 정의 네트워크를 사용하세요. 이름 기반 통신이 가능해져 설정 관리가 훨씬 쉬워집니다.
자주 사용하는 네트워크 관련 명령어
# 네트워크 목록 확인
docker network ls
# 네트워크 생성
docker network create my_net
# 네트워크 상세 정보 (연결된 컨테이너, IP 대역 확인)
docker network inspect my_net
# 실행 중인 컨테이너를 네트워크에 연결
docker network connect my_net my_container
# 컨테이너를 네트워크에서 분리
docker network disconnect my_net my_container
# 사용하지 않는 네트워크 일괄 삭제
# 컨테이너가 연결된 네트워크 확인
docker inspect my_container --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{end}}'
핵심 요약의 네트워크 일괄 정리
안전한 실행 조건: 삭제 대상이 컨테이너에 연결되지 않은 임시 네트워크뿐인 경우에만 실행합니다.
실행 전 반드시 확인
- docker network ls와 docker network inspect로 삭제 대상을 확인했다
- Compose 프로젝트가 사용하는 네트워크가 아님을 확인했다
- 다시 생성할 네트워크 이름과 설정을 알고 있다
docker network prune위 항목을 모두 확인한 후 복사할 수 있습니다
네트워크 설계 시 보안과 격리를 위해 서비스 유형(프론트엔드/백엔드/데이터)별로 별도 네트워크를 만들고, 필요한 컨테이너만 각 네트워크에 연결하는 최소 권한 원칙을 적용하세요.
다음 모듈에서는 여러 컨테이너, 네트워크, 볼륨 구성을 Docker Compose 파일 하나로 선언하고 한 번에 실행하는 방법을 다룹니다.