Как подключиться к локальному узлу машины из контейнера Docker?


1455

Итак, у меня Nginx работает внутри контейнера Docker, у меня работает MySQL на localhost, я хочу подключиться к MySql изнутри моего Nginx. MySql работает на локальном хосте и не открывает порт для внешнего мира, поэтому он связан с локальным хостом, а не с IP-адресом машины.

Есть ли способ подключиться к этому MySql или любой другой программе на локальном хосте из этого контейнера Docker?

Этот вопрос отличается от «Как получить IP-адрес хоста докера из контейнера докера» тем, что IP-адрес хоста докера может быть публичным или частным IP в сети, который может или может быть быть недоступным из контейнера докера (я имею в виду публичный IP, если он размещен на AWS или что-то в этом роде). Даже если у вас есть IP-адрес докер-хоста, это не означает, что вы можете подключиться к док-хосту из контейнера, учитывая, что IP-адрес вашей сети Docker может быть наложенным, хост, мост, macvlan, нет и т. Д., Что ограничивает достижимость этот IP-адрес.


Почему бы не связать mysql с docker0?
Иван

2
Для Windows Machine: - $ docker run -d --name MyWebServer -P httpd
Lokesh S


1
Без network: hostвас нельзя вернуться из контейнера к хозяину. Только хост для контейнера. Это основная идеология контейнеров. Они изолированы как по соображениям стабильности, так и по соображениям безопасности.
FreeSoftwareServers

Ответы:


1976

Изменить: Если вы используете Docker-для-Mac или Docker-для-Windows 18.03+, просто подключитесь к службе MySQL с помощью хоста host.docker.internal(вместо 127.0.0.1в строке подключения).

Начиная с Docker 18.09.3, это не работает в Docker-для-Linux. Исправление было представлено на 8 марта, 2019 и мы надеемся , будут объединены в базу кода. До тех пор, обходной путь должен использовать контейнер, как описано в ответе Qoomon .

2020-01: некоторый прогресс был достигнут. Если все идет хорошо, это должно приземлиться в Docker 20.04


TLDR

Используйте --network="host"в вашей docker runкоманде, тогда 127.0.0.1в вашем док-контейнере будет указывать на ваш докер хост.

Примечание. Этот режим работает только в Docker для Linux согласно документации .


Обратите внимание на режимы работы с сетью Docker-контейнеров

Docker предлагает различные сетевые режимы при запуске контейнеров. В зависимости от выбранного вами режима, вы будете подключаться к базе данных MySQL, работающей на хосте докера, по-разному.

Docker run --network = "bridge" (по умолчанию)

Docker создает мост с именем docker0по умолчанию. И хост-докер, и контейнеры-докеры имеют IP-адрес на этом мосту.

на хосте Docker напечатайте, у 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

Итак, у моего докера есть 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-адрес узла докера 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 . Такой контейнер будет совместно использовать сетевой стек с хостом докера и с точки зрения контейнера localhost(или 127.0.0.1) будет ссылаться на хост докера.

Помните, что любой порт, открытый в вашем контейнере докера, будет открыт на хосте докера. И это без необходимости -pили -P docker runвариант .

Конфигурация IP на моем хосте докера:

[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

Как вы можете видеть, и хост-докер, и контейнер-докер используют один и тот же сетевой интерфейс и имеют одинаковый IP-адрес.


Подключение к MySQL из контейнеров

режим моста

Чтобы получить доступ к MySQL, работающему на хосте докера, из контейнеров в режиме моста , необходимо убедиться, что служба MySQL прослушивает соединения по 172.17.42.1IP-адресу.

Для этого убедитесь, что у вас есть либо один, 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 $2}')

затем в вашем приложении используйте DOCKER_HOST_IPпеременную окружения, чтобы открыть соединение с MySQL.

Примечание: если вы используете bind-address = 0.0.0.0сервер MySQL, вы будете прослушивать соединения на всех сетевых интерфейсах. Это означает, что ваш сервер MySQL может быть доступен из Интернета; убедитесь, что настроили правила брандмауэра соответственно.

Примечание 2: если вы используете bind-address = 172.17.42.1ваш сервер MySQL, он не будет прослушивать сделанные подключения 127.0.0.1. Процессы, работающие на док-хосте, который хочет подключиться к MySQL, должны будут использовать 172.17.42.1IP-адрес.

