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

1455

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

Existe-t-il un moyen de se connecter à ce MySql ou à tout autre programme sur localhost à partir de ce conteneur Docker?

Cette question est différente de "Comment obtenir l'adresse IP de l'hôte docker à l'intérieur d'un conteneur de docker" en raison du fait que l'adresse IP de l'hôte docker peut être l'IP publique ou l'IP privée du réseau qui peut ou non ne pas être accessible à partir du conteneur Docker (je veux dire IP publique si hébergé chez AWS ou quelque chose). Même si vous avez l'adresse IP de l'hôte docker, cela ne signifie pas que vous pouvez vous connecter à l'hôte docker à partir du conteneur étant donné que l'adresse IP de votre réseau Docker peut être superposée, hôte, pont, macvlan, aucune, etc., ce qui restreint l'accessibilité de cette adresse IP.

Phil
la source
Pourquoi ne pas également lier mysql à docker0?
ivant
2
Pour la machine Windows: - $ docker run -d --name MyWebServer -P httpd
Lokesh S
1
Sans cela, network: hostvous ne pouvez pas revenir d'un conteneur à l'hôte. Hôte uniquement au conteneur. C'est la principale idéologie derrière les conteneurs. Ils sont isolés pour des raisons de stabilité et de sécurité.
FreeSoftwareServers

Réponses:

1974

Modifier: si vous utilisez Docker-pour-mac ou Docker-pour-Windows 18.03+, connectez-vous simplement à votre service mysql en utilisant l'hôte host.docker.internal(au lieu de 127.0.0.1dans votre chaîne de connexion).

Depuis Docker 18.09.3, cela ne fonctionne pas sur Docker-for-Linux. Un correctif a été soumis le 8 mars 2019 et sera, espérons-le, fusionné avec la base de code. Jusque-là, une solution consiste à utiliser un conteneur comme décrit dans la réponse de qoomon .

2020-01: certains progrès ont été réalisés. Si tout se passe bien, cela devrait atterrir dans Docker 20.04


TLDR

Utilisez --network="host"dans votre docker runcommande, puis 127.0.0.1dans votre conteneur Docker pointera vers votre hôte Docker.

Remarque: Ce mode ne fonctionne que sur Docker pour Linux, selon la documentation .


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

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

docker run --network = "bridge" (par défaut)

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

sur l'hôte Docker, tapez sudo ip addr show docker0vous 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

Voici donc mon hôte docker a l'adresse IP 172.17.42.1sur ledocker0 interface réseau.

Maintenant, démarrez un nouveau conteneur et obtenez un shell dessus: docker run --rm -it ubuntu:trusty bashet dans le type de conteneur ip addr show eth0pour découvrir comment son interface réseau principale est configurée:

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. Regardez maintenant 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

L'adresse IP de l'hôte docker 172.17.42.1est donc définie comme route par défaut et est accessible à partir de 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 --network = "host"

Vous pouvez également exécuter un conteneur Docker avec les paramètres réseau définis surhost . 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) fera référence à l'hôte docker.

Sachez que tout port ouvert dans votre conteneur Docker serait ouvert sur l'hôte Docker. Et cela sans nécessiter l' option -pou-P docker run .

Configuration 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 à partir d'un conteneur Docker en mode hôte :

[vagrant@docker:~] $ docker run --rm -it --network=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 en tant que tels ont la même adresse IP.


Connexion à MySQL à partir de conteneurs

mode pont

Pour accéder à MySQL exécuté sur l'hôte docker à partir de conteneurs en mode pont , vous devez vous assurer que le service MySQL écoute les connexions sur l' 172.17.42.1adresse IP.

Pour ce faire, assurez-vous que vous avez soit bind-address = 172.17.42.1ou bind-address = 0.0.0.0dans 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 la DOCKER_HOST_IPvariable d'environnement pour ouvrir la connexion à MySQL.

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

Remarque 2: si vous utilisez bind-address = 172.17.42.1votre serveur MySQL, il n'écoutera pas les connexions établies avec 127.0.0.1. Les processus s'exécutant sur l'hôte docker qui voudraient se connecter à MySQL devraient utiliser l' 172.17.42.1adresse IP.

mode hôte

Pour accéder à MySQL exécuté sur l'hôte docker à partir de conteneurs en mode hôte , vous pouvez conserver bind-address = 127.0.0.1votre configuration MySQL et tout ce que vous devez faire est de vous connecter à 127.0.0.1partir de vos conteneurs:

[vagrant@docker:~] $ docker run --rm -it --network=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>

