Depuis l'intérieur d'un conteneur Docker, comment se connecter à l'emplacement de la machine?

donc j'ai un Nginx qui tourne dans un conteneur docker, j'ai un mysql qui tourne sur localhost, je veux me connecter au MySql à partir de mon Nginx. Le MySql tourne 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.

y a-t-il un moyen de se connecter à ce MySql ou à tout autre programme sur localhost depuis ce conteneur docker?

709
demandé sur Kevin 2014-06-20 07:54:16

15 réponses

Edit: Si vous utilisez Docker-pour-mac ou Docker-pour-Windows 18.03+, connectez-vous à votre service mysql à l'aide de l'hôte host.docker.internal .

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


TLDR

utilisez --network="host" dans votre commande docker run , puis 127.0.0.1 dans votre conteneur Docker pointera vers votre Docker hôte.


Note sur les modes de mise en réseau des conteneurs dockers

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

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

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 du 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 l'interface réseau docker0 .

maintenant démarrer un nouveau conteneur et obtenir un shell sur elle: docker run --rm -it ubuntu:trusty bash et dans le conteneur tapez ip addr show eth0 pour 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

ainsi l'adresse IP de l'hôte docker 172.17.42.1 est définie comme route par défaut et est 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 --réseau="accueil"

Vous pouvez également exécuter un conteneur docker avec paramètres réseau définis à 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 docker.

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

d'IP config sur mon panneau d'accueil:

[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 --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 à la fois l'hôte docker et le conteneur docker partagent la même interface réseau et en tant que tel ont la même adresse IP.


Connexion à MySQL à partir de récipients

mode pont

pour accéder à MySQL fonctionnant sur l'hôte docker à partir des conteneurs en mode pont , vous devez vous assurer que le service MySQL est à l'écoute des connexions sur l'adresse IP 172.17.42.1 .

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 avez besoin de définir une variable d'environnement avec l'adresse IP de la gateway, vous pouvez exécuter le code suivant dans un conteneur:

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

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

Note: si vous utilisez bind-address = 0.0.0.0 votre serveur MySQL écoutera pour les connexions sur toutes les interfaces réseau. Cela signifie que votre serveur MySQL peut être contacté à partir d'Internet ; assurez-vous de configurer les règles du pare-feu en conséquence.

Note 2: si vous utilisez bind-address = 172.17.42.1 votre serveur MySQL n'écoutera pas les connexions faites à 127.0.0.1 . Les processus tournant sur l'hôte du docker qui voudraient se connecter à MySQL devraient utiliser l'adresse IP 172.17.42.1 .

mode hôte

pour accéder à MySQL tournant sur l'hôte docker à partir des conteneurs dans mode hôte , vous pouvez garder bind-address = 127.0.0.1 dans votre configuration MySQL et tout ce que vous devez faire est de vous connecter à 127.0.0.1 à partir 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.1 et non mysql -h localhost ; sinon le client MySQL essaierait de se connecter en utilisant une socket unix.

1035
répondu Thomasleveil 2018-09-11 18:39:22

pour macOS et Windows

Docker v 18.03 et plus (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.

prise en charge de Linux en attente https://github.com/docker/for-linux/issues/264

MacOS avec des versions antérieures de Docker

Docker pour Mac v 17.12 à v 18.02

comme ci-dessus, mais utilisez docker.for.mac.host.internal à la place.

Docker pour Mac v 17.06 à v 17.11

comme ci-dessus, mais utilisez docker.for.mac.localhost à la place.

Docker pour Mac 17.05 et en dessous de

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 IP que vous voulez, assurez-vous juste que vous ne l'utilisez à rien d'autre.

sudo ifconfig lo0 alias 123.123.123.123/24

alors assurez-vous que votre serveur est à l'écoute de L'IP mentionnée ci-dessus ou 0.0.0.0 . S'il écoute sur localhost 127.0.0.1 il n'acceptera pas la connexion.

alors il suffit de pointer votre conteneur docker sur cette IP et vous pouvez 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éinitialisera à chaque redémarrage, donc créez 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

212
répondu Janne Annala 2018-04-15 19:42:25

je fais un hack similaire à ci-dessus affiche d'obtenir l'adresse IP locale de la carte à un alias de nom (DNS) dans le récipient. Le problème majeur est d'obtenir dynamiquement avec un script simple qui fonctionne à la fois dans Linux et OSX l'adresse IP 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  }' | cut -f2 -d: | head -n1

ainsi, en utilisant Docker composer, 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  }' | cut -f2 -d: | head -n1)
docker-compose -f docker-compose.yml up

docker-composer.yml :

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

puis changer http://localhost en http://dockerhost dans votre code.