режим хоста

Чтобы получить доступ к MySQL, работающему на хосте докера, из контейнеров в режиме хоста , вы можете сохранить 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.


8
Спасибо за такой подробный ответ! Из того, что я понял, использование режима хоста - единственный способ получить эту функциональность через localhost. Я не пробовал, но я бы предположил, что вы можете создать отдельную сеть для подключения контейнеров через их собственный мост, предлагая им общий локальный хост.
Бен

26
Примечание для пользователей OSX: сначала войдите в вашу виртуальную машину с докером (boot2docker), используя «docker-machine ssh default», затем запустите «sudo ip addr show docker0». Продолжайте инструкции Томаса оттуда.
Чарли Далсасс

30
Я использую Docker для Mac, и больше нет 172.17.42.1, больше нет docker0. Это был 172.17.0.1 в качестве шлюза, и даже не могуtelnet 172.17.0.1 3306
zx1986

26
Вы можете монтировать сокет mysql в контейнер, а не подключаться к сети, как -v /var/run/mysqld/mysqld.sock:/tmp/mysql.sockэто.
СНХ

8
Может ли кто-нибудь разобраться в ситуации, когда у вас работает Docker на Mac и вы не используете boot2docker, так как отсутствует интерфейс docker0?
TheJKFever

350

Для 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 до 18.02

То же, что и выше, но используйте docker.for.mac.host.internalвместо этого.

Докер для Mac с 17.06 по 17.11

То же, что и выше, но используйте docker.for.mac.localhostвместо этого.

Докер для Mac 17.05 и ниже

Чтобы получить доступ к хост-машине из док-контейнера, вы должны прикрепить IP-псевдоним к вашему сетевому интерфейсу. Вы можете связать любой IP-адрес, который хотите, просто убедитесь, что вы не используете его ни с чем другим.

sudo ifconfig lo0 alias 123.123.123.123/24

Затем убедитесь, что ваш сервер прослушивает IP-адрес, упомянутый выше или 0.0.0.0. Если он прослушивает localhost, 127.0.0.1он не примет соединение.

Затем просто укажите свой док-контейнер на этот IP, и вы получите доступ к хост-машине!

Для проверки вы можете запустить что-то вроде curl -X GET 123.123.123.123:3000внутри контейнера.

Псевдоним будет сбрасываться при каждой перезагрузке, поэтому при необходимости создайте сценарий запуска.

Решение и дополнительная документация здесь: https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds


5
Блестящий и спасибо, это сработало для меня из контейнера. mysql -uroot -hdocker.for.mac.localhost
Ричард Фрэнк

1
docker.for.mac.localhost Это именно то, что я искал. Но в то же время это чертовски грязно. В докере можно было бы ожидать, что хук docker.for.mac.localhost будет общим внутренним именем докера, которое будет действительным для любой операционной системы, а не только для Mac. Но для целей развития это достаточно хорошо.
99Sono

Как я могу получить доступ к порту, который выставлен на скажем 9093 .. Я пытаюсь telnet docker.for.mac.localhost 9093. Это недоступно, но если я пингую docker.for.mac.localhost, это достижимо. Я что-то здесь пропускаю?
Achilleus

1
DNS-имя docker.for.mac.host.internal следует использовать вместо docker.for.mac.localhost (все еще действует) для разрешения хоста из контейнеров, поскольку существует RFC, запрещающий использование поддоменов localhost. См. Tools.ietf.org/html/draft-west-let-localhost-be-localhost-06 .
Jya

Это не работает для меня. Когда я docker run -e HOSTNAME= docker.for.mac.host.internal , контейнер создан, но ничего не происходит. Я должен тогда crtl + C. По --net=host -e HOSTNAME=localhostкрайней мере, контейнер работает и жалуется, что не может найти нужный мне сервис (MySQL db).
Хорхе Орпинель

83

Я сделал хак, аналогичный рассмотренным выше постам, чтобы получить локальный 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 $2 }' | 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 $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"

Затем измените http://localhostк http://dockerhostв вашем коде.

Более подробное руководство по настройке DOCKERHOSTскрипта можно найти в этом посте с объяснением того, как он работает.


1
В зависимости от вашего варианта использования, вы можете просто избежать использования DOCKERHOSTзначения здесь вместо «localhost» или 0.0.0.0 в любой службе, к которой ваш контейнер докера должен подключиться локально.
enderland

