Question Depuis l'intérieur d'un conteneur Docker, comment me connecter à l'hôte local de la machine?


J'ai donc un Nginx en cours d'exécution dans un conteneur docker, j'ai un mysql fonctionnant sur localhost, je veux me connecter à MySql depuis mon Nginx. MySql s'exécute sur localhost et n'expose pas un port au monde extérieur, donc il est lié à localhost, pas lié à l'adresse IP de la machine.

Y at-il un moyen de se connecter à ce MySQL ou à tout autre programme sur localhost à partir de ce conteneur docker?


659
2018-06-20 03:54


origine


Réponses:


Modifier: Si vous utilisez Docker-for-mac ou Docker-for-Windows 18.03+, connectez-vous à votre service mysql en utilisant l'hôte host.docker.internal.

À partir de Docker 18.04, cela ne fonctionne pas sur Docker-for-Linux.


TLDR

Utilisation --net="host" dans ton docker run commande, puis 127.0.0.1 dans votre conteneur docker pointe vers votre hôte docker.


Remarque sur les modes de mise en réseau du conteneur docker

Docker vous propose différents modes de mise en réseau lors de l'exécution des conteneurs. Selon le mode que vous choisissez, vous vous connectez différemment à votre base de données MySQL s'exécutant sur l'hôte du docker.

docker run --net = "pont" (par défaut)

Docker crée un pont nommé docker0 par défaut. L'hôte docker et les conteneurs docker ont tous deux une adresse IP sur ce pont.

sur l'hôte Docker, tapez sudo ip addr show docker0 vous aurez une sortie ressemblant à:

[vagrant@docker:~] $ sudo ip addr show docker0
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
    inet 172.17.42.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::5484:7aff:fefe:9799/64 scope link
       valid_lft forever preferred_lft forever

Donc, ici, mon hôte docker a l'adresse IP 172.17.42.1 sur le docker0 interface réseau.

Maintenant, lancez un nouveau conteneur et récupérez un shell: docker run --rm -it ubuntu:trusty bash et dans le type de conteneur ip addr show eth0 pour découvrir comment est configurée son interface réseau principale:

root@e77f6a1b3740:/# ip addr show eth0
863: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 66:32:13:f0:f1:e3 brd ff:ff:ff:ff:ff:ff
    inet 172.17.1.192/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::6432:13ff:fef0:f1e3/64 scope link
       valid_lft forever preferred_lft forever

Ici mon conteneur a l'adresse IP 172.17.1.192. Maintenant, regardez la table de routage:

root@e77f6a1b3740:/# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.17.42.1     0.0.0.0         UG    0      0        0 eth0
172.17.0.0      *               255.255.0.0     U     0      0        0 eth0

Donc, l'adresse IP de l'hôte docker 172.17.42.1 est défini comme route par défaut et accessible depuis votre conteneur.

root@e77f6a1b3740:/# ping 172.17.42.1
PING 172.17.42.1 (172.17.42.1) 56(84) bytes of data.
64 bytes from 172.17.42.1: icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from 172.17.42.1: icmp_seq=2 ttl=64 time=0.201 ms
64 bytes from 172.17.42.1: icmp_seq=3 ttl=64 time=0.116 ms

docker run --net = "hôte"

Vous pouvez également exécuter un conteneur docker avec paramètres réseau définis sur host. Un tel conteneur partagera la pile réseau avec l'hôte docker et du point de vue du conteneur, localhost (ou 127.0.0.1) se référera à l'hôte du docker.

Sachez que tout port ouvert dans votre conteneur docker sera ouvert sur l'hôte docker. Et ceci sans exiger le -p ou -P  docker run option.

Config IP sur mon hôte docker:

[vagrant@docker:~] $ ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:98:dc:aa brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe98:dcaa/64 scope link
       valid_lft forever preferred_lft forever

et d'un conteneur docker dans hôte mode:

