[Docker] 네트워크 공유 없이, 호스트 포트로 컨테이너간 통신하기 (host.docker.internal)



태그: Docker, DevOps, Network, host.docker.internal

1. 문제 상황

개발 환경에서 여러 서비스를 도커로 관리할 때가 많습니다.

  • App-A (예: DRF)는 network-A에 있습니다.

  • App-B (예: Nextcloud)는 network-B에 있습니다.

  • 두 컨테이너는 같은 호스트 머신에서 실행됩니다.

  • App-B는 호스트의 8080 포트와 바인딩되어 있습니다. (예: docker run -p 8080:80 ...)

App-A에서 App-B를 API로 호출해야 합니다. 귀찮게 두 네트워크를 브릿지로 연결하고 싶지는 않습니다. 호스트의 8080 포트를 바로 호출할 순 없을까요?

컨테이너 내부에서 localhost:8080이나 127.0.0.1:8080을 호출하면, 이는 호스트 머신이 아닌 컨테이너 자기 자신을 가리킵니다.

2. 해결책: host.docker.internal

가장 간단한 해결책은 host.docker.internal이라는 특수 DNS 이름을 사용하는 것입니다.

host.docker.internal: 컨테이너 내부에서 호스트 머신의 IP 주소로 해석되는 특별한 호스트 이름입니다.

App-A (DRF)의 코드에서 Nextcloud를 호출할 때, URL을 다음과 같이 설정합니다.

# DRF (App-A) 내부 코드
import requests

# 'localhost' 대신 'host.docker.internal'을 사용합니다.
NEXTCLOUD_URL = "http://host.docker.internal:8080"

try:
    response = requests.get(NEXTCLOUD_URL)
    print(f"Nextcloud 연결 성공: {response.status_code}")
except requests.exceptions.ConnectionError:
    print("Nextcloud 연결 실패")

컨테이너 내부에서 curl로 테스트할 때도 마찬가지입니다.

# App-A 컨테이너 내부에서 실행
curl http://host.docker.internal:8080

3. ⚠️ 중요: Linux 호스트 환경 설정

Docker Desktop (macOS, Windows) 사용자는 host.docker.internal이 기본적으로 작동합니다.

하지만 Linux 호스트 환경에서는 이 설정을 수동으로 추가해야 합니다. host-gateway라는 특수 키워드를 사용하여 호스트 IP를 매핑할 수 있습니다.

방법 1: docker run 사용 시

--add-host 플래그를 추가합니다.

docker run \
  --add-host=host.docker.internal:host-gateway \
  --network network-A \
  my-drf-app-image

방법 2: docker-compose.yml 사용 시

App-A (DRF) 서비스에 extra_hosts를 추가합니다.

services:
  drf-app:
    image: my-drf-app-image
    networks:
      - network-A
    extra_hosts:
      # host.docker.internal을 호스트 머신 IP(host-gateway)로 매핑
      - "host.docker.internal:host-gateway"

# ... (network-A 정의) ...

4. 요약

분리된 도커 네트워크 간 통신 시, 네트워크를 복잡하게 연결할 필요 없습니다.

  1. 호출 대상 컨테이너(Nextcloud)를 호스트 포트(8080)에 바인딩합니다.

  2. 호출하는 컨테이너(DRF)에서 http://host.docker.internal:8080 주소로 요청합니다.

  3. 호스트가 Linux라면, 호출하는 컨테이너에 extra_hosts (host.docker.internal:host-gateway) 설정을 잊지 않고 추가합니다.