2
Я немного изменил ваше решение, чтобы оно было совместимо с пользовательскими сетями: export DOCKERHOST=$(docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}}{{end}}' <NETWORK-NAME> | awk -F "/" 'NR==1{print $1}') где <NETWORK-NAME> может быть мостом или именем сети, как определено docker-compose (обычно path-name - network_name ).
dieresys

1
Вам необходимо добавить комментарий: используйте dockerhostв качестве хоста для соединения с БД (обычно заменяют localhostв файле конфигурации).
Джастин

странное решение, но это единственное, что заставляет xdebug работать под докером с php cli
Eddie

Перестал работать Acl после этого решения в haproxy. Есть идеи почему?
HyukHyukBoi

41

Это сработало для меня в стеке NGINX / PHP-FPM, не касаясь какого-либо кода или сети, где приложение просто ожидает подключения к localhost

Смонтировать mysqld.sockот хоста внутрь контейнера.

Найдите расположение файла mysql.sock на хосте, на котором работает mysql:
netstat -ln | awk '/mysql(.*)?\.sock/ { print $9 }'

Смонтируйте этот файл туда, где он ожидается в докере:
docker run -v /hostpath/to/mysqld.sock:/containerpath/to/mysqld.sock

Возможные местоположения 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

2
Это гораздо более чистое решение, которое не подвергает Mysql внешней стороне (если не используется брандмауэр).
user1226868

5
Сокеты не масштабируются так же хорошо, как TCP, потому что они блокируются чаще и могут вызвать странное поведение. Используйте TCP, когда это возможно.
Джоэл Э Салас

3
@JoelESalas У вас есть источник для этого требования?
Частное

Я нашел, что это самое простое решение. Недурно user833482! Вы должны чаще вносить вклад в StackOverflow.
Частное

2
@JoelESalas Я думаю, ты ошибаешься. Клиентская библиотека mysql даже использует сокеты unix по умолчанию при подключении к localhost, а не фактически подключается к localhost. Unix-сокет позволяет избежать накладных расходов на стек TCP и маршрутизацию и должен работать быстрее.
М Конрад

25

До тех пор host.docker.internal не работает для каждой платформы, вы можете использовать мой контейнер в качестве шлюза NAT без какой-либо ручной настройки:

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


5
Я могу подтвердить, что это не работает в Docker для Windows 19.03.2 с контейнером Windows.
KMC

есть идеи как это исправить? (Я не пользователь Windows)
Qoomon

Если ваша среда не блокирует использование порта MySQL, вы можете ссылаться на сервер по имени компьютера, на котором он находится. Поэтому в строке подключения используйте имя вашего компьютера в качестве имени сервера.
KMC

24

Решение для Linux (ядро> = 3.6).

Хорошо, ваш локальный сервер имеет интерфейс Docker по умолчанию с IP-адресом 172.17.0.1 . Ваш контейнер запустился с сетевыми настройками по умолчанию --net = "bridge" .

  1. Включите route_localnet для интерфейса docker0:
    $ sysctl -w net.ipv4.conf.docker0.route_localnet=1
  2. Добавьте эти правила в 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. Создайте пользователя mysql с доступом «%», что означает - от кого угодно, кроме localhost:
    CREATE USER 'user'@'%' IDENTIFIED BY 'password';
  4. Измените в своем скрипте адрес mysql-сервера на 172.17.0.1


Из документации ядра :

route_localnet - BOOLEAN: не рассматривать петлевые адреса как марсианский источник или пункт назначения при маршрутизации. Это позволяет использовать 127/8 для локальной маршрутизации (по умолчанию FALSE ).


1
Какова цель второй команды iptable? Я могу понять, во-первых, переписать все назначения TCP, которые соответствуют 172.17.0.1:3306 до 127.0.0.1:3306, но зачем нужна вторая команда iptable?
Патрик

17

Решение для Windows 10

Docker Community Edition 17.06.0-ce-win18 2017-06-28 (стабильный)

Вы можете использовать DNS-имя хоста docker.for.win.localhost, чтобы разрешить внутренний IP. (Предупреждение некоторых источников, упомянутыхwindows но это должно быть win)

Обзор
Мне нужно было сделать нечто подобное, то есть подключиться из моего контейнера Docker к моему локальному хосту, на котором выполнялись Azure Storage EmulatorиCosmosDB Emulator .