note: utilisez mysql -h 127.0.0.1et non mysql -h localhost; sinon le client MySQL essaierait de se connecter en utilisant un socket unix.

Thomasleveil
la source
8
Merci pour cette réponse si détaillée! D'après ce que j'ai rassemblé, l'utilisation du mode hôte est le seul moyen d'obtenir cette fonctionnalité via localhost. Je n'ai pas essayé mais je suppose que vous pouvez créer un réseau séparé pour connecter les conteneurs sur leur propre pont en leur offrant un «localhost» commun.
Ben
26
Remarque pour les utilisateurs OSX: connectez-vous d'abord à votre machine virtuelle docker (boot2docker), en utilisant "docker-machine ssh default", puis exécutez "sudo ip addr show docker0". Continuez avec les instructions de Thomas à partir de là.
Charlie Dalsass du
30
J'utilise Docker pour Mac, et il n'y a plus de 172.17.42.1, plus de docker0. C'était 172.17.0.1 comme passerelle, et ne peut même pastelnet 172.17.0.1 3306
zx1986
26
Vous pouvez monter le socket mysql dans le conteneur au lieu de mettre en réseau comme -v /var/run/mysqld/mysqld.sock:/tmp/mysql.sockcelui-ci.
chx
8
Quelqu'un peut-il résoudre le problème lorsque vous utilisez Docker sur Mac et que vous n'utilisez pas boot2docker en tant que tel, il n'y a pas d'interface docker0?
TheJKFever, le
350

Pour macOS et Windows

Docker v 18.03 et supérieur (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 en adresse IP interne utilisée par l'hôte.

Prise en charge 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

Identique à ci-dessus mais à utiliser à la docker.for.mac.host.internalplace.

Docker pour Mac v 17.06 à v 17.11

Identique à ci-dessus mais à utiliser à la docker.for.mac.localhostplace.

Docker pour Mac 17.05 et versions antérieures

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

sudo ifconfig lo0 alias 123.123.123.123/24

Assurez-vous ensuite que votre serveur écoute l'IP mentionnée ci-dessus ou 0.0.0.0. S'il écoute sur localhost, 127.0.0.1il n'acceptera pas la connexion.

Il vous suffit ensuite de pointer votre conteneur Docker vers cette 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 se réinitialise à chaque redémarrage, créez donc 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

Janne Annala
la source
5
brillant et merci, cela a fonctionné pour moi de l'intérieur du conteneur. mysql -uroot -hdocker.for.mac.localhost
Richard Frank
1
docker.for.mac.localhost Est exactement ce que je cherchais. Mais c'est sale comme l'enfer en même temps. Dans Docker, on peut s'attendre à ce que le hook docker.for.mac.localhost soit un nom interne de docker générique qui soit valide pour n'importe quel système d'exploitation, pas seulement pour Mac. Mais à des fins de développement, cela suffit.
99Sono
Comment accéder à un port qui est exposé par exemple 9093 .. J'essaie de telnet docker.for.mac.localhost 9093. Son inaccessible mais si je cingle docker.for.mac.localhost, son accessible. Suis-je manquant quelque chose ici?
Achilleus
1
Le nom DNS docker.for.mac.host.internal doit être utilisé à la place de docker.for.mac.localhost (toujours valide) pour la résolution d'hôte à partir des conteneurs, car il existe un RFC interdisant l'utilisation des sous-domaines de localhost. Voir tools.ietf.org/html/draft-west-let-localhost-be-localhost-06 .
Jya
Ça ne marche pas pour moi. Quand je docker run -e HOSTNAME= docker.for.mac.host.internal , le conteneur est créé mais rien ne se passe. Je dois ensuite crtl + C. Avec --net=host -e HOSTNAME=localhostau moins le conteneur s'exécute et se plaint qu'il ne trouve pas le service dont j'ai besoin (MySQL db).
Jorge Orpinel
83

Je fais un hack similaire aux messages ci-dessus pour obtenir l'adresse IP locale à mapper sur un nom d'alias (DNS) dans le conteneur. Le problème majeur est d'obtenir dynamiquement avec un script simple qui fonctionne à la fois sous 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

Ainsi, 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"

Changez ensuite http://localhosten http://dockerhostdans votre code.

Pour un guide plus avancé sur la façon de personnaliser le DOCKERHOSTscript, jetez un œil à cet article avec une explication de son fonctionnement.

Mariano Ruiz
la source
1
Selon votre cas d'utilisation, vous pouvez même vous contenter d'utiliser la DOCKERHOSTvaleur ici au lieu de "localhost" ou 0.0.0.0 dans le service auquel votre conteneur Docker doit se connecter localement.
enderland
2
J'ai légèrement modifié votre solution pour qu'elle soit compatible avec les réseaux personnalisés: export DOCKERHOST=$(docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}}{{end}}' <NETWORK-NAME> | awk -F "/" 'NR==1{print $1}')<NAMEWORK-NAME> pourrait être un pont ou le nom du réseau tel que défini par docker-compose (généralement chemin-nom - nom_réseau ).
dieresys
1
Vous devez ajouter un commentaire: utiliser dockerhostcomme hôte pour la connexion db (remplacer habituellement localhostdans le fichier de configuration).
Justin
solution bizarre, mais c'est la seule qui fait fonctionner xdebug sous docker avec php cli
Eddie
Acl a cessé de fonctionner après cette solution en haproxy. Une idée pourquoi?
HyukHyukBoi
41

