[Docker] 포트포워딩과 호스트 [Localhost](http://Localhost) 접근
Docker를 사용하다 보면 컨테이너의 서비스를 외부에 노출하거나, 반대로 컨테이너 내부에서 개발 환경의 다른 서비스(예: 호스트 머신에서 실행 중인 DB)에 접근해야 하는 경우가 있다. 오늘은 Docker 네트워킹에서 가장 자주 마주치는 두 가지 시나리오인 포트 포워딩 (-p 옵션)과 컨테이너에서 호스트의 localhost 서비스에 접근하는 방법에 대해 정리 해보고자 한다.
핵심 포인트
- Docker 컨테이너는 기본적으로 호스트와 분리된 네트워크 환경(브릿지 모드)을 가진다.
p <호스트 포트>:<컨테이너 포트>
옵션은 외부에서 컨테이너 내부 서비스로 접근하기 위한 포트 포워딩 설정이다. (Host -> Container)-net="host"
옵션은 컨테이너가 호스트의 네트워크를 그대로 공유하게 만들어, 네트워크 격리를 포기하는 대신 호스트 서비스 접근을 쉽게 한다. (p
사용 불가 및 보안 위험 증가)- 컨테이너에서 호스트 머신의
localhost
서비스에 접근하려면,host.docker.internal
(Docker Desktop 또는 Linux +-add-host
) 또는 호스트 게이트웨이 IP (구버전 Linux)를 사용해야 한다. - 가장 권장되는 방법은 기본 브릿지 네트워크를 유지하며,
p
옵션과host.docker.internal
(또는-add-host
)을 함께 사용하는 방법. - 컨테이너에서 호스트 서비스 접근 시
Connection refused
오류가 발생하면, 호스트 서비스가127.0.0.1
이 아닌0.0.0.0
에서 리스닝하는지 확인. - Linux 환경에서
host.docker.internal
을 사용하려면 Docker 버전 20.10 이상에서-add-host=host.docker.internal:host-gateway
플래그를 추가하는 것이 좋다.
Docker의 기본 네트워크: 브릿지(Bridge) 모드와 포트 포워딩 (p
)
Docker 컨테이너를 별다른 네트워크 설정 없이 실행하면, 기본적으로 ‘bridge’라는 가상 네트워크에 연결된다. 이 네트워크는 호스트 머신과는 독립된 공간처럼 작동하며, 컨테이너는 자신만의 내부 IP 주소(예: 172.17.0.2)를 할당받는다.
p
옵션: 포트포워딩
- 목적: 호스트 머신 외부 또는 호스트 머신 자체에서 컨테이너 내부에서 실행 중인 서비스(예: 웹 서버, API)에 접근할 수 있도록 경로를 열어주는 역할
- 작동 방식: 호스트 머신의 특정 포트로 들어오는 네트워크 요청을 컨테이너 내부의 지정된 포트로 전달(포워딩)한다.
- 사용법:
docker run -p <호스트 포트>:<컨테이너 포트> [이미지 이름]
- 예시:
docker run -d -p 8080:80 nginx
- 호스트 머신의
8080
포트로 들어오는 모든 요청이 컨테이너 내부의80
포트(Nginx 기본 포트)로 전달된다. - 이제 웹 브라우저에서
http://<호스트 IP>:8080
또는http://localhost:8080
으로 접속하면 Nginx 기본 페이지를 볼 수 있다.
- 호스트 머신의
- 예시:
- 핵심:
p
옵션은 외부에서 컨테이너 내부로 들어오는 길을 열어주는 것입니다.
호스트 네트워크 직접 사용: -net="host"
옵션
컨테이너가 호스트 머신의 네트워크 환경을 그대로 사용해야 하는 경우, 예를 들어, 컨테이너가 호스트의 localhost나 특정 네트워크 인터페이스에 직접 접근해야 하거나, 네트워크 성능 오버헤드를 최소화하고 싶을 때 사용한다.
- 작동 방식: 컨테이너가 독립된 네트워크 공간을 갖지 않고, 호스트 머신의 네트워크 스택(네임스페이스)을 공유한다. 컨테이너는 별도 IP를 갖지 않으며, 호스트의 IP와 포트를 직접 사용하게 된다.
- 사용법:
docker run --net="host" [이미지 이름]
- 주요 특징:
- 컨테이너 내부에서
localhost
는 호스트 머신의localhost
를 의미 p
옵션은 사용할 수 없거나 무시됩니다. 컨테이너가 사용하는 포트가 곧 호스트의 포트가 된다.- 네트워크 성능은 약간 향상될 수 있다.
- 컨테이너 내부에서
- 장점:
- 호스트의
localhost
서비스 접근 용이. - 네트워크 성능 오버헤드 감소.
- 포트 매핑 불필요.
- 호스트의
- 단점:
- 보안 위험 증가: 컨테이너가 호스트 네트워크에 완전히 노출되어 격리의 이점이 사라지게 된다. 또한 컨테이너가 침해되면 호스트 전체 네트워크에 영향을 줄 수 있다.
- 포트 충돌: 컨테이너가 사용하려는 포트를 호스트가 이미 사용 중이면 실행되지 않는다.
- 이식성 제한: 주로 Linux 환경에서 사용되며, Docker Desktop 환경에서는 동작 방식이 다르다.
⭐ 포트 포워딩과 호스트 localhost
동시 접근
컨테이너의 서비스를 외부에도 노출하고(-p 사용), 동시에 컨테이너 내부에서 호스트의 localhost 서비스(예: DB)에도 접근하고 싶다면 –net=”host”는 -p를 못 쓰게 하니 사용하면 안된다. 이럴때, host.docker.internal 을 사용해서 기본 브릿지 네트워크를 유지하면서, -p 옵션으로 포트를 노출하고, 컨테이너에서 호스트로 접근할 수 있다.
- Docker Desktop (Mac/Windows) 환경:
- 별도의 설정 없이 컨테이너 내부에서
host.docker.internal
이라는 특수 DNS 이름을 사용하면 호스트 머신에 접근할 수 있다. - 예시: 컨테이너 앱 설정에서 DB 호스트를
localhost
대신host.docker.internal
로 지정 (host.docker.internal:11434
)
- 별도의 설정 없이 컨테이너 내부에서
- Linux 네이티브 Docker 환경 (Docker 20.10 이상 권장):
docker run
명령어에-add-host=host.docker.internal:host-gateway
플래그를 추가host-gateway
는 Docker가 자동으로 호스트의 게이트웨이 IP 주소로 해석해주는 값이다.- 컨테이너 내부에서는 Docker Desktop과 동일하게
host.docker.internal
을 사용. - 예시:
docker run -d -p 8080:80 --add-host=host.docker.internal:host-gateway my-app-image
- Linux 네이티브 Docker 환경 (구 버전):
- 호스트의
docker0
브릿지 인터페이스 IP 주소(보통172.17.0.1
)를 직접 알아내서 사용한다. (ip addr show docker0
명령 등으로 확인) - 컨테이너 앱 설정에서 이 IP 주소를 직접 사용한다. (예:
172.17.0.1:11434
) - 이 방법은 IP가 변경될 수 있어 권장되지 않는다.
- 호스트의
실제 적용 예시 (Linux 기준, Docker 20.10+)
1
2
3
4
5
6
7
8
9
10
# 호스트의 11434 포트에서 Ollama 서비스가 실행 중이라고 가정
# 컨테이너의 9090 포트를 호스트의 49090 포트로 노출하고,
# 컨테이너 내부에서 호스트의 Ollama 서비스에 접근 가능하도록 실행
docker run -d --name my-dev-container \\
-p 49090:9090 \\
--add-host=host.docker.internal:host-gateway \\
-e OLLAMA_API_ENDPOINT=http://host.docker.internal:11434 \\
my-image:latest
: 위 예시에서 컨테이너 내부 애플리케이션은 OLLAMA_API_ENDPOINT
환경 변수를 읽어 http://host.docker.internal:11434
주소로 호스트의 Ollama 서비스에 접근할 수 있으며 동시에 외부에서는 http://<호스트 IP>:49090
으로 컨테이너의 9090
포트 서비스에 접근할 수 있다.
외부 서비스를 노출할 때는 -p 옵션을, 컨테이너에서 호스트 localhost에 접근해야 할 때는 host.docker.internal (또는 –add-host 플래그)을 사용하는 것이 일반적이고 안전한 방법이다. –net=”host”는 강력하지만 보안과 충돌 위험을 고려하여 신중하게 사용해야 한다.