По Azure Storage Emulatorумолчанию прослушивает 127.0.0.1 , в то время как вы также можете изменить IP-адрес, я искал решение, которое будет работать с настройками по умолчанию.

Это также работает для подключения из моего контейнера Docker SQL Serverи IIS, оба работают локально на моем хосте с настройками порта по умолчанию.


13

Очень просто и быстро, проверьте IP своего хоста с помощью ifconfig (linux) или ipconfig (windows), а затем создайте

докер-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>"

Таким образом, ваш контейнер сможет получить доступ к вашему хосту. При доступе к вашей БД не забудьте использовать имя, которое вы указали ранее, в данном случае «dockerhost» и порт вашего хоста, на котором работает БД


В HaProxy это решение почему-то перестало работать с acl, работает только настройка по умолчанию.
HyukHyukBoi

1
Единственное решение, которое работает в системе Linux. +1
Рафик Фархад

11

Ни один из ответов не сработал для меня при использовании Docker Toolbox на Windows 10 Home, но 10.0.2.2 сработал , поскольку он использует VirtualBox, который выставляет хост для виртуальной машины по этому адресу.


2
Оно работает. Даже не нужно указывать --network = host. Похоже, 10.0.2.2 установлен в качестве IP-адреса по умолчанию для хоста. Спасибо.
TheManish

Но можно ли использовать этот статический IP-адрес для всех версий Windows и Mac? Как я могу использовать его для нескольких платформ с помощью сценария?
151291

Это сработало для меня. Просто запустите ipconfig на вашем хосте (windows) и получите IP-адрес в разделеEthernet adapter vEthernet (DockerNAT)
Kihats

10

Для тех в Windows, предполагая, что вы используете сетевой драйвер моста, вам нужно специально привязать MySQL к ip-адресу сетевого интерфейса hyper-v.

Это делается с помощью файла конфигурации в обычно скрытой папке C: \ ProgramData \ MySQL.

Привязка к 0.0.0.0 не будет работать. Необходимый адрес также отображается в конфигурации докера, и в моем случае это был 10.0.75.1.


3
Вы заслуживаете медаль! Я работал над этим два полных дня. Спасибо за помощь!
Майкл

1
Я также работал над этим в течение двух полных дней. Это единственное место в сети, о котором я упоминал. Microsoft совершенно молчит об этом, когда говорит о подключении к MSSQL из контейнера Docker. Это заставляет задуматься, работают ли они когда-нибудь сами!
контанго

8

Редактировать: я закончил прототипирование концепции на 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.


1
Важно отметить, что режим хоста обеспечивает лучшую производительность, поскольку он использует сетевой стек ОС.
17

2
Очень хороший момент. Хотя МОЖНО подключиться из контейнера к хост-службе с неиспользуемым IP-подключением docs.docker.com/docker-for-mac/networking . Не приятное решение ... но работает.
Ксавье Хаппе

Хорошие вещи здесь. Оказавшись внутри контейнера с --network="host", как можно подключиться к хосту mysql, например?
Майкл

1
@Buccleuch Просто используйте localhost. Проверьте мой исходный код GitHub: github.com/sivabudh/system-in-a-box/blob/master/dj_host_docker/… . Ищите 'HOST', вы увидите 127.0.0.1 для подключения к Postgresql.
Сивабуд

Мне удалось получить доступ к базам данных mysql хоста, смонтировав том в соответствии с @ user833482 и, конечно же, после установки mysql-client и server на док-контейнер.
Майкл

7

Самое простое решение для Mac OSX

Просто используйте IP-адрес вашего Mac. На Mac запустите это, чтобы получить IP-адрес и использовать его из контейнера:

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

Пока сервер, работающий локально на вашем Mac или в другом док-контейнере, прослушивает 0.0.0.0, докер-контейнер сможет связаться по этому адресу.

Если вы просто хотите получить доступ к другому док-контейнеру, который прослушивает 0.0.0.0, вы можете использовать 172.17.0.1


1
Docker для Mac docker.for.mac.host.internalтеперь предоставляет имя хоста.
Мэтт

5

Это не ответ на актуальный вопрос. Так я решил похожую проблему. Решение полностью основано на: Определите Docker Container Networking, чтобы контейнеры могли общаться . Спасибо Ник Рабой