Cela a fonctionné pour moi sur une pile NGINX / PHP-FPM sans toucher à aucun code ou réseau où l'application s'attend juste à 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 menu fixe:
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
user833482
la source
2
Il s'agit d'une solution beaucoup plus propre, n'exposant pas Mysql à l'extérieur (si vous n'utilisez pas de pare-feu).
user1226868
5
Les sockets n'évoluent pas aussi bien que TCP car ils bloquent plus souvent et peuvent provoquer des comportements étranges. Utilisez TCP autant que possible.
Joel E Salas
3
@JoelESalas Avez-vous une source pour cette réclamation?
Privé
J'ai trouvé que c'était la solution la plus simple. Bravo user833482! Vous devriez contribuer plus souvent à StackOverflow.
Privé
2
@JoelESalas Je pense que vous vous trompez. La bibliothèque cliente mysql utilise même des sockets unix par défaut lors de la connexion à localhost plutôt que d'établir une connexion à localhost. Un socket Unix évite la surcharge de la pile TCP et du routage, et devrait s'exécuter plus rapidement.
M Conrad
25

Jusqu'à host.docker.internal fonctionne pour chaque plate-forme, vous pouvez utiliser mon conteneur agissant comme une passerelle NAT sans aucune configuration manuelle:

https://github.com/qoomon/docker-host

qoomon
la source
5
Je peux confirmer que cela ne fonctionne pas dans Docker pour Windows 19.03.2 avec le conteneur Windows.
KMC
une idée de comment résoudre ce problème? (Je ne suis pas un utilisateur Windows)
qoomon
Si votre environnement ne bloque pas le port utilisé par mysql, vous pouvez vous référer au serveur par le nom de l'ordinateur qu'il héberge. Donc, dans votre chaîne de connexion, utilisez le nom de votre ordinateur comme nom de serveur.
KMC
24

Solution pour Linux (noyau> = 3.6).

Ok, votre serveur localhost a une interface docker par défaut docker0 avec l'adresse IP 172.17.0.1 . Votre conteneur a commencé avec les paramètres réseau par défaut --net = "bridge" .

  1. Activez 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éez un utilisateur mysql avec un accès à partir de '%', ce 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


De la documentation du noyau :

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

Ray D
la source
1
Quel est le but de la deuxième commande iptable? Je peux comprendre que la première consiste à réécrire toutes les destinations tcp qui correspondent à 172.17.0.1:3306 à 127.0.0.1:3306, mais pourquoi la deuxième commande iptable est-elle nécessaire?
Patrick
17

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'adresse IP interne. (Attention à certaines sources mentionnées windowsmais cela devrait êtrewin )

Présentation
J'avais besoin de faire quelque chose de similaire, c'est-à-dire de me connecter de mon conteneur Docker à mon hôte local, qui exécutait le Azure Storage Emulatoret CosmosDB Emulator.

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

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

Ralph Willgoss
la source
13

Très simple et rapide, vérifiez votre IP hôte avec ifconfig (linux) ou ipconfig (windows) puis créez un

docker-compose.yml

version: '3' # specify docker-compose version

services:
  nginx:
    build: ./ # specify the directory of the Dockerfile
    ports:
      - "8080:80" # specify port mapping
    extra_hosts:
      - "dockerhost:<yourIP>"

De cette façon, votre conteneur pourra accéder à votre hôte. Lorsque vous accédez à votre base de données, n'oubliez pas d'utiliser le nom que vous avez spécifié auparavant, dans ce cas "dockerhost" et le port de votre hôte dans lequel la base de données s'exécute

Felipe Toledo
la source
Dans HaProxy, cette solution a cessé de fonctionner sur les acl pour une raison quelconque, seul le paramètre par défaut fonctionne.
HyukHyukBoi
1
La seule solution qui fonctionne sur un système Linux. +1
Rafik Farhad
11

Aucune des réponses n'a fonctionné pour moi lors de l'utilisation de Docker Toolbox sur Windows 10 Home, mais 10.0.2.2 l'a fait, car il utilise VirtualBox qui expose l'hôte à la machine virtuelle sur cette adresse.

Elad
la source
2
Ça marche. Même pas besoin de spécifier --network = host. ressemble à 10.0.2.2 est défini comme IP par défaut pour l'hôte. Merci.
TheManish
Mais, puis-je utiliser cette adresse IP statique pour toutes les versions de Windows et Mac?, Comment puis-je la gérer pour plusieurs plates-formes via un script?
151291
Cela a fonctionné pour moi. Exécutez simplement ipconfig sur votre hôte (Windows) et obtenez l'adresse IP sousEthernet adapter vEthernet (DockerNAT)
Kihats
10

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

Cela se fait via le fichier de configuration dans le dossier C: \ ProgramData \ MySQL normalement caché.

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

Casey
la source
3
Vous méritez une médaille! J'y travaille depuis deux jours entiers. Merci d'avoir aidé!
Michael
1
J'y ai également travaillé pendant deux jours complets. C'est le seul endroit sur le Web que j'ai trouvé mentionné. Microsoft est complètement silencieux à ce sujet lorsqu'il parle de se connecter à MSSQL à partir d'un conteneur Docker. Cela vous fait vous demander s'ils l'ont déjà fait fonctionner eux-mêmes!
Contango
8

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 s'adresse à 2 groupes de personnes: ceux qui utilisent un Mac et ceux qui utilisent Linux.

Le mode réseau hôte 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 avec Ubuntu 14.04 LTS et je passe bientôt à 16.04 LTS en production), oui , vous pouvez faire en sorte que le service fonctionnant dans un conteneur Docker se connecte àlocalhost services exécutés sur le Hôte Docker (par exemple, votre ordinateur portable).

