Изнутри контейнера Docker, как подключиться к localhost машины?
Итак, у меня есть Nginx, работающий внутри контейнера docker, у меня есть mysql, работающий на localhost, я хочу подключиться к MySql из моего Nginx. MySql работает на localhost и не подвергает порт внешнему миру, поэтому его привязка к localhost, не привязанная к ip-адресу машины.
есть ли способ подключиться к этому MySql или любой другой программе на localhost из этого контейнера docker?
15 ответов
Edit: если вы используете Докер-для-mac или Docker-for-Windows 18.03+, просто подключитесь к своей службе mysql, используя хост host.docker.internal
.
начиная с Docker 18.04, это не работает на Docker-for-Linux.
TLDR
использовать --network="host"
в своем , потом 127.0.0.1
в вашем контейнере docker будет указывать на ваш хост docker.
обратите внимание на docker контейнерные сетевые режимы
настройки предложения различные сетевые режимы при запуске контейнеров. В зависимости от выбранного режима вы будете подключаться к базе данных MySQL, запущенной на хосте docker по-разному.
docker run --network= "мост" (по умолчанию)
Docker создает мост с именем docker0
по умолчанию. И хост docker, и контейнеры docker имеют IP-адрес на этом мосту.
на Докер хост, типа sudo ip addr show docker0
у вас будет выход, похожий на:
[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
Итак, здесь мой хост docker имеет IP-адрес 172.17.42.1
на docker0
сетевой интерфейс.
теперь запустите новый контейнер и получите оболочку на нем:docker run --rm -it ubuntu:trusty bash
и в пределах контейнерного типа ip addr show eth0
чтобы узнать, как настроен его основной сетевой интерфейс:
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
здесь мой контейнер имеет IP-адрес 172.17.1.192
. Теперь посмотрите на таблицу маршрутизации:
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
Итак, IP Адрес хоста docker 172.17.42.1
устанавливается в качестве маршрута по умолчанию и доступен из контейнера.
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"
в качестве альтернативы вы можете запустить контейнер docker с настройки сети установлено значение host
. Такой контейнер будет делиться сетевым стеком с хостом docker и с точки зрения контейнера, localhost
(или 127.0.0.1
) будет ссылаться на хост docker.
имейте в виду, что любой порт открыт в ваш контейнер docker будет открыт на хосте docker. И это не требуя -p
или -P
docker run
опции.
конфигурация IP на моем хосте 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
и из контейнера докера в хоста режим:
[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
как вы можете видеть, как хост docker и контейнер docker имеют один и тот же сетевой интерфейс и как таковой имеют один и тот же IP-адрес.
подключение к MySQL из контейнеров
режим моста
для доступа к MySQL, работающему на хосте docker из контейнеров в режим моста, вам нужно убедиться, что служба MySQL прослушивает соединения на 172.17.42.1
IP-адрес.
чтобы сделать это, убедитесь, что у вас есть либо bind-address = 172.17.42.1
или bind-address = 0.0.0.0
в вашем конфигурационном файле MySQL (my.cnf).
Если вам нужно установить переменную среды с IP-адресом шлюза, вы можете запустить следующее код в контейнере:
export DOCKER_HOST_IP=$(route -n | awk '/UG[ \t]/{print }')
тогда в вашем приложении, используйте DOCKER_HOST_IP
переменная окружения, чтобы открыть соединение с MySQL.
Примечание: если вы используете bind-address = 0.0.0.0
ваш сервер MySQL будет прослушивать соединения на всех сетевых интерфейсах. Это означает, что ваш сервер MySQL может быть достигнут из интернета ; убедитесь, что настроили правила брандмауэра соответственно.
примечание 2: если вы используете bind-address = 172.17.42.1
ваш сервер MySQL не будет слушать для подключения к 127.0.0.1
. Процессы, запущенные на хосте docker, которые хотели бы подключиться к MySQL, должны были бы использовать 172.17.42.1
IP-адрес.
режим хоста
для доступа к MySQL, работающему на хосте docker из контейнеров в режим хоста, вы можете сохранить bind-address = 127.0.0.1
в вашей конфигурации MySQL и все, что вам нужно сделать, это подключиться к 127.0.0.1
из ваших контейнеров:
[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>
Примечание: используйте mysql -h 127.0.0.1
и не mysql -h localhost
; в противном случае клиент MySQL попытался бы подключиться с помощью сокета unix.
для macOS и Windows
Docker v 18.03 и выше (с 21 марта 2018 года)
используйте свой внутренний IP-адрес или подключитесь к специальному DNS-имени host.docker.internal
который разрешится на внутренний IP-адрес, используемый хостом.
поддержка Linux в ожидании https://github.com/docker/for-linux/issues/264
MacOS с более ранними версиями Docker
Докер для Mac v 17.12-v 18.02
то же, что и выше, но используйте docker.for.mac.host.internal
вместо.
Докер для Mac v 17.06 - V 17.11
то же, что и выше, но используйте docker.for.mac.localhost
вместо.
Docker для Mac 17.05 и ниже
чтобы получить доступ к хост-машине из контейнера docker, необходимо подключить псевдоним IP к сетевому интерфейсу. Вы можете привязать любой IP вы хотите, просто убедитесь, что вы не используете его ни к чему еще.
sudo ifconfig lo0 alias 123.123.123.123/24
затем убедитесь, что ваш сервер прослушивает IP-адрес, упомянутый выше, или 0.0.0.0
. Если он слушает localhost 127.0.0.1
он не будет принимать соединения.
затем просто укажите контейнер docker на этот IP-адрес, и вы можете получить доступ к хост-машине!
для проверки вы можете запустить что-то вроде curl -X GET 123.123.123.123:3000
внутри контейнера.
псевдоним будет сброшен при каждой перезагрузке, поэтому создайте сценарий запуска, если необходимый.
решение и дополнительная документация здесь: https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds
Я делаю Хак, подобный вышеуказанным сообщениям, чтобы получить локальный IP-адрес для сопоставления с псевдонимом (DNS) в контейнере. Основная проблема заключается в том, чтобы получить динамически с помощью простого скрипта, который работает как в Linux и OSX IP-адрес хоста. Я сделал этот скрипт, который работает в обеих средах (даже в Linux с "$LANG" != "en_*"
настроить):
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, полная конфигурация будет:
скрипт запуска (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
докер-сочинять.в формате YML:
myapp:
build: .
ports:
- "80:80"
extra_hosts:
- "dockerhost:$DOCKERHOST"
затем измените http://localhost
до http://dockerhost
в коде.
для более руководство о том, как настроить DOCKERHOST
скрипт, взгляните на этот пост с объяснением как это работает.
это сработало для меня в стеке nginx / PHP-FPM, не касаясь кода или сети, где приложение просто ожидает возможности подключения к localhost
Mount mysqld.sock
от хоста к внутри контейнера.
найдите местоположение mysql.файл носка на хосте с mysql:netstat -ln | awk '/mysql(.*)?\.sock/ { print }'
установите этот файл туда, где он ожидается в докере:docker run -v /hostpath/to/mysqld.sock:/containerpath/to/mysqld.sock
возможные местоположения mysqld.носок:
/tmp/mysqld.sock
/var/run/mysqld/mysqld.sock
/var/lib/mysql/mysql.sock
/Applications/MAMP/tmp/mysql/mysql.sock # if running via MAMP
решение для Windows 10
Docker Community Edition 17.06.0-ce-win18 2017-06-28 (стабильный)
вы можете использовать DNS-имя хоста docker.for.win.localhost
, для разрешения на внутренний IP. (Предупреждение некоторые источники упомянуты windows
но он должен быть!--2-->)
обзор
Мне нужно было сделать что-то подобное, то есть подключиться из моего контейнера Docker к моему localhost, на котором был запущен Azure Storage Emulator
и CosmosDB Emulator
.
на Azure Storage Emulator
по умолчанию прослушивает 127.0.0.1, хотя вы также можете изменить IP-адрес, я искал решение, которое будет работать с настройками по умолчанию.
это также работает для подключения из моего контейнера Docker в SQL Server
и IIS
, оба работают локально на моем хосте с настройки порта по умолчанию.
для тех, кто в Windows, предполагая, что вы используете сетевой драйвер моста, вы захотите специально привязать MySQL к ip-адресу сетевого интерфейса hyper-V.
Это делается через файл конфигурации под обычно скрытым C:\ProgramData\MySQL папка.
привязка к 0.0.0.0 не будет работать. Необходимый адрес также отображается в конфигурации docker, и в моем случае это был 10.0.75.1.
Edit: я закончил прототипирование концепции на GitHub. Проверьте: https://github.com/sivabudh/system-in-a-box
во-первых, мой ответ ориентирован на 2 группы людей: те, кто использует Mac, и те, кто использует Linux.
на хоста сетевой режим не работает на Mac. Вы должны использовать псевдоним IP, см.:https://stackoverflow.com/a/43541681/2713729
что такое хост сетевой режим? Смотри:https://docs.docker.com/engine/reference/run/#/network-settings
во-вторых, для тех из вас, кто использует Linux (мой прямой опыт был с Ubuntu 14.04 LTS, и я скоро обновлюсь до 16.04 LTS в производстве),да, вы можете заставить службу работать внутри контейнера Docker подключиться к localhost
службы, работающие на хосте Docker (например. ваш ноутбук.)
как?
ключ, когда вы запускаете Докер контейнер, вы должны запустить его с помощью хоста режим. Команда выглядит так:
docker run --network="host" -id <Docker image ID>
когда вы делаете ifconfig
(вам понадобится apt-get install net-tools
контейнер для ifconfig
для вызова) внутри вашего контейнера вы увидите, что сетевые интерфейсы такие же, как и на хосте Docker (например. ваш ноутбук.)
важно отметить, что я пользователь Mac, но я запускаю Ubuntu под Parallels, поэтому использование Mac не является недостатком. ;-)
и вот как вы подключаете контейнер NGINX к MySQL, работающему на localhost
.
решение для Linux (ядро >=3.6).
Ok, ваш сервер localhost имеет интерфейс docker по умолчанию docker0 С ip-адресом 172.17.0.1. Ваш контейнер запущен с сетевыми настройками по умолчанию --net= "мост".
- включить route_localnet для интерфейса docker0:
$ sysctl -w net.ipv4.conf.docker0.route_localnet=1
- добавить правила в 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
- создать пользователя mysql с доступом из "%", что означает-от любого, за исключением localhost:
CREATE USER 'user'@'%' IDENTIFIED BY 'password';
- измените в своем скрипте адрес mysql-сервера на 172.17.0.1
route_localnet - BOOLEAN: не рассматривайте адреса замыкания на себя в качестве марсианского источника или назначения при маршрутизации. Это позволяет использовать 127/8 для локальной маршрутизации (по умолчанию Ложные).
вот мое решение : это работает для моего случая
установите локальный сервер mysql в открытый доступ по комментарию
#bind-address = 127.0.0.1
в /etc/mysql / mysql.conf.dперезапустить сервер mysql
sudo /etc/init.d/mysql restart
выполните следующую команду, чтобы открыть корневой доступ пользователя к любому хосту
mysql -uroot -proot GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES;
создать сценарий 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
-
запуск с докер-композитор
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
Я не согласен с ответом от Thomasleveil.
привязка mysql к 172.17.42.1 предотвратит другие программы, использующие базу данных на хосте, чтобы достичь ее. Это будет работать, только если все пользователи базы данных dockerized.
привязка mysql к 0.0.0.0 откроет БД для внешнего мира, что не только очень плохо, но и противоречит тому, что хочет сделать автор исходного вопроса. Он явно говорит: "MySql работает на localhost, а не подвергая порт внешнему миру, поэтому его привязывают к localhost"
чтобы ответить на комментарий от ivant
" Почему бы не привязать mysql к docker0?"
Это невозможно. Документация mysql/mariadb явно говорит, что невозможно привязать к нескольким интерфейсам. Можно выполнить привязку только к 0, 1 или ко всем интерфейсам.
В заключение, я не нашел никакого способа добраться до базы данных (только localhost) на хосте из контейнер докера. Это определенно кажется очень распространенной моделью, но я не знаю, как это сделать.
простейшее решение для Mac OSX
просто используйте IP-адрес вашего Mac. На Mac запустите это, чтобы получить IP-адрес и использовать его из контейнера:
$ ifconfig | grep 'inet 192'| awk '{ print }'
пока сервер, работающий локально на вашем Mac или в другом контейнере docker, прослушивает 0.0.0.0, контейнер docker сможет связаться с этим адресом.
Если вы просто хотите получить доступ к другому контейнеру docker, который прослушивает 0.0.0.0, вы можете использовать 172.17.0.1
группы и пространства имен играют важную роль в экосистеме контейнеров.
пространство имен обеспечивает уровень изоляции. Каждый контейнер выполняется в отдельном пространстве имен, и его доступ ограничен этим пространством имен. Группы управляют использованием ресурсов каждого контейнера, а пространство имен - тем, что процесс может видеть и получать доступ к соответствующему ресурсу.
вот базовые понимания подход решения можно следуй,
Использовать Сетевое Пространство Имен
когда контейнер порождает образ, определяется и создается сетевой интерфейс. Это дает контейнеру уникальный IP-адрес и интерфейс.
$ docker run -it alpine ifconfig
изменяя пространство имен на host, сети cotainers не остаются изолированными от своего интерфейса, процесс будет иметь доступ к сетевому интерфейсу хост-машин.
$ docker run -it --net=host alpine ifconfig
если процесс прослушивает порты, они будут слушать на интерфейс хоста и сопоставлен с контейнером.
использовать пространство имен PID Изменение пространства имен Pid позволяет контейнеру взаимодействовать с другим процессом за пределами его обычной области.
этот контейнер будет работать в собственном пространстве имен.
$ docker run -it alpine ps aux
изменяя пространство имен на хост, контейнер также может видеть все другие процессы, запущенные в системе.
$ docker run -it --pid=host alpine ps aux
Совместное Использование Пространства Имен
это плохая практика делать это в производстве, потому что вы выходите из модели безопасности контейнера, которая может открыться для уязвимостей и легкого доступа к подслушивающему устройству. Это только для отладки инструментов и занижения лазеек в безопасности контейнеров.
первый контейнер-сервер nginx. Это создаст новое пространство имен network и process. Этот контейнер будет привязан к порту 80 вновь созданного сетевого интерфейса.
$ docker run -d --name http nginx:alpine
еще один контейнер может теперь повторно используйте это пространство имен,
$ docker run --net=container:http mohan08p/curl curl -s localhost
кроме того, этот контейнер может видеть интерфейс с процессами в общем контейнере.
$ docker run --pid=container:http alpine ps aux
это позволит вам предоставить больше привилегий контейнерам без изменения или перезапуска приложения. Аналогичным образом вы можете подключиться к mysql на хосте, запустить и отладить приложение. Но, его не рекомендуют идти этим путем. Надеюсь, это поможет.
вы можете получить ip-адрес хоста, используя alpine image
docker run --rm alpine ip route | awk 'NR==1 {print }'
Это было бы более последовательно, поскольку вы всегда используете alpine для запуска команды.
подобно ответу Мариано, вы можете использовать ту же команду для установки переменной среды
DOCKER_HOST=$(docker run --rm alpine ip route | awk 'NR==1 {print }') docker-compose up
Для Компьютера Windows :-
выполните следующую команду, чтобы выставить порт docker случайным образом во время сборки
$docker run -d --name MyWebServer -P mediawiki
в приведенном выше списке контейнеров вы можете увидеть порт, назначенный как 32768. Попробуйте получить доступ
localhost:32768
вы можете увидеть страницу mediawiki
можно использовать сайту ngrok чтобы создать безопасный туннель к вашей машине localhost, а затем подвергнуть этот туннель контейнеру docker.
сайту ngrok свободно использовать как в 05/22/2017.
действия:
1) перейти к сайту ngrok
2) скачать клиент ngrok и следуйте инструкциям по установке
3) ЗАРЕГИСТРИРОВАТЬСЯ для учетной записи, и они обеспечат аутентификацию знак. Регистрация требуется, потому что ngrok дает вам туннель tcp-порта только после регистрации. Для регистрации не требуется никаких затрат или кредитной карты.
4) в вашем терминале do ngrok tcp 3306
. 3306
- это порт, который mysql работает на моем локальном, вы можете сделать это с любым другим портом.
5) Вы получите адрес из шага 4
например: tcp://0.tcp.ngrok.io:10117
. Это туннельное соединение с вашей локальной машиной. 0.tcp.ngrok.io
отображается на ваш localhost
и порт 10117
is сопоставлено с вашим локальным портом 3306
. Теперь вы можете получить доступ к порту localhost 3306 из любого места, используя этот адрес, включая любой контейнер docker, работающий на этом компьютере. В контейнере docker(где бы он ни находился), предполагая, что у вас уже установлен клиент mysql, сделайте следующее:
mysql --host 0.tcp.ngrok.io --port 10117 -u root
вы сможете войти в свой root
учетная запись вашей локальной машины изнутри контейнера docker!
я написал об этом решении подробнее подробности здесь