Оставьте это здесь для других, которые могут захотеть делать вызовы REST между одним контейнером и другим. Отвечает на вопрос: что использовать вместо localhost в среде докера?

Узнайте, как выглядит ваша сеть docker network ls

Создать новую сеть docker network create -d my-net

Запустить первый контейнер docker run -d -p 5000:5000 --network="my-net" --name "first_container" <MyImage1:v0.1>

Проверьте настройки сети для первого контейнера docker inspect first_container. «Сети»: должна быть «моя сеть»

Запустить второй контейнер docker run -d -p 6000:6000 --network="my-net" --name "second_container" <MyImage2:v0.1>

Проверьте настройки сети для второго контейнера docker inspect second_container. «Сети»: должна быть «моя сеть»

SSH в ваш второй контейнер docker exec -it second_container shили docker exec -it second_container bash.

Внутри второго контейнера вы можете пропинговать первый контейнер ping first_container. Кроме того, ваш код звонков, таких как http://localhost:5000может быть заменен наhttp://first_container:5000


Именно то, что я искал. Спасибо: D
Симар Сингх

5

Для окон,

Я изменил URL базы данных в весенней конфигурации: spring.datasource.url=jdbc:postgresql://host.docker.internal:5432/apidb

Затем создайте образ и запустите. Это сработало для меня.


интересно ....
Фил

для меня не работает. У меня есть Mac и пытается из php контейнера подключиться к localhost mysql. Есть идеи ?
А. Залонис

4

Я не согласен с ответом Thomasleveil.

Привязка mysql к 172.17.42.1 предотвратит доступ других программ, использующих базу данных на хосте. Это будет работать только в том случае, если все пользователи вашей базы данных докеризованы.

Привязка mysql к 0.0.0.0 откроет базу данных для внешнего мира, что не только очень плохо, но и противоречит тому, что хочет сделать автор оригинального вопроса. Он явно говорит: «MySql работает на локальном хосте и не открывает порт для внешнего мира, поэтому он связан с локальным хостом»

Ответить на комментарий от ivant

"Почему бы не связать mysql с docker0?"

Это невозможно. В документации mysql / mariadb явно сказано, что невозможно привязать несколько интерфейсов. Вы можете привязать только к 0, 1 или всем интерфейсам.

В заключение я НЕ нашел никакого способа получить доступ к базе данных (только для локального хоста) на хосте из контейнера докера. Это определенно похоже на очень распространенную модель, но я не знаю, как это сделать.


4
с хоста докера вы все равно можете подключиться к серверу MySQL, используя 172.17.42.1адрес. Но ваша заметка верна в противном случае. Кроме того, я отредактировал свой ответ в hostсетевом режиме, который позволяет поддерживать 127.0.0.1
привязку

нет, как я уже сказал, вы не можете подключиться к 172.17.42.1, если mysql привязан к localhost.
orzel

4
«Привязка mysql к 172.17.42.1 предотвратит доступ других программ, использующих базу данных на хосте». - это неправда. Другие программы могут использовать mysql, им просто нужно подключиться к 172.17.42.1 вместо localhost / 127.0.0.1.
0x89

Решение проблемы в этом ответе обычно состоит в том, чтобы заставить сервер MySQL связываться с 0.0.0.0и затем настроить межсетевой экран так, чтобы база данных не была доступна из Интернета.
Половник

4

Вот мое решение: это работает для моего случая

  • установить публичный доступ к локальному серверу MySQL через комментарий #bind-address = 127.0.0.1 в /etc/mysql/mysql.conf.d

  • перезапустите сервер MySQL sudo /etc/init.d/mysql restart

  • выполните следующую команду, чтобы открыть пользователю root доступ к любому хосту mysql -uroot -proot GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES;

  • скрипт создания sh: run_docker.sh

    #! Бен / Баш

    HOSTIP = `ip -4 addr show scope глобальный dev eth0 | grep inet | awk '{print \ $ 2}' | cut -d / -f 1`


      docker run -it -d --name веб-приложение \
                  --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

  
  • работать с docker-composer

    версия: '2.1'

    Сервисы:
    tomcatwar: extra_hosts: - "местный: 10.1.2.232" изображение: sopheamak / springboot_docker_mysql
    порты: - 8080: 8080 окружающая обстановка: - DATABASE_HOST = местный - DATABASE_USER = root - DATABASE_PASSWORD = root - DATABASE_NAME = demo - DATABASE_PORT = 3306