Comment?

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

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

Lorsque vous faites un ifconfig(vous aurez besoin de apt-get install net-toolsvotre conteneur pour ifconfigêtre appelable) à l'intérieur de votre conteneur, vous verrez que les interfaces réseau sont les mêmes que celles sur l'hôte Docker (par exemple, votre ordinateur portable).

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

Et voici comment vous connectez le conteneur NGINX au MySQL fonctionnant sur un localhost.

sivabudh
la source
1
Il est important de noter que le mode hôte offre de meilleures performances car il utilise la pile réseau du système d'exploitation.
sivabudh
2
Très bon point là-bas. Bien qu'il soit possible de se connecter d'un conteneur à un service hôte avec l'attachement IP inutilisé docs.docker.com/docker-for-mac/networking . Pas une solution agréable ... mais ça marche.
Xavier Huppé
De bonnes choses ici. Une fois à l'intérieur du conteneur avec --network="host", comment se connecter à l'hôte mysql par exemple?
Michael
1
@Buccleuch Il suffit d'utiliser localhost. Consultez mon code source GitHub: github.com/sivabudh/system-in-a-box/blob/master/dj_host_docker/… . Recherchez 'HOST', vous verrez 127.0.0.1 pour vous connecter à Postgresql.
sivabudh
J'ai pu accéder aux bases de données mysql de l'hôte en montant le volume selon @ user833482, et après avoir installé mysql-client et serveur sur le conteneur docker bien sûr.
Michael
7

Solution la plus simple pour Mac OSX

Utilisez simplement l'adresse IP de votre Mac. Sur le Mac, exécutez ceci pour obtenir l'adresse IP et l'utiliser à partir du conteneur:

$ ifconfig | grep 'inet 192'| awk '{ print $2}'

Tant que le serveur s'exécutant localement sur votre Mac ou dans un autre conteneur Docker écoute 0.0.0.0, le conteneur Docker pourra atteindre cette adresse.

Si vous voulez simplement accéder à un autre conteneur docker qui écoute sur 0.0.0.0, vous pouvez utiliser 172.17.0.1

dansalmo
la source
1
Docker pour Mac expose docker.for.mac.host.internalmaintenant le nom d'hôte.
Matt
5

Ce n'est pas une réponse à la vraie question. C'est ainsi que j'ai résolu un problème similaire. La solution vient totalement de: Définir la mise en réseau de conteneurs Docker pour que les conteneurs puissent communiquer . Merci à Nic Raboy