[vagrant@docker:~] $ docker run --rm -it --net=host ubuntu:trusty ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:98:dc:aa brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe98:dcaa/64 scope link
       valid_lft forever preferred_lft forever

Comme vous pouvez le voir, l'hôte docker et le conteneur docker partagent exactement la même interface réseau et ont donc la même adresse IP.


Connexion à MySQL à partir de conteneurs

mode pont

Pour accéder à MySQL s'exécutant sur l'hôte docker à partir de conteneurs dans mode pont, vous devez vous assurer que le service MySQL est à l'écoute des connexions sur le 172.17.42.1 Adresse IP.

Pour ce faire, assurez-vous d'avoir bind-address = 172.17.42.1 ou bind-address = 0.0.0.0 dans votre fichier de configuration MySQL (my.cnf).

Si vous devez définir une variable d'environnement avec l'adresse IP de la passerelle, vous pouvez exécuter le code suivant dans un conteneur:

export DOCKER_HOST_IP=$(route -n | awk '/UG[ \t]/{print $2}')

puis dans votre application, utilisez le DOCKER_HOST_IP variable d'environnement pour ouvrir la connexion à MySQL.

Remarque: si tu utilises bind-address = 0.0.0.0 votre serveur MySQL écoutera les connexions sur toutes les interfaces réseau. Cela signifie que votre serveur MySQL pourrait être atteint à partir d'Internet; assurez-vous de configurer les règles de pare-feu en conséquence.

Note 2: si tu utilises bind-address = 172.17.42.1 votre serveur MySQL n'écoutera pas les connexions faites à 127.0.0.1. Les processus s'exécutant sur l'hôte du docker qui voudraient se connecter à MySQL devraient utiliser le 172.17.42.1 Adresse IP.

mode hôte

Pour accéder à MySQL s'exécutant sur l'hôte docker à partir de conteneurs dans mode hôte, tu peux garder bind-address = 127.0.0.1 dans votre configuration MySQL et tout ce que vous devez faire est de se connecter à 127.0.0.1 de vos conteneurs:

[vagrant@docker:~] $ docker run --rm -it --net=host mysql mysql -h 127.0.0.1 -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 36
Server version: 5.5.41-0ubuntu0.14.04.1 (Ubuntu)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

Remarque: Utiliser mysql -h 127.0.0.1 et pas mysql -h localhost; sinon, le client MySQL essaierait de se connecter en utilisant un socket unix.


962
2018-06-20 11:46



Pour macOS et Windows

Docker v 18.03 et au-dessus (depuis le 21 mars 2018)

Utilisez votre adresse IP interne ou connectez-vous au nom DNS spécial host.docker.internal qui se résoudra à l'adresse IP interne utilisée par l'hôte.

Support Linux en attente https://github.com/docker/for-linux/issues/264

MacOS avec les versions antérieures de Docker

Docker pour Mac v 17.12 à v 18.02

Idem que ci-dessus mais utilisez docker.for.mac.host.internal au lieu.

Docker pour Mac v 17.06 à v 17.11

Idem que ci-dessus mais utilisez docker.for.mac.localhost au lieu.

Docker pour Mac 17.05 et ci-dessous

Pour accéder à la machine hôte à partir du conteneur docker, vous devez attacher un alias IP à votre interface réseau. Vous pouvez lier n'importe quelle adresse IP, assurez-vous de ne pas l'utiliser pour autre chose.

sudo ifconfig lo0 alias 123.123.123.123/24 

Ensuite, assurez-vous que votre serveur écoute l'IP mentionné ci-dessus ou 0.0.0.0. Si ça écoute sur localhost 127.0.0.1 il n'acceptera pas la connexion.

Ensuite, pointez simplement votre conteneur docker sur cette adresse IP et vous pourrez accéder à la machine hôte!

Pour tester, vous pouvez exécuter quelque chose comme curl -X GET 123.123.123.123:3000 à l'intérieur du conteneur.