4

На ум приходит несколько решений:

  1. Сначала переместите ваши зависимости в контейнеры
  2. Сделайте ваши другие сервисы доступными извне и подключитесь к ним с этим внешним IP
  3. Запустите ваши контейнеры без изоляции сети
  4. Избегайте подключения по сети, вместо этого используйте сокет, смонтированный как том

Причина, по которой это не работает «из коробки», заключается в том, что контейнеры по умолчанию запускаются с собственным сетевым пространством имен. Это означает, что localhost (или 127.0.0.1, указывающий на интерфейс обратной связи) уникален для каждого контейнера. Подключение к нему приведет к подключению к самому контейнеру, а не к сервисам, работающим вне докера или внутри другого контейнера докера.

Опция 1 : если ваша зависимость может быть перемещена в контейнер, я бы сделал это в первую очередь. Это делает ваше приложение переносимым, так как другие пытаются запустить ваш контейнер в своей среде. И вы по-прежнему можете публиковать порт на своем хосте, где другие службы, которые не были перенесены, все еще могут достичь его. Вы даже можете опубликовать порт в интерфейсе localhost на вашем хосте докера, чтобы избежать его внешнего доступа с помощью синтаксиса, например: -p 127.0.0.1:3306:3306для опубликованного порта.

Вариант 2 Существует множество способов определения IP-адреса хоста внутри контейнера, но у каждого из них есть ограниченное число сценариев, в которых они работают (например, требуется Docker для Mac). Наиболее переносимый вариант - ввести IP-адрес вашего хоста в контейнер с помощью чего-то вроде переменной среды или файла конфигурации, например:

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

Это требует, чтобы ваша служба прослушивала этот внешний интерфейс, что может быть проблемой безопасности. Для других методов, чтобы получить IP-адрес узла изнутри контейнера, см. В этом посте .

Вариант 3 : Запуск без изоляции сети, т.е. с--net host , означает, что ваше приложение работает в пространстве имен сети хоста. Это меньше изолирует контейнер, и это означает, что вы не можете получить доступ к другим контейнерам через общую докерную сеть с DNS (вместо этого вам нужно использовать опубликованные порты для доступа к другим контейнерам приложений). Но для приложений, которым требуется доступ к другим службам на хосте, которые только прослушивают на 127.0.0.1хосте, это может быть самым простым вариантом.

Вариант 4. Различные сервисы также разрешают доступ через сокет на основе файловой системы. Этот сокет может быть подключен к контейнеру в качестве тома с привязкой, что позволяет получить доступ к службе хоста, не выходя в сеть. Для доступа к механизму докера вы часто видите примеры монтирования /var/run/docker.sockв контейнер (предоставляя этому контейнеру корневой доступ к хосту). С mysql, вы можете попробовать что-то вроде, -v /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysql.sockа затем подключиться к localhostкоторой mysql преобразуется в использование сокета.


3

Вы можете получить IP хоста используя альпийское изображение

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

Это будет более последовательным, так как вы всегда используете alpine для запуска команды.

Как и в ответе Мариано, вы можете использовать ту же команду для установки переменной окружения

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

3

Для Linux, где вы не можете изменить интерфейс, к которому привязывается служба localhost

Есть две проблемы, которые нам нужно решить

  1. Получение IP хоста
  2. Сделать наш сервис localhost доступным для Docker

Первая проблема может быть решена с использованием образа docker-host в qoomon , как указано в других ответах.

Вам нужно будет добавить этот контейнер в ту же мостовую сеть, что и ваш другой контейнер, чтобы вы могли получить к нему доступ. Откройте терминал внутри вашего контейнера и убедитесь, что вы можете пинговать dockerhost.

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

Теперь проблема сложнее, сделать сервис доступным для докера.

Мы можем использовать telnet, чтобы проверить, можем ли мы получить доступ к порту на хосте (вам может понадобиться установить это).

Проблема в том, что наш контейнер будет иметь доступ только к службам, которые связаны со всеми интерфейсами, такими как SSH:

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

Но сервисы, привязанные только к localhost, будут недоступны:

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

Надлежащим решением здесь было бы связать сервис с докерской мостовой сетью. Однако этот ответ предполагает, что вы не можете изменить это. Так что вместо этого мы будем использовать iptables.