Laissant ceci ici pour ceux qui pourraient vouloir faire des appels REST entre un conteneur et un autre. Répond à la question: quoi utiliser à la place de localhost dans un environnement docker?

Découvrez à quoi ressemble votre réseau docker network ls

Créer un nouveau réseau docker network create -d my-net

Démarrer le premier conteneur docker run -d -p 5000:5000 --network="my-net" --name "first_container" <MyImage1:v0.1>

Vérifiez les paramètres réseau du premier conteneur docker inspect first_container. "Réseaux": devrait avoir 'my-net'

Démarrer le deuxième conteneur docker run -d -p 6000:6000 --network="my-net" --name "second_container" <MyImage2:v0.1>

Vérifiez les paramètres réseau pour le deuxième conteneur docker inspect second_container. "Réseaux": devrait avoir 'my-net'

ssh dans votre deuxième conteneur docker exec -it second_container shoudocker exec -it second_container bash .

À l'intérieur du deuxième conteneur, vous pouvez envoyer une requête ping au premier conteneur par ping first_container. De plus, vos appels de code tels que ceux qui http://localhost:5000peuvent être remplacés parhttp://first_container:5000

Shirish Hirekodi
la source
Exactement ce que je cherchais. Remerciements: D
Simar Singh
5

Pour les fenêtres,

J'ai changé l'URL de la base de données dans la configuration du printemps: spring.datasource.url=jdbc:postgresql://host.docker.internal:5432/apidb

Ensuite, créez l'image et exécutez. Ça a marché pour moi.

Praveenkumar Beedanal
la source
intéressant ....
Phil
pour moi ça ne marche pas. J'ai un mac et j'essaie depuis un conteneur php de me connecter à myshl localhost. Une idée ?
A. Zalonis
4

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

Rendre mysql lié à 172.17.42.1 empêchera d'autres programmes d'utiliser la base de données sur l'hôte pour y accéder. Cela ne fonctionnera que si tous les utilisateurs de votre base de données sont ancrés.

Rendre mysql lié à 0.0.0.0 ouvrira la base de données 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 d'origine veut faire. Il dit explicitement "Le MySql fonctionne sur localhost et n'expose pas un port au monde extérieur, donc il est lié sur localhost"

Répondre au commentaire d'ivant

"Pourquoi ne pas lier mysql à docker0 également?"

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

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

orzel
la source
4
à partir de l'hôte docker, vous pouvez toujours vous connecter au serveur MySQL en utilisant l' 172.17.42.1adresse. Mais votre note est juste autrement. Aussi, j'ai édité ma réponse avec le hostmode réseau qui permet de garder le serveur MySQL lié 127.0.0.1tout en permettant aux conteneurs de s'y connecter
Thomasleveil
non, comme je l'ai dit, vous ne pouvez pas vous connecter à 172.17.42.1 si mysql est lié à localhost.
orzel
4
"Rendre mysql lié à 172.17.42.1 empêchera d'autres programmes d'utiliser la base de données sur l'hôte pour y accéder." - ce n'est pas vrai. D'autres programmes peuvent utiliser mysql, ils n'ont qu'à se connecter à 172.17.42.1 au lieu de localhost / 127.0.0.1.
0x89
La solution au problème dans cette réponse consiste généralement à obtenir le serveur MySQL à se lier à 0.0.0.0, puis à configurer un pare-feu afin que la base de données ne soit pas accessible depuis Internet.
halfer
4

Voici ma solution: cela fonctionne pour mon cas

  • mettre le serveur mysql local en accès public en commentant #bind-address = 127.0.0.1 dans /etc/mysql/mysql.conf.d

  • redémarrer le serveur mysql sudo /etc/init.d/mysql restart

  • exécutez la commande suivante pour ouvrir l'accès root de l'utilisateur à tout hôte mysql -uroot -proot GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES;

  • créer un script sh: run_docker.sh

    #! bin / bash

    HOSTIP = `ip -4 addr show scope global dev eth0 | grep inet | awk '{print \ $ 2}' | cut -d / -f 1`


      docker run -it -d --name web-app \
                  --add-host = local: $ {HOSTIP} \
                  -p 8080: 8080 \
                  -e DATABASE_HOST = $ {HOSTIP} \
                  -e DATABASE_PORT = 3306 \
                  -e DATABASE_NAME = démo \
                  -e DATABASE_USER = root \
                  -e DATABASE_PASSWORD = root \
                  sopheamak / springboot_docker_mysql

  
  • courir avec docker-composer

    version: '2.1'

    prestations de service:
    tomcatwar: extra_hosts: - "local: 10.1.2.232" image: sopheamak / springboot_docker_mysql
    ports: - 8080: 8080 environnement: - DATABASE_HOST = local - DATABASE_USER = root - DATABASE_PASSWORD = root - DATABASE_NAME = démo - DATABASE_PORT = 3306

