[Docker] Communiquer entre conteneurs sans partage de réseau via le port hôte (host.docker.internal)



Tags : Docker, DevOps, Réseau, host.docker.internal

1. Situation problématique

Il est courant de gérer plusieurs services avec Docker dans un environnement de développement.

  • App-A (ex : DRF) est sur network-A.

  • App-B (ex : Nextcloud) est sur network-B.

  • Les deux conteneurs s'exécutent sur la même machine hôte.

  • App-B est lié au port 8080 de l'hôte. (ex : docker run -p 8080:80 ...)

App-A doit appeler App-B via l'API. Je ne veux pas m'embêter à connecter les deux réseaux avec un pont. N'est-il pas possible d'appeler directement le port 8080 de l'hôte ?

Lorsque vous appelez localhost:8080 ou 127.0.0.1:8080 à l'intérieur du conteneur, cela fait référence non pas à la machine hôte mais à lui-même.

2. Solution : host.docker.internal

La solution la plus simple est d'utiliser un nom DNS spécial, host.docker.internal.

host.docker.internal : un nom d'hôte spécial qui est interprété à l'intérieur du conteneur comme l'adresse IP de la machine hôte.

Lorsque vous appelez Nextcloud depuis le code de App-A (DRF), définissez l'URL comme suit.

# Code interne de DRF (App-A)
import requests

# Utilisez 'host.docker.internal' au lieu de 'localhost'.
NEXTCLOUD_URL = "http://host.docker.internal:8080"

try:
    response = requests.get(NEXTCLOUD_URL)
    print(f"Connexion à Nextcloud réussie : {response.status_code}")
except requests.exceptions.ConnectionError:
    print("Échec de la connexion à Nextcloud")

Il en va de même lors du test avec curl à l'intérieur du conteneur.

# À exécuter à l'intérieur du conteneur App-A
curl http://host.docker.internal:8080

3. ⚠️ Important : Configuration de l'environnement hôte Linux

Les utilisateurs de Docker Desktop (macOS, Windows) ont host.docker.internal qui fonctionne par défaut.

Cependant, dans un environnement de machine hôte Linux, vous devez ajouter cette configuration manuellement. Vous pouvez mapper l'IP de l'hôte en utilisant un mot clé spécial appelé host-gateway.

Méthode 1 : En utilisant docker run

Ajoutez le drapeau --add-host.

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

Méthode 2 : En utilisant docker-compose.yml

Ajoutez extra_hosts au service App-A (DRF).

services:
  drf-app:
    image: my-drf-app-image
    networks:
      - network-A
    extra_hosts:
      # Mapper host.docker.internal à l'IP de la machine hôte (host-gateway)
      - "host.docker.internal:host-gateway"

# ... (définition de network-A) ...

4. Résumé

Pour communiquer entre des réseaux Docker séparés, il n'est pas nécessaire de connecter les réseaux de manière complexe.

  1. Mappez le conteneur à appeler (Nextcloud) au port hôte (8080).

  2. Effectuez une requête depuis le conteneur appelant (DRF) à l'adresse http://host.docker.internal:8080.

  3. Si l'hôte est Linux, n'oubliez pas d'ajouter la configuration extra_hosts (host.docker.internal:host-gateway) au conteneur appelant.