— 왜 붙고, 왜 안 붙는지 주소 관점으로 이해하기
Docker 네트워크 문제를 코드가 아니라
“누가 누구를 어떤 주소로 보느냐” 기준으로 정리한 기록
오늘의 한 줄 요약
Docker 통신 문제의 90%는 주소 문제다.
localhost, service name, host 주소만 구분하면 끝난다.
배경
로컬에서 Spring Boot 애플리케이션을 실행한 상태에서
Docker로 여러 서비스를 띄워 연동 테스트를 진행했다.
- DB (예: MongoDB)
- 외부 서비스
문제는 다음과 같았다.
- 컨테이너 안에서는 되는데 로컬에서는 안 됨
- localhost로 붙었는데 연결 실패
- 헬스체크는 실패하는데 서비스는 떠 있음
결론적으로 네트워크 구조를 정확히 이해하지 못한 상태였다.
Docker 네트워크 구조 한 장 요약
Docker bridge 네트워크
- docker compose up 실행 시
- 프로젝트 전용 user-defined bridge 네트워크가 자동 생성됨
- 이 bridge는 가상 L2 스위치 역할을 함
컨테이너 ── veth ── bridge ── veth ── 컨테이너
- 같은 bridge에 붙은 컨테이너끼리는 사설 IP로 직접 통신 가능
- 네트워크 격리는 유지됨
service 이름 = 컨테이너 DNS 이름
Docker는 내장 DNS (127.0.0.11) 를 제공한다.
services:
mongo:
image: mongo
같은 bridge 네트워크에 있는 컨테이너 내부에서는:
mongodb://mongo:27017
이게 가능한 이유는:
- mongo라는 service 이름이
- Docker DNS를 통해 컨테이너 IP로 자동 변환되기 때문
📌 service 이름은 코드 이름이 아니라 “환경이 제공하는 네트워크 이름”
localhost의 진짜 의미
핵심: localhost는 항상 “나 자신”
위치localhost 의미
| 로컬 터미널 | 로컬 머신 |
| 컨테이너 내부 | 해당 컨테이너 |
| Kubernetes Pod | 해당 Pod |
그래서 아래는 모두 실패한다.
- 컨테이너 → 다른 컨테이너 (localhost)
- 컨테이너 → 호스트 (localhost)
로컬 ↔ Docker 컨테이너 통신 규칙
1️⃣ 로컬 → Docker 컨테이너
👉 ports:로 포트가 열려 있어야 한다
services:
mongo:
image: mongo
로컬 애플리케이션에서는:
mongodb://localhost:27017
의미:
- ports = 호스트 ↔ 컨테이너를 잇는 다리
- 로컬에서 접근할 땐 항상 호스트 포트 기준
2️⃣ Docker 컨테이너 → 로컬
👉 Mac / Windows (Docker Desktop)
http://host.docker.internal:8080
- localhost ❌ (컨테이너 자신)
- host.docker.internal ⭕ (호스트 머신)
📌 Docker가 제공하는 특수 DNS 이름
주의: 로컬 애플리케이션 바인딩
컨테이너에서 로컬 애플리케이션으로 접근하려면
로컬 서버가 외부 요청을 받아야 한다.
server.address=0.0.0.0
server.port=8080
- 127.0.0.1만 바인딩되어 있으면 ❌
- 0.0.0.0 = 모든 인터페이스에서 listen
실제 구성 예시 (로컬 + Docker 혼합)
로컬에서 실행 중
- Spring Boot 애플리케이션
Docker로 실행
- MongoDB
- 외부 서비스
통신 방식
주체접근 주소
| 로컬 Spring → Mongo | localhost:27017 |
| 로컬 Spring → 외부 서비스 | localhost:{외부 서비스_port} |
| 외부 서비스 컨테이너 → Spring | host.docker.internal:8080 |
| 컨테이너 ↔ 컨테이너 | service명:포트 |
흔한 실수 정리
- ❌ 컨테이너 안에서 localhost로 다른 서비스 접근
- ❌ service 이름을 로컬에서 사용
- ❌ 포트 publish 없이 로컬에서 접근 시도
- ❌ 컨테이너 → 로컬 호출 시 host.docker.internal 미사용
정리하며 얻은 결론
- Docker 네트워크는 어렵지 않다.
- 주소를 환경 기준으로 나누면 끝난다.
로컬 → localhost
컨테이너 → service name
컨테이너 → 로컬 → host.docker.internal
한 줄 결론
Docker ↔ 로컬 통신은
“누가 실행 주체인지”와 “어디서 보느냐”만 구분하면 된다.
'DevOps > Docker' 카테고리의 다른 글
| Docker - Healthcheck, Liveness, Readiness (0) | 2026.02.01 |
|---|---|
| Docker - Kafka를 Docker로 띄우면 왜 로컬에서는 붙었다가 실패할까? (0) | 2026.02.01 |
댓글