L'alias sera réinitialisé à chaque redémarrage afin de créer un script de démarrage si nécessaire.

Solution et plus de documentation ici: https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds


197
2018-04-21 11:33



Je fais un hack similaire aux messages ci-dessus pour obtenir l'adresse IP locale à mapper à un nom d'alias (DNS) dans le conteneur. Le problème majeur est d'obtenir dynamiquement avec un script simple qui fonctionne à la fois dans Linux et OSX l'adresse IP de l'hôte. J'ai fait ce script qui fonctionne dans les deux environnements (même dans la distribution Linux avec "$LANG" != "en_*" configuré):

ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1

Donc, en utilisant Docker Compose, la configuration complète sera:

Script de démarrage (docker-run.sh):

export DOCKERHOST=$(ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1)
docker-compose -f docker-compose.yml up

docker-compose.yml:

myapp:
  build: .
  ports:
    - "80:80"
  extra_hosts:
    - "dockerhost:$DOCKERHOST"

Ensuite, changez http://localhost à http://dockerhost dans votre code.

Pour un guide plus détaillé de la façon de personnaliser le DOCKERHOST script, jetez un oeil à ce post avec une explication de comment cela fonctionne.


48
2017-08-03 21:30



Cela a fonctionné pour moi sur une pile NGINX / PHP-FPM sans toucher à aucun code ou réseau où l'application s'attendait à pouvoir se connecter à localhost

Monter mysqld.sock de l'hôte à l'intérieur du conteneur.

Recherchez l'emplacement du fichier mysql.sock sur l'hôte exécutant mysql:
netstat -ln | awk '/mysql(.*)?\.sock/ { print $9 }'

Montez ce fichier là où il est attendu dans le docker:
docker run -v /hostpath/to/mysqld.sock:/containerpath/to/mysqld.sock

Emplacements possibles de mysqld.sock:

/tmp/mysqld.sock
/var/run/mysqld/mysqld.sock 
/var/lib/mysql/mysql.sock
/Applications/MAMP/tmp/mysql/mysql.sock # if running via MAMP

29
2018-05-27 13:36



Pour ceux sur Windows, en supposant que vous utilisez le pilote réseau pont, vous devez lier spécifiquement MySQL à l'adresse IP de l'interface réseau hyper-v.

Ceci est fait via le fichier de configuration sous le dossier C: \ ProgramData \ MySQL normalement caché.

La liaison à 0.0.0.0 ne fonctionnera pas. L'adresse requise est également affichée dans la configuration du docker, et dans mon cas c'était 10.0.75.1.


8
2017-12-10 15:53



Solution pour Windows 10

Docker Community Edition 17.06.0-ce-win18 2017-06-28 (stable)

Vous pouvez utiliser le nom DNS de l'hôte docker.for.win.localhost, pour résoudre l'IP interne. (Avertissement certaines sources mentionnées windows mais il devrait être win)

Aperçu
Je devais faire quelque chose de similaire, c'est-à-dire se connecter de mon conteneur Docker à mon localhost, qui fonctionnait Azure Storage Emulator et CosmosDB Emulator.

le Azure Storage Emulator par défaut écoute sur 127.0.0.1, alors que vous pouvez changer l'adresse IP aussi, je cherchais une solution qui fonctionnerait avec les paramètres par défaut.

Cela fonctionne également pour la connexion de mon conteneur Docker à SQL Server et IIS, tous deux s'exécutant localement sur mon hôte avec les paramètres de port par défaut.


8
2017-11-09 10:49



Edit: J'ai fini par prototyper le concept sur GitHub. Check-out:  https://github.com/sivabudh/system-in-a-box


Tout d'abord, ma réponse est orientée vers 2 groupes de personnes: ceux qui utilisent un Mac, et ceux qui utilisent Linux.