sopheamak
la source
4

Plusieurs solutions viennent à l'esprit:

  1. Déplacez d'abord vos dépendances dans des conteneurs
  2. Rendez vos autres services accessibles en externe et connectez-vous avec cette IP externe
  3. Exécutez vos conteneurs sans isolation du réseau
  4. Évitez de vous connecter via le réseau, utilisez plutôt une prise montée en tant que volume

La raison pour laquelle cela ne fonctionne pas est que les conteneurs s'exécutent avec leur propre espace de noms réseau par défaut. Cela signifie que localhost (ou 127.0.0.1 pointant vers l'interface de bouclage) est unique par conteneur. La connexion à ceci se connectera au conteneur lui-même, et non aux services exécutés à l'extérieur de docker ou à l'intérieur d'un conteneur de docker différent.

Option 1 : si votre dépendance peut être déplacée dans un conteneur, je le ferais en premier. Il rend votre pile d'applications portable tandis que d'autres essaient d'exécuter votre conteneur sur leur propre environnement. Et vous pouvez toujours publier le port sur votre hôte où d'autres services qui n'ont pas été migrés peuvent toujours l'atteindre. Vous pouvez même publier le port sur l'interface localhost sur votre hôte docker pour éviter qu'il ne soit accessible de l'extérieur avec une syntaxe comme: -p 127.0.0.1:3306:3306pour le port publié.

Option 2 : Il existe différentes manières de détecter l'adresse IP de l'hôte depuis l'intérieur du conteneur, mais chacune a un nombre limité de scénarios où elle fonctionne (par exemple, nécessitant Docker pour Mac). L'option la plus portable consiste à injecter votre adresse IP hôte dans le conteneur avec quelque chose comme une variable d'environnement ou un fichier de configuration, par exemple:

docker run --rm -e "HOST_IP=$(ip r s 0/0 | awk '{print $3}')" ...

Cela nécessite que votre service écoute sur cette interface externe, ce qui pourrait être un problème de sécurité. Pour d'autres méthodes pour obtenir l'adresse IP de l'hôte à l'intérieur du conteneur, consultez ce post .