Во-первых, нам нужно найти имя сети моста, с которой использует Docker ifconfig. Если вы используете безымянный мост, это будет просто docker0. Однако, если вы используете именованную сеть, у вас будет мост, начинающийся с br-того, что вместо него будет использоваться докер. Мой есть br-5cd80298d6f4.

Как только у нас будет имя этого моста, нам нужно разрешить маршрутизацию от этого моста к localhost. По умолчанию это отключено по соображениям безопасности:

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

Теперь, чтобы настроить наше iptablesправило. Поскольку наш контейнер может получать доступ только к портам в сети Docker Bridge, мы будем притворяться, что наш сервис фактически привязан к порту в этой сети.

Для этого мы отправим все запросы <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>

Например, для моего сервиса на порту 1025

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

Теперь вы сможете получить доступ к своему сервису из контейнера:

bash-5.0# telnet dockerhost 1025
220 127.0.0.1 ESMTP Service Ready

1
Это то же самое, что @ ray-d упомянул выше, но хорошо объяснено. Спасибо! Кроме того, при использовании docker-compose мне также пришлось добавить правило DNAT в цепочке PREROUTING для всех пакетов, поступающих также на интерфейс docker0: поскольку, похоже, что docker-compose использует docker0 во время сборок (на удивление не во время выполнения): sysctl -w net.ipv4.conf.docker0.route_localnet=1иiptables -t nat -A PREROUTING -p tcp -i docker0 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025
Арвинд

3

Вам нужно знать ворота ! Мое решение с локальным сервером состояло в том, чтобы открыть его под 0.0.0.0:8000, затем запустить docker с подсетью и запустить контейнер как:

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>

Итак, теперь вы можете получить доступ к петле через http://172.35.0.1:8000


3

Попробуй это:

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

Получить 192.168.1.202 , используетifconfig

Это сработало для меня. Надеюсь, это поможет!


2

CGroups и пространства имен играют главную роль в экосистеме контейнера.

Пространство имен обеспечивает уровень изоляции. Каждый контейнер работает в отдельном пространстве имен, и его доступ ограничен этим пространством имен. Cgroups контролирует использование ресурсов каждого контейнера, тогда как Namespace контролирует, что процесс может видеть и получать доступ к соответствующему ресурсу.

Вот базовое понимание подхода к решению, который вы могли бы использовать,

Использовать пространство имен сети

Когда контейнер появляется из образа, определяется и создается сетевой интерфейс. Это дает контейнеру уникальный IP-адрес и интерфейс.

$ docker run -it alpine ifconfig

Изменяя пространство имен на хост, сети 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. Это создаст новую сеть и пространство имен процесса. Этот контейнер будет привязан к порту 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 на хосте, запустить и отладить ваше приложение. Но не рекомендуется идти по этому пути. Надеюсь, поможет.


1

Для Windows Machine: -

Выполните команду ниже, чтобы случайно открыть порт Docker во время сборки

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

введите описание изображения здесь

введите описание изображения здесь

В приведенном выше списке контейнеров вы можете видеть порт, назначенный как 32768. Попробуйте получить доступ

localhost:32768 

Вы можете увидеть страницу MediaWiki


5
Хотя этот ответ может предоставить полезную информацию для некоторых пользователей, это неправильный путь ! Речь идет о доступе к службе, запущенной в контейнере, с хост-машины. Вопрос, однако, заключался в доступе к службе, работающей на хосте, из контейнера.
Эйнджон


1

Я решил это, создав пользователя в MySQL для ip контейнера:

$ 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

Затем на контейнере: jdbc:mysql://<b>172.17.0.1</b>:3306/database_name


Это самое простое решение. Это сработало для меня, и я упомянул многих
Сопия Альфред

-1

Я делаю это, передавая IP-адрес хоста как переменную среды контейнеру. Затем контейнер получает доступ к хосту по этой переменной.


Можете ли вы проиллюстрировать, как вы это делаете? Я
пробовал

`docker run -i -t -e HOST = 10.145.2.123 ubuntu root @ ce2a843da3ee: / tmp # ./telnet $ HOST 22 Попытка 10.145.2.123 ... Подключена к 10.145.2.123. Экранирующий символ - «^]». SSH-2.0-OpenSSH_7.4`
Ф. Кам
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.