le hôte Le mode réseau ne fonctionne pas sur un Mac. Vous devez utiliser un alias IP, voir: https://stackoverflow.com/a/43541681/2713729

Qu'est-ce qu'un mode réseau hôte? Voir: https://docs.docker.com/engine/reference/run/#/network-settings

Deuxièmement, pour ceux d'entre vous qui utilisent Linux (mon expérience directe était avec Ubuntu 14.04 LTS et je suis en train de passer à 16.04 LTS en production bientôt), Oui, vous pouvez connecter le service à l'intérieur d'un conteneur Docker localhost services fonctionnant sur l'hôte Docker (par exemple, votre ordinateur portable).

Comment?

La clé est lorsque vous exécutez le conteneur Docker, vous devez l'exécuter avec le hôte mode. La commande ressemble à ceci:

docker run --network="host" -id <Docker image ID>

Quand tu fais un ifconfig (tu devras apt-get install net-tools votre récipient pour ifconfig pour être appelable) à l'intérieur de votre conteneur, vous verrez que les interfaces réseau sont les mêmes que sur l'hôte Docker (par exemple votre ordinateur portable).

Il est important de noter que je suis un utilisateur de Mac, mais je cours sous Ubuntu sous Parallels, donc l'utilisation d'un Mac n'est pas un inconvénient. ;-)

Et c'est ainsi que vous connectez le conteneur NGINX à MySQL en cours d'exécution sur un localhost.


7
2018-02-07 07:15



Solution pour Linux (noyau> = 3.6).

Ok, votre serveur localhost a une interface docker par défaut docker0 avec adresse ip 172.17.0.1. Votre conteneur a démarré avec les paramètres réseau par défaut --net = "pont".

  1. Activer route_localnet pour l'interface docker0:
    $ sysctl -w net.ipv4.conf.docker0.route_localnet=1
  2. Ajoutez ces règles à iptables:
    $ iptables -t nat -I PREROUTING -i docker0 -d 172.17.0.1 -p tcp --dport 3306 -j DNAT --to 127.0.0.1:3306
    $ iptables -t filter -I INPUT -i docker0 -d 127.0.0.1 -p tcp --dport 3306 -j ACCEPT
  3. Créer un utilisateur mysql avec un accès à partir de '%' qui signifie - de n'importe qui, à l'exclusion de localhost:
    CREATE USER 'user'@'%' IDENTIFIED BY 'password';
  4. Changez dans votre script l'adresse mysql-server en 172.17.0.1


Du documentation du noyau:

route_localnet - BOOLEAN: Ne considère pas les adresses de bouclage comme source ou destination martienne pendant le routage. Cela permet l'utilisation de 127/8 à des fins de routage local (FAUX par défaut).


7
2017-09-27 13:22



Je ne suis pas d'accord avec la réponse de Thomasleveil.

Rendre mysql bind à 172.17.42.1 empêchera d'autres programmes utilisant la base de données sur l'hôte de l'atteindre. Cela ne fonctionnera que si tous les utilisateurs de votre base de données sont dockerisés.

Rendre mysql bind à 0.0.0.0 ouvrira le db au monde extérieur, ce qui est non seulement une très mauvaise chose à faire, mais aussi contraire à ce que l'auteur de la question originale veut faire. Il dit explicitement que "MySql fonctionne sur localhost et n'expose pas un port au monde extérieur, donc c'est lié à localhost"

Pour répondre au commentaire de ivant

"Pourquoi ne pas lier mysql à docker0 aussi?"

Ce n'est pas possible. La documentation mysql / mariadb indique explicitement qu'il n'est pas possible de lier plusieurs interfaces. Vous pouvez uniquement lier à 0, 1 ou toutes les interfaces.

En conclusion, je n'ai trouvé aucun moyen d'atteindre la base de données (localhost only) sur l'hôte à partir d'un conteneur docker. Cela semble définitivement un modèle très commun, mais je ne sais pas comment le faire.


2
2018-03-12 23:31