Option 3 : l'exécution sans isolation du réseau, c'est-à-dire l'exécution avec --net host, signifie que votre application s'exécute sur l'espace de noms du réseau hôte. Il s'agit d'une isolation moindre pour le conteneur et cela signifie que vous ne pouvez pas accéder à d'autres conteneurs sur un réseau de docker partagé avec DNS (à la place, vous devez utiliser des ports publiés pour accéder à d'autres applications conteneurisées). Mais pour les applications qui ont besoin d'accéder à d'autres services sur l'hôte qui n'écoutent que 127.0.0.1sur l'hôte, cela peut être l'option la plus simple.

Option 4 : divers services permettent également d'accéder à un socket basé sur un système de fichiers. Ce socket peut être monté dans le conteneur en tant que volume monté de liaison, vous permettant d'accéder au service hôte sans passer par le réseau. Pour accéder au moteur Docker, vous voyez souvent des exemples de montage /var/run/docker.sockdans le conteneur (donnant à ce conteneur un accès racine à l'hôte). Avec mysql, vous pouvez essayer quelque chose comme -v /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysql.sock, puis vous connecter à localhostquel mysql se convertit en utilisant le socket.

BMitch
la source
3

Vous pouvez obtenir l'adresse IP de l'hôte en utilisant une image alpine

docker run --rm alpine ip route | awk 'NR==1 {print $3}'

Ce serait plus cohérent car vous utilisez toujours alpine pour exécuter la commande.

Semblable à la réponse de Mariano, vous pouvez utiliser la même commande pour définir une variable d'environnement

DOCKER_HOST=$(docker run --rm alpine ip route | awk 'NR==1 {print $3}') docker-compose up
hasnat
la source
3

Pour Linux, où vous ne pouvez pas modifier l'interface à laquelle le service localhost se lie

Il y a deux problèmes que nous devons résoudre

  1. Obtenir l'IP de l'hôte
  2. Rendre notre service localhost disponible à Docker

Le premier problème peut être résolu en utilisant qoomon docker-host , comme indiqué par d'autres réponses.

Vous devrez ajouter ce conteneur au même réseau de pont que votre autre conteneur pour pouvoir y accéder. Ouvrez un terminal à l'intérieur de votre conteneur et assurez-vous que vous pouvez cinglerdockerhost .

bash-5.0# ping dockerhost
PING dockerhost (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.523 ms

Maintenant, le problème le plus difficile, rendre le service accessible à docker.

Nous pouvons utiliser telnet pour vérifier si nous pouvons accéder à un port sur l'hôte (vous devrez peut-être l'installer).

Le problème est que notre conteneur ne pourra accéder qu'aux services qui se lient à toutes les interfaces, comme SSH:

bash-5.0# telnet dockerhost 22
SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3

Mais les services liés uniquement à localhost seront inaccessibles:

bash-5.0# telnet dockerhost 1025
telnet: can't connect to remote host (172.20.0.2): Connection refused

La bonne solution ici serait de lier le service au réseau de dockers bridge. Cependant, cette réponse suppose qu'il n'est pas possible pour vous de changer cela. Nous allons donc utiliser à la place iptables.

Tout d'abord, nous devons trouver le nom du réseau de pont avec lequel docker utilise ifconfig. Si vous utilisez un pont sans nom, ce sera juste le cas docker0. Cependant, si vous utilisez un réseau nommé, un pont commençant par br-ce docker sera utilisé à la place. Le mien l'est br-5cd80298d6f4.

Une fois que nous avons le nom de ce pont, nous devons autoriser le routage de ce pont vers localhost. Ceci est désactivé par défaut pour des raisons de sécurité:

sysctl -w net.ipv4.conf.<bridge_name>.route_localnet=1

Maintenant, pour configurer notre iptablesrègle. Étant donné que notre conteneur ne peut accéder qu'aux ports du réseau Docker Bridge, nous allons prétendre que notre service est réellement lié à un port de ce réseau.

Pour ce faire, nous transmettrons toutes les demandes <docker_bridge>:portàlocalhost:port

iptables -t nat -A PREROUTING -p tcp -i <docker_bridge_name> --dport <service_port> -j DNAT --to-destination 127.0.0.1:<service_port>

Par exemple, pour mon service sur le port 1025

iptables -t nat -A PREROUTING -p tcp -i br-5cd80298d6f4 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025

Vous devriez maintenant pouvoir accéder à votre service à partir du conteneur:

bash-5.0# telnet dockerhost 1025
220 127.0.0.1 ESMTP Service Ready
JShorthouse
la source
1
C'est la même chose que ce que @ ray-d a mentionné ci-dessus, mais est bien expliqué. Je vous remercie! De plus, lors de l'utilisation de docker-compose, j'ai également dû ajouter une règle DNAT dans la chaîne PREROUTING pour tous les paquets arrivant sur l'interface docker0: car, docker-compose semble utiliser docker0 lors des générations (pas pendant les exécutions, de manière surprenante): sysctl -w net.ipv4.conf.docker0.route_localnet=1etiptables -t nat -A PREROUTING -p tcp -i docker0 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025
arvindd
3

Vous devez connaître la passerelle ! Ma solution avec le serveur local était de l'exposer sous 0.0.0.0:8000, puis d'exécuter le docker avec le sous - réseau et d' exécuter le conteneur comme:

docker network create --subnet=172.35.0.0/16 --gateway 172.35.0.1 SUBNET35
docker run -d -p 4444:4444 --net SUBNET35 <container-you-want-run-place-here>

Vous pouvez maintenant accéder à votre bouclage via http://172.35.0.1:8000

kirill .z
la source
3

Essaye ça:

version: '3.5'
services:
  yourservice-here:
    container_name: container_name
    ports:
      - "4000:4000"
    extra_hosts: # <---- here
      - localhost:192.168.1.202
      - or-vitualhost.local:192.168.1.202

Pour obtenir 192.168.1.202, utiliseifconfig

Cela a fonctionné pour moi. J'espère que cette aide!

Binh Ho
la source
2

Les CGroups et les espaces de noms jouent un rôle majeur dans l'écosystème de conteneurs.

L'espace de noms fournit une couche d'isolement. Chaque conteneur s'exécute dans un espace de noms distinct et son accès est limité à cet espace de noms. Les groupes de contrôle contrôlent l'utilisation des ressources de chaque conteneur, tandis que l'espace de noms contrôle ce qu'un processus peut voir et accéder à la ressource respective.

Voici la compréhension de base de l'approche de solution que vous pourriez suivre,

Utiliser l'espace de noms réseau

Lorsqu'un conteneur sort de l'image, une interface réseau est définie et créée. Cela donne au conteneur une adresse IP et une interface uniques.

$ docker run -it alpine ifconfig

En changeant l'espace de noms en hôte, les réseaux cotainers ne restent pas isolés de son interface, le processus aura accès à l'interface réseau des machines hôtes.

$ docker run -it --net=host alpine ifconfig

Si le processus écoute sur les ports, ils seront écoutés sur l'interface hôte et mappés sur le conteneur.

Utiliser l'espace de noms PID En modifiant l' espace de noms PID, un conteneur peut interagir avec d'autres processus au-delà de sa portée normale.

Ce conteneur s'exécutera dans son propre espace de noms.

$ docker run -it alpine ps aux

En changeant l'espace de noms en hôte, le conteneur peut également voir tous les autres processus en cours d'exécution sur le système.

$ docker run -it --pid=host alpine ps aux

Partage de l'espace de noms

C'est une mauvaise pratique de le faire en production, car vous sortez du modèle de sécurité du conteneur, ce qui pourrait ouvrir des vulnérabilités et un accès facile à l'écoute clandestine. C'est uniquement pour les outils de débogage et pour minimiser les failles dans la sécurité des conteneurs.

Le premier conteneur est le serveur nginx. Cela créera un nouveau réseau et traitera l'espace de noms. Ce conteneur se liera au port 80 de l'interface réseau nouvellement créée.

$ docker run -d --name http nginx:alpine

Un autre conteneur peut désormais réutiliser cet espace de noms,

$ docker run --net=container:http mohan08p/curl curl -s localhost

En outre, ce conteneur peut voir l'interface avec les processus dans un conteneur partagé.

$ docker run --pid=container:http alpine ps aux

Cela vous permettra d'accorder plus de privilèges aux conteneurs sans modifier ni redémarrer l'application. De la même manière, vous pouvez vous connecter à mysql sur l'hôte, exécuter et déboguer votre application. Mais, ce n'est pas recommandé de suivre cette voie. J'espère que cela aide.

mohan08p
la source
1

Pour Windows Machine: -

Exécutez la commande ci-dessous pour exposer le port docker de manière aléatoire pendant la construction

$docker run -d --name MyWebServer -P mediawiki

entrez la description de l'image ici

entrez la description de l'image ici

Dans la liste de conteneurs ci-dessus, vous pouvez voir le port affecté comme 32768. Essayez d'accéder

localhost:32768 

Vous pouvez voir la page mediawiki

Lokesh S
la source
5
Bien que cette réponse puisse fournir des informations utiles à certains utilisateurs, ce n'est pas la bonne solution ! Il s'agit d'accéder à un service exécuté dans le conteneur depuis la machine hôte. La question, cependant, concernait l'accès à un service exécuté sur l'hôte à partir du conteneur.
einjohn
1

Jusqu'à ce que le correctif ne soit pas fusionné dans la masterbranche, pour obtenir l'adresse IP de l'hôte, il suffit de l'exécuter à l'intérieur du conteneur:

ip -4 route list match 0/0 | cut -d' ' -f3

(comme suggéré par @Mahoney ici ).

patryk.beza
la source
1

Je l'ai résolu en créant un utilisateur dans MySQL pour l'ip du conteneur:

$ sudo mysql<br>
mysql> create user 'username'@'172.17.0.2' identified by 'password';<br>
Query OK, 0 rows affected (0.00 sec)

mysql> grant all privileges on database_name.* to 'username'@'172.17.0.2' with grant option;<br>
Query OK, 0 rows affected (0.00 sec)

$ sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
<br>bind-address        = 172.17.0.1

$ sudo systemctl restart mysql.service

Puis sur conteneur: jdbc:mysql://<b>172.17.0.1</b>:3306/database_name

Leandro
la source
C'est la solution la plus simple. Cela a fonctionné pour moi et j'en ai référé beaucoup
Sopia Alfred
-1

La façon dont je le fais est de passer l'IP hôte en tant que variable d'environnement au conteneur. Le conteneur accède ensuite à l'hôte par cette variable.

F. Kam
la source
Pouvez-vous illustrer comment vous procédez? J'avais tenté cette approche mais je n'ai pas trouvé grand succès
kmjb
`docker run -i -t -e HOST = 10.145.2.123 ubuntu root @ ce2a843da3ee: / tmp # ./telnet $ HOST 22 Trying 10.145.2.123 ... Connecté à 10.145.2.123. Le caractère d'échappement est '^]'. SSH-2.0-OpenSSH_7.4`
F. Kam