pour un guide plus avancé sur la façon de personnaliser le script DOCKERHOST , jetez un oeil à ce post avec une explication de la façon dont il fonctionne.

52
répondu Mariano Ruiz 2017-07-21 19:18:20

cela a fonctionné pour moi sur une pile Nginx / PHP-FPM sans toucher à aucun code ou réseau où l'application s'attend juste à être en mesure de se connecter à localhost

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

trouver l'emplacement du mysql.fichier sock sur l'hôte qui exécute mysql:

netstat -ln | awk '/mysql(.*)?\.sock/ { print }'

montez ce fichier à l'endroit prévu 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
30
répondu user833482 2018-07-12 12:48: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 de certaines sources mentionnées windows mais il devrait être win )

vue d'ensemble

J'avais besoin d' pour faire quelque chose de similaire, c'est Connecter de mon Docker container à mon localhost, qui exécutait les 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'IP sa limite aussi, je cherchais une solution qui fonctionnerait avec les paramètres par défaut.

cela fonctionne aussi pour la connexion de mon conteneur Docker à SQL Server et IIS , les deux fonctionnant localement sur mon hôte avec les paramètres de port par défaut.

9
répondu Ralph Willgoss 2018-06-03 14:57:11

pour ceux qui se trouvent sur Windows, en supposant que vous utilisez le pilote bridge network, vous voudrez lier MySQL spécifiquement à L'adresse ip de l'interface réseau hyper-V.

cela se fait via le fichier de configuration sous le C:\ProgramData\MySQL dossier.

Reliure à 0.0.0.0 ne fonctionnera pas. L'adresse nécessaire est indiqué dans le panneau de configuration, et dans mon cas était 10.0.75.1.

8
répondu Casey 2016-12-10 15:53:05

Edit: j'ai fini de prototypage 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 host 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 utilisez Linux (mon expérience directe a été avec Ubuntu 14.04 LTS et je suis la mise à niveau à 16.04 LTS en production bientôt), Oui , vous pouvez faire le service courant à l'intérieur d'un conteneur Docker se connecter à localhost services fonctionnant sur L'hôte Docker (par ex. votre ordinateur portable).

comment?

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

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

