[Docker] Comunicar contenedores a través de puertos del host sin compartir red (host.docker.internal)



Etiquetas: Docker, DevOps, Red, host.docker.internal

1. Situación del problema

Es común gestionar múltiples servicios en el entorno de desarrollo utilizando Docker.

  • App-A (por ejemplo: DRF) está en network-A.

  • App-B (por ejemplo: Nextcloud) está en network-B.

  • Ambos contenedores se ejecutan en la misma máquina anfitriona.

  • App-B está vinculado al puerto 8080 del host. (por ejemplo: docker run -p 8080:80 ...)

Necesitamos hacer una llamada API desde App-A a App-B. No queremos complicarnos conectando las dos redes a través de un puente. ¿No podemos llamar directamente al puerto 8080 del host?

Al llamar a localhost:8080 o 127.0.0.1:8080 desde dentro del contenedor, se refiere a sí mismo y no a la máquina anfitriona.

2. Solución: host.docker.internal

La solución más sencilla es usar un nombre DNS especial llamado host.docker.internal.

host.docker.internal: un nombre de host especial que se resuelve a la dirección IP de la máquina anfitriona desde dentro del contenedor.

En el código de App-A (DRF) al hacer la llamada a Nextcloud, configuramos la URL de la siguiente manera.

# Código interno de DRF (App-A)
import requests

# Utilizamos 'host.docker.internal' en vez de 'localhost'.
NEXTCLOUD_URL = "http://host.docker.internal:8080"

try:
    response = requests.get(NEXTCLOUD_URL)
    print(f"Conexión a Nextcloud exitosa: {response.status_code}")
except requests.exceptions.ConnectionError:
    print("Fallo en la conexión a Nextcloud")

Lo mismo ocurre al probar desde dentro del contenedor con curl.

# Ejecutar desde dentro del contenedor de App-A
curl http://host.docker.internal:8080

3. ⚠️ Importante: Configuración del entorno de host de Linux

Los usuarios de Docker Desktop (macOS, Windows) tienen host.docker.internal funcionando por defecto.

Sin embargo, en un entorno de host Linux, esta configuración debe añadirse manualmente. Se puede mapear la IP del host usando una palabra clave especial llamada host-gateway.

Método 1: Al usar docker run

Agregue el flag --add-host.

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

Método 2: Al usar docker-compose.yml

Agregue extra_hosts al servicio de App-A (DRF).

services:
  drf-app:
    image: my-drf-app-image
    networks:
      - network-A
    extra_hosts:
      # Mapee host.docker.internal a la IP de la máquina host (host-gateway)
      - "host.docker.internal:host-gateway"

# ... (definición de network-A) ...

4. Resumen

No es necesario complicar las conexiones de red al comunicar entre redes separadas en Docker.

  1. Vincule el contenedor objetivo (Nextcloud) al puerto del host (8080).

  2. Haga una solicitud desde el contenedor emisor (DRF) a la dirección http://host.docker.internal:8080.

  3. Si el host es Linux, no olvide añadir la configuración de extra_hosts (host.docker.internal:host-gateway) en el contenedor emisor.