Quand vous faites un ifconfig (vous aurez besoin de apt-get install net-tools votre conteneur pour ifconfig pour être appelable) à l'intérieur de votre conteneur, vous verrez que la les interfaces réseau sont les mêmes que celles de L'hôte Docker (p. ex. 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 c'est ainsi que vous connectez le conteneur Nginx au MySQL tournant sur un localhost .

7
répondu sivabudh 2017-05-23 11:55:00

Solution pour Linux (kernel >=3.6).

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

  1. activer route_localnet pour l'interface docker0:

    $ sysctl -w net.ipv4.conf.docker0.route_localnet=1
  2. ajouter les règles suivantes: 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 utilisateur mysql avec accès à partir de ' % ' qui signifie - de n'importe qui, à l'exclusion de localhost:

    CREATE USER 'user'@'%' IDENTIFIED BY 'password';
  4. changement dans votre script l'adresse mysql-server à 172.17.0.1



De la documentation du noyau :

route_localnet - booléen: ne pas considérer les adresses loopback comme source ou destination martienne pendant l'acheminement. Cela permet l'utilisation de 127/8 à des fins de routage local ( faux par défaut ).

7
répondu Ray D 2017-09-27 13:22:52

voici ma solution : cela fonctionne pour mon cas

  • mettre le serveur mysql local à l'accès public par commentaire #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 utilisateur n'importe quel hôte mysql -uroot -proot GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES;

  • créer 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=demo \
                  -e DATABASE_USER=root \
                  -e DATABASE_PASSWORD=root \
                  sopheamak/springboot_docker_mysql

  
  • exécuter avec docker-compositeur

    version: '2.1'
    
    

    services:

    tomcatwar: extra_hosts: - "local:10.1.2.232" image: sopheamak/springboot_docker_mysql

    ports: - 8080:8080 environment: - DATABASE_HOST=local - DATABASE_USER=root - DATABASE_PASSWORD=root - DATABASE_NAME=demo - DATABASE_PORT=3306

3
répondu sopheamak 2017-07-17 07:47:55

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.

Making mysql bind to 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 originale veut faire. Il dit explicitement "la MySql court sur localhost et de ne pas exposer un port au monde extérieur, ainsi son lié sur localhost"

pour répondre au commentaire de ivant

"Pourquoi ne pas lier mysql pour docker0 ainsi?"

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 pas trouvé n'importe quel moyen d'atteindre la base de données (localhost seulement) sur l'hôte à partir d'un conteneur docker. Qui semble définitivement comme un très très commun, mais je ne sais pas comment le faire.

2
répondu orzel 2016-10-11 14:23:23

la solution la plus simple pour Mac OSX

il suffit d'utiliser l'adresse IP de votre Mac. Sur le Mac lancer pour obtenir l'adresse IP et l'utiliser à partir de l'intérieur du conteneur:

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

aussi longtemps que le serveur tournant localement sur votre Mac ou dans un autre conteneur docker écoute 0.0.0.0, le conteneur docker sera en mesure d'atteindre cette adresse.

si vous voulez juste accéder à un autre docker conteneur qui est à l'écoute sur 0.0.0.0.0 vous pouvez utiliser 172.17.0.1

2
répondu dansalmo 2017-05-17 22:23:13

les Cgroupes et les Namespaces jouent un rôle majeur dans l'écosystème des conteneurs.

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

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

Utiliser L'Espace De Nom De Réseau

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

$ docker run -it alpine ifconfig

en changeant le namespace à l'hôte, les réseaux de cotainers ne restent pas isolés à 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 les ports, ils seront écoutés sur l'interface hôte et mis en correspondance avec le conteneur.

Utiliser le PID de l'espace de Noms En changeant l'espace de noms Pid permet à un conteneur d'interagir avec d'autres processus au-delà de sa portée normale.

ce conteneur fonctionnera dans son propre espace de nom.

$ docker run -it alpine ps aux

en changeant le namespace à l'hôte, le conteneur peut également voir tous les autres processus tournant sur le système.

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

Partage De L'Espace De Noms

c'est une mauvaise pratique de faire cela en production parce que vous êtes en train de sortir du modèle de sécurité des conteneurs qui pourrait s'ouvrir à des vulnérabilités, et un accès facile à eavesdropper. Ce n'est que pour déboguer les outils et minimiser les failles dans la sécurité des conteneurs.

le premier conteneur est nginx server. Ce créera un nouveau namespace de réseau et de processus. 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 maintenant réutiliser cet espace de nom,

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

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

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

cela vous permettra de donner plus de privilèges aux conteneurs sans changer ou redémarrer l'application. Dans de la même façon, vous pouvez vous connecter à mysql sur l'hôte, exécuter et déboguer votre application. Mais, ce n'est pas recommander d'aller par ce chemin. Espérons que cela aide.

2
répondu mohan08p 2017-09-06 12:05:22

vous pouvez obtenir l'adresse ip de l'hôte en utilisant l'image alpine

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

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

similaire à 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 }') docker-compose up
2
répondu hasnat 2018-06-11 08:47:06

Pour Machine Windows: -

exécuter la commande ci-dessous pour exposer le port docker au hasard pendant le temps de construction

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

enter image description here

enter image description here

dans la liste des conteneurs ci-dessus, vous pouvez voir le port assigné comme 32768. Essayez d'accéder à

localhost:32768 

You peut voir la page mediawiki

1
répondu Lokesh S 2018-09-22 06:07:32

vous pouvez utiliser ngrok pour créer un tunnel sécurisé vers votre machine localhost et ensuite exposer ce tunnel à votre conteneur docker.

ngrok est libre à partir du 22/05/2017.

Suit:

1) passer à ngrok

2) télécharger le client ngrok et suivre les instructions d'installation

3) inscrivez pour un compte et ils fourniront un jeton d'authentification. L'inscription est nécessaire car ngrok ne vous donne le tunnel du port tcp qu'après l'inscription. Il n'y a aucun coût ou carte de crédit nécessaire pour vous inscrire.

4) dans votre terminal faites ngrok tcp 3306 . 3306 est le port que mysql fonctionne sur mon local, vous pouvez le faire avec n'importe quel autre port.

5) vous recevrez une adresse de l'étape 4 comme ceci: tcp://0.tcp.ngrok.io:10117 . C'est la connexion du tunnel à votre machine locale. 0.tcp.ngrok.io est mappé à votre localhost et le port 10117 est mappé à votre port local 3306 . Maintenant, vous pouvez accéder à votre port 3306 localhost de n'importe où en utilisant cette adresse, y compris n'importe quel conteneur docker tournant sur cette machine. Dans votre conteneur docker(où qu'il se trouve), en supposant que vous avez mysql client déjà installé, faites ce qui suit:

mysql --host 0.tcp.ngrok.io --port 10117 -u root

Vous pourrez vous connecter à votre compte root de votre machine locale depuis l'intérieur du conteneur docker!

j'ai blogué sur cette solution Voir plus de détails ici

-12
répondu Stephens 2017-05-24 22:30:42