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

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

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

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


person Phil    schedule 20.06.2014    source источник
comment
Почему бы также не привязать mysql к docker0?   -  person ivant    schedule 20.06.2014
comment
Для Windows Machine: - $ docker run -d --name MyWebServer -P httpd   -  person Lokesh S    schedule 17.09.2018
comment
Возможный дубликат Как получить IP-адрес хоста докера из контейнера докера   -  person Nick Grealy    schedule 07.11.2019
comment
Без network: host вы не можете вернуться из контейнера на хост. Только хост в контейнер. Это основная идеология контейнеров. Они изолированы как по соображениям стабильности, так и по соображениям безопасности.   -  person FreeSoftwareServers    schedule 17.05.2020
comment
Привет, stackoverflow.com/a/61001152/418599 - популярное решение для получения действительного внутреннего хоста докера.   -  person Antonio Petricca    schedule 26.05.2021


Ответы (34)


Изменить:

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

Если вы используете Docker-for-Linux 20.10.0+, вы также можете использовать хост host.docker.internal , если вы запустили свой контейнер Docker с параметром --add-host host.docker.internal:host-gateway.

В противном случае читайте ниже


TL; DR

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

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


Примечание о сетевых режимах контейнера докеров

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

В качестве альтернативы вы можете запустить контейнер докеров с настройками сети, установленными на 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.1 IP-адресе.

Для этого убедитесь, что в вашем конфигурационном файле MySQL (my.cnf) указано значение bind-address = 172.17.42.1 или bind-address = 0.0.0.0.

Если вам нужно установить переменную среды с 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.1 IP-адрес.

режим хоста

Чтобы получить доступ к 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.

person Thomasleveil    schedule 20.06.2014
comment
Спасибо за столь подробный ответ! Из того, что я собрал, использование режима хоста - единственный способ получить эту функциональность через localhost. Я не пробовал, но предполагаю, что вы можете создать отдельную сеть для подключения контейнеров через их собственный мост, предлагая им общий «localhost». - person Ben; 12.05.2015
comment
На странице docs.docker.com/articles/networking также есть руководство по расширенным сетевым технологиям. - person Thomasleveil; 12.05.2015
comment
Примечание для пользователей OSX: сначала войдите в свою виртуальную машину docker (boot2docker), используя docker-machine ssh по умолчанию, затем запустите sudo ip addr show docker0. Продолжайте оттуда следовать инструкциям Томаса. - person Charlie Dalsass; 02.10.2015
comment
Я использую Docker для Mac, и больше нет ни 172.17.42.1, ни docker0. Это был шлюз 172.17.0.1, и даже telnet 172.17.0.1 3306 не может - person zx1986; 30.06.2016
comment
Есть причина, по которой они не пытались упростить это. Лучше также докерировать все зависимости, что позволит вам обойти всю эту проблему. - person Jonah; 10.08.2016
comment
Вы можете смонтировать сокет mysql в контейнер вместо того, чтобы работать в сети, как -v /var/run/mysqld/mysqld.sock:/tmp/mysql.sock this. - person chx; 02.09.2016
comment
Может ли кто-нибудь решить ситуацию, когда у вас запущен Docker на Mac и не используется boot2docker, как таковой интерфейс docker0 отсутствует? - person TheJKFever; 09.02.2017
comment
если вы получаете отказ в доступе изнутри контейнера докеров, вам может потребоваться разрешить root-доступ за пределами localhost с помощью GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION; - person ospider; 13.07.2017
comment
Для всех, кто пытается подключиться к хост-службе и запускает Docker для Mac. Существует специальное DNS-имя docker.for.mac.host.internal только для Mac, которое разрешается во внутренний IP-адрес, используемый хостом. источник - person MikeV; 22.03.2018
comment
Последняя версия Docker поддерживает host.docker.internal в качестве доменного имени из контейнера (согласно последнему обновлению в ответе @Janne Annala >). В дальнейшем это кажется более общим решением, когда вам все еще нужен некоторый уровень изоляции между сетью контейнера и хоста. - person funseiki; 19.04.2018
comment
--net=host прерывает трансляцию опубликованного порта, так что если контейнер предоставляет порт 80 (используя --publish XXX:80 или проще -p XXX:80, тогда, если служба на хосте уже привязана к порту 80 (экземпляр докера или собственная служба хоста), то контейнер не сможет привязать порт 80. Так что ни в коем случае не годится. - person Eric; 02.05.2018
comment
если вы используете Mac, хост-система не будет показывать вам на хосте (Mac) IP-адрес для сети brdige. Поэтому, когда вы хотите связаться с Mac, докер-машиной, вам нужно использовать переадресацию порта -p AnyPort1: Anyport2 и использовать localhost. С другой стороны, с док-машины будет работать что-то вроде этого: telnet host.docker.internal 445 - person 99Sono; 17.11.2019
comment
Вы можете видеть направления Mac, начиная с версии Docker 18.03, ссылаясь на host.docker.internal здесь - person Zephaniah Grunschlag; 08.05.2020
comment
Просто попробовал --network="host" в Docker Desktop для Windows (2.3.0.2), и он работал отлично. - person Loek; 21.05.2020
comment
Это с достаточным отрывом один из 5 лучших ответов, которые я получил на SO! Thomasleveil спасибо за вашу ATI (внимание, время и интерес) ‹3 @ iam.Carrot огромное спасибо за поддержание этого ответа: plusone: и: thumbsup: - person walt_die; 12.06.2020
comment
Это частично решило мою проблему - host.docker.internal работал отлично. Однако я пытаюсь получить доступ к сайту IIS, размещенному локально, и получаю сообщение об ошибке SSL, потому что, конечно, у меня нет сертификата SSL для host.docker.internal. Есть ли способ создать локальный сертификат для этого использования? - person Peter Tirrell; 02.07.2020
comment
@PeterTirrell У меня та же проблема, что вы описали. Вы смогли найти решение? - person massaskillz; 23.07.2020
comment
@massaskillz, правда, не знал. В моем случае я использовал внутренний класс-оболочку вокруг HttpClient для выполнения вызова, поэтому я настроил HttpClientHandler.ServerCertificateCustomValidationCallback, чтобы в основном перехватывать любые ошибки проверки SSL и игнорировать их, если RequestUri содержит host.docker.internal. Это взломано, но заставило меня отладить. - person Peter Tirrell; 27.07.2020
comment
Этот ответ заслуживает 100 голосов, но я не могу этого сделать. - person Shamim; 05.08.2020
comment
Запуск докера типа: docker run --rm -d -p 5000:5000/tcp mytestimage:latest --network="host" не работает. Я получаю сообщение об ошибке, что не удается подключиться к 127.0.0.1. Единственное, что сработало, было в моем коде C #, использующем host.docker.internal вместо localhost или 127.0.0.1. Есть идеи, почему это не работает на Docker в Windows? - person Don Rhummy; 21.09.2020
comment
Замечательный ответ! Я просто хотел добавить, что для того, чтобы это работало в docker-compose.yml, вы должны добавить extra-hosts entry с host.docker.internal:host-gateway, как и с docker run --add-host. Возможно, @Thomasleveil тоже мог бы добавить это в верхнюю правку. Мне потребовалось немного времени, чтобы понять это. - person kzu; 22.05.2021
comment
работает ли это для контейнеров Windows - похоже, нет. - person Dzmitry Lahoda; 14.07.2021

Для macOS и Windows

Docker версии 18.03 и выше (с 21 марта 2018 г.)

Используйте свой внутренний IP-адрес или подключитесь к специальному DNS-имени host.docker.internal, которое будет преобразовано во внутренний IP-адрес, используемый хостом.

Ожидается поддержка Linux https://github.com/docker/for-linux/issues/264 < / а>

MacOS с более ранними версиями Docker

Docker для Mac версий 17.12–18.02

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

Docker для Mac версий 17.06–17.11

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

Docker для 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

person Janne Annala    schedule 21.04.2017
comment
великолепно и спасибо, это сработало для меня изнутри контейнера. mysql -uroot -hdocker.for.mac.localhost - person Richard Frank; 22.07.2017
comment
docker.for.mac.localhost Это именно то, что я искал. Но в то же время это чертовски грязно. В docker можно было бы ожидать, что хук docker.for.mac.localhost будет общим внутренним именем докера, которое будет действительным для любой операционной системы, а не только для Mac. Но для целей разработки этого достаточно. - person 99Sono; 03.12.2017
comment
DNS-имя docker.for.mac.host.internal следует использовать вместо docker.for.mac.localhost (все еще действующее) для разрешения хоста из контейнеров, поскольку существует RFC, запрещающий использование поддоменов localhost. См. tools.ietf.org/html/draft-west -let-localhost-be-localhost-06. - person Jya; 19.02.2018
comment
У меня это не работает. Когда я docker run -e HOSTNAME= docker.for.mac.host.internal , контейнер создается, но ничего не происходит. Мне нужно тогда crtl + C. По крайней мере, с --net=host -e HOSTNAME=localhost контейнер работает и жалуется, что не может найти нужную мне службу (MySQL db). - person Jorge Orpinel Pérez; 11.03.2018
comment
Так быстро и полезно. Спасибо! - person iedmrc; 18.09.2020
comment
Большое спасибо, поле docker.for.mac.host.internal работает для macOs - person quento; 28.10.2020

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

host.docker.internal

вместо того

localhost

у меня работает безупречно. ????

person DeyaEldeen    schedule 27.07.2020
comment
Может быть, этот ответ можно было бы немного расширить и уточнить? Означает ли это, что вы все еще можете использовать режим моста? - person Jolta; 08.10.2020
comment
У меня это не работает, но почему бы и нет? - person Arnold Roa; 04.03.2021
comment
@ArnoldRoa, это будет работать только на Mac / Windows, но не на Linux. - person Shane Cheek; 24.03.2021
comment
Не работает по состоянию на 26.04.2021. host.docker.internal ни к чему не приводит. - person Triynko; 26.04.2021
comment
Не могу воспроизвести проблему @ Triynko - у меня это отлично работает (движок: 20.10.6) - person Kieran E; 12.05.2021
comment
Для настройки host.docker.internal с помощью docker-compose см. stackoverflow.com/a/67158212/243392 - person Brian Burns; 25.05.2021

Я делаю хак, аналогичный приведенным выше сообщениям, чтобы получить локальный 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 см. На странице этот пост с объяснением того, как это работает.

person Mariano Ruiz    schedule 03.08.2016
comment
В зависимости от вашего варианта использования вы можете даже просто использовать здесь значение DOCKERHOST вместо localhost или 0.0.0.0 в любой службе, к которой ваш док-контейнер должен подключаться локально. - person enderland; 15.03.2017
comment
Я немного изменил ваше решение, чтобы оно было совместимо с пользовательскими сетями: 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). - person dieresys; 26.04.2017
comment
Вам необходимо добавить комментарий: используйте dockerhost в качестве хоста для подключения к базе данных (обычно заменяйте localhost в файле конфигурации). - person Justin; 30.06.2017
comment
странное решение, но это единственное, что заставляет xdebug работать под докером с php cli - person Eddie; 16.12.2019
comment
После этого решения в haproxy перестал работать Acl. Есть идеи, почему? - person HyukHyukBoi; 28.01.2020

Это сработало для меня в стеке 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
person user833482    schedule 27.05.2015
comment
Это гораздо более чистое решение, не открывающее доступ к Mysql извне (если не используется брандмауэр). - person user1226868; 06.06.2015
comment
Сокеты не масштабируются так же хорошо, как TCP, потому что они чаще блокируются и могут вызывать странное поведение. По возможности используйте TCP. - person Joel E Salas; 20.01.2016
comment
@JoelESalas У вас есть источник для этого утверждения? - person Private; 13.10.2016
comment
Я обнаружил, что это самое простое решение. Недурно user833482! Вам следует чаще вносить свой вклад в StackOverflow. - person Private; 13.10.2016
comment
@JoelESalas Я думаю, вы ошибаетесь. Клиентская библиотека mysql даже использует сокеты unix по умолчанию при подключении к localhost, а не фактически устанавливает соединение с localhost. Сокет unix позволяет избежать накладных расходов на стек TCP и маршрутизацию и должен работать быстрее. - person M Conrad; 11.01.2017
comment
Это решение в конечном итоге сработало для моего варианта использования подключения logstash, работающего в контейнере, к MariaDB, работающему на моем хосте, с использованием JDBC. Однако есть одна загвоздка: вы должны включить зависимость от JNA. Оставив это как хлебную крошку для других: stackoverflow.com/questions/25918416/ - person Maksym; 05.12.2020

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

Хорошо, ваш сервер localhost имеет интерфейс докеров по умолчанию docker0 с 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).

person Ray D    schedule 27.09.2017
comment
Какова цель второй команды iptable? Я понимаю, что первый - переписать все назначения tcp, соответствующие 172.17.0.1:3306, на 127.0.0.1:3306, но зачем нужна вторая команда iptable? - person Patrick; 12.09.2019
comment
Это сделало мой день! Спасибо, что поделились - person tuna; 27.04.2021

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

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

person qoomon    schedule 17.10.2018
comment
Я могу подтвердить, что это не работает в Docker для Windows 19.03.2 с контейнером Windows. - person KMC; 17.09.2019
comment
есть идеи, как это исправить? (Я не пользователь Windows) - person qoomon; 18.09.2019
comment
Если ваша среда не блокирует порт, который использует mysql, вы можете обращаться к серверу по имени компьютера, на котором он размещен. Поэтому в строке подключения используйте имя вашего компьютера в качестве имени сервера. - person KMC; 18.09.2019
comment
Я могу подтвердить, что это НЕ РАБОТАЕТ в Docker для Windows версии 20.10.5. Это бесит. IP-адрес хоста (из контейнера) меняется случайным образом. Как, черт возьми, я должен развернуть строку подключения, когда IP-адрес хоста изменяется во время выполнения, а host.docker.internal ничего не разрешает? - person Triynko; 26.04.2021
comment
@Triynko как вы определяете ip хоста в данный момент? - person qoomon; 27.04.2021
comment
@Triynko, можете ли вы выполнить следующие команды и сказать мне, удастся ли что-нибудь из них? docker run --rm alpine ping host.docker.internal docker run --rm alpine ping docker.for.win.localhost docker run --rm alpine ping gateway.docker.internal - person qoomon; 27.04.2021

Решение для 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, которые работают локально на моем хосте с настройками порта по умолчанию.

person Ralph Willgoss    schedule 09.11.2017

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

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

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

person Felipe Toledo    schedule 22.03.2019
comment
В HaProxy это решение по какой-то причине перестало работать с acl, работает только настройка по умолчанию. - person HyukHyukBoi; 28.01.2020

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

  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 route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')" ...

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

Чуть менее переносимым является использование host.docker.internal. Это работает в текущих версиях Docker для Windows и Docker для Mac. А в 20.10 в Docker для Linux добавлена ​​возможность, когда вы передаете специальную запись хоста с помощью:

docker run --add-host host.docker.internal:host-gateway ...

host-gateway - это специальное значение, добавленное в Docker 20.10, которое автоматически расширяется до IP-адреса хоста. Для получения дополнительных сведений см. этот PR.

Вариант 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 преобразует в использование сокета.

person BMitch    schedule 30.06.2019
comment
для option2 (единственное, что сработало из всех ответов): следующая команда получает IP-адрес интерфейса, отличного от локального хоста, как на osx, так и на linux: ifconfig | grep 'inet ' | grep -v 127.0.0.1 | awk '{ print $2 }' | head -1 | sed -n 's/[^0-9]*\([0-9\.]*\)/\1/p' - person MichaelMoser; 23.03.2021
comment
--add-host host.docker.internal:host-gateway золотой - person sanmai; 26.05.2021

Для окон,

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

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

person Praveenkumar Beedanal    schedule 07.02.2020
comment
у меня не работает. У меня есть Mac, и я пытаюсь из контейнера php подключиться к localhost mysql. Любая идея ? - person A. Zalonis; 19.04.2020

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

person Elad    schedule 09.11.2018
comment
Оно работает. Даже не нужно указывать --network = host. похоже, что 10.0.2.2 установлен в качестве IP-адреса по умолчанию для хоста. Спасибо. - person TheManish; 27.03.2019
comment
Но могу ли я использовать этот статический IP-адрес для всех версий Windows и Mac? Как я могу обрабатывать его для нескольких платформ с помощью скрипта? - person 151291; 31.03.2020
comment
Это сработало для меня. Просто запустите ipconfig на своем хосте (Windows) и получите IP-адрес в Ethernet adapter vEthernet (DockerNAT) - person Kihats; 02.05.2020

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

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

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

person Casey    schedule 10.12.2016
comment
Вы заслужили медаль! Я работал над этим два полных дня. Спасибо за помощь! - person Michael; 04.08.2017
comment
Я тоже работал над этим два полных дня. Это единственное место в сети, о котором я обнаружил. Microsoft полностью умалчивает об этом, когда говорит о подключении к MSSQL из контейнера Docker. Это заставляет задуматься, заставили ли они когда-нибудь это работать сами! - person Contango; 02.11.2017

Изменить: я закончил прототипирование концепции на 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, вы должны запускать его в режиме хоста. Команда выглядит так:

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

Когда вы выполните ifconfig (вам нужно apt-get install net-tools ваш контейнер для ifconfig, чтобы его можно было вызвать) внутри вашего контейнера, вы увидите, что сетевые интерфейсы такие же, как и на хосте Docker (например, на вашем ноутбуке).

Важно отметить, что я пользователь Mac, но я запускаю Ubuntu под Parallels, поэтому использование Mac не является недостатком. ;-)

Вот как вы подключаете контейнер NGINX к MySQL, работающему на localhost.

person sivabudh    schedule 07.02.2017
comment
Важно отметить, что режим хоста обеспечивает лучшую производительность, поскольку он использует сетевой стек ОС. - person sivabudh; 07.02.2017
comment
Очень хороший момент. Хотя возможно подключение из контейнера к службе хоста с неиспользуемым IP-адресом. docs. docker.com/docker-for-mac/networking. Решение не из приятных ... но работает. - person Xavier Huppé; 24.02.2017
comment
Здесь хорошие вещи. Оказавшись внутри контейнера с --network="host", как, например, подключиться к хосту mysql? - person Mchl; 22.05.2017
comment
@Buccleuch Просто используйте localhost. Посмотрите мой исходный код на GitHub: github.com / sivabudh / system-in-a-box / blob / master / dj_host_docker /. Найдите 'HOST', вы увидите 127.0.0.1 для подключения к Postgresql. - person sivabudh; 22.05.2017
comment
Мне удалось получить доступ к базам данных хоста mysql, установив том в соответствии с @ user833482, и, конечно же, после установки mysql-client и server в контейнер докеров. - person Mchl; 22.05.2017

Самое простое решение для 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

person dansalmo    schedule 17.05.2017
comment
Docker для Mac теперь предоставляет docker.for.mac.host.internal имя хоста. - person Matt; 23.03.2018

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

Оставим это здесь для других, которые могут захотеть выполнять вызовы 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. «Сети»: должен иметь «my-net»

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

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

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

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

person Shirish Hirekodi    schedule 13.07.2019
comment
Именно то, что я искал. Спасибо - person Simar Singh; 20.09.2019
comment
Если вы знаете, что это не ответ на вопрос (а это не так, потому что вопрос конкретно касается localhost), почему вы его публикуете? - person Sly Gryphon; 09.02.2021

Я не согласен с ответом Томаслевейля.

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

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

Чтобы ответить на комментарий ivant

"Почему бы также не привязать mysql к docker0?"

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

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

person orzel    schedule 12.03.2015
comment
с хоста докера вы все еще можете подключиться к серверу MySQL, используя адрес 172.17.42.1. Но в остальном ваша заметка верна. Кроме того, я отредактировал свой ответ в host сетевом режиме, который позволяет сохранять сервер MySQL привязанным к 127.0.0.1, позволяя контейнерам подключаться к нему. - person Thomasleveil; 14.03.2015
comment
нет, как я уже сказал, вы не можете подключиться к 172.17.42.1, если mysql привязан к localhost. - person orzel; 14.03.2015
comment
Привязка mysql к 172.17.42.1 не позволит другим программам использовать базу данных на хосте для доступа к нему. - это неправда. Другие программы могут использовать mysql, им просто нужно подключиться к 172.17.42.1 вместо localhost / 127.0.0.1. - person 0x89; 09.03.2016
comment
Решение проблемы в этом ответе обычно состоит в том, чтобы заставить сервер MySQL привязаться к 0.0.0.0, а затем настроить брандмауэр, чтобы база данных была недоступна из Интернета. - person halfer; 16.06.2017

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

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

person storenth    schedule 23.01.2020

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

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

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

person Binh Ho    schedule 25.04.2020

Вот мое решение: оно работает в моем случае

  • установить публичный доступ к локальному серверу 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

    #!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" образ: sopheamak / springboot_docker_mysql
    порты: - 8080: среда 8080: - DATABASE_HOST = local - DATABASE_USER = root - DATABASE_PASSWORD = root - DATABASE_NAME = demo - DATABASE_PORT = 3306

person sopheamak    schedule 17.07.2017

Для 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>: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
person JShorthouse    schedule 07.09.2019
comment
Это то же самое, что упомянул @ 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 - person arvindd; 26.03.2020

Сначала см. этот ответ о вариантах решения этой проблемы. Но если вы используете docker-compose, вы можете добавить network_mode: host к своей службе, а затем использовать 127.0.0.1 для подключения к локальному хосту. Это лишь один из вариантов, описанных в ответе выше. Ниже вы можете узнать, как я модифицировал docker-compose.yml из https://github.com/geerlingguy/php-apache-container.git:

 ---
 version: "3"
 services:
   php-apache:
+    network_mode: host
     image: geerlingguy/php-apache:latest
     container_name: php-apache
...

+ указывает на добавленную мной строку.


[Дополнительная информация] Это также работало в версии 2.2. и host или просто host работают в docker-compose.

 ---
 version: "2.2"

 services:
   php-apache:
+    network_mode: "host"
        or
+    network_mode: host
...
person Ehsan88    schedule 21.11.2020
comment
Ага. Он работает с: network_mode: host. Теперь может получить доступ к локальным доменным именам / etc / hosts, которые указывают на контейнеры докеров другого проекта. - person Ernestyno; 18.12.2020

Подключитесь к адресу шлюза.

❯ docker network inspect bridge | grep Gateway
                    "Gateway": "172.17.0.1"

Убедитесь, что процесс на хосте прослушивает этот интерфейс или все интерфейсы и запускается после докера. Если вы используете systemd, вы можете добавить следующее, чтобы убедиться, что он запускается после docker.

[Unit]
After=docker.service

Пример

❯ python -m http.server &> /dev/null &
[1] 149976

❯ docker run --rm python python -c  "from urllib.request import urlopen;print(b'Directory listing for' in urlopen('http://172.17.0.1:8000').read())" 
True
person balki    schedule 22.01.2021

Вы можете получить IP-адрес хоста, используя alpine image

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
person hasnat    schedule 11.06.2018

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

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

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

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

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

person mohan08p    schedule 06.09.2017

Я решил это, создав пользователя в 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

person Leandro    schedule 27.09.2019
comment
Это простейшее решение. Это сработало для меня, и я рекомендовал много - person Ole Sopia; 23.04.2020

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

person Duc Trung Mai    schedule 30.11.2020
comment
Работал у меня. Я использовал команду ifconfig и взял первый inet ip, и это кажется правильным - person Amin Shojaei; 25.04.2021

Пока fix не будет объединен в ветку master, чтобы IP-адрес хоста запускался изнутри контейнер:

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

(как предлагает @Mahoney здесь).

person patryk.beza    schedule 22.03.2019

Чтобы все заработало, вам нужно создать конфиг для вашего сервера (caddy, nginx), где основным доменом будет docker.for.mac.localhost. Для этого замените в baseURL http: // localhost / api на http: //docker.for.mac.localhost/api

docker-compose.yml

backend:
  restart: always
  image: backend
  build:
    dockerfile: backend.Dockerfile
    context: .
  environment:
    # add django setting.py os.getenv("var") to bd config and ALLOWED_HOSTS CORS_ORIGIN_WHITELIST
    DJANGO_ALLOWED_PROTOCOL: http
    DJANGO_ALLOWED_HOSTS: docker.for.mac.localhost
    POSTGRES_PASSWORD: 123456
    POSTGRES_USER: user
    POSTGRES_DB: bd_name
    WAITDB: "1"
  volumes:
    - backend_static:/app/static
    - backend_media:/app/media
  depends_on:
    - db

frontend:
  restart: always
  build:
    dockerfile: frontend.Dockerfile
    context: .
  image: frontend
  environment:
    #  replace baseURL for axios
    API_URL: http://docker.for.mac.localhost/b/api
    API_URL_BROWSER: http://docker.for.mac.localhost/b/api
    NUXT_HOST: 0.0.0.0
  depends_on:
    - backend

caddy:
  image: abiosoft/caddy
  restart: always
  volumes:
    - $HOME/.caddy:/root/.caddy
    - ./Caddyfile.local:/etc/Caddyfile
    - backend_static:/static
    - backend_media:/media
  ports:
  - 80:80
  depends_on:
    - frontend
    - backend
    - db

Caddyfile.local

http://docker.for.mac.localhost {

  proxy /b backend:5000 {
    header_upstream Host {host}
    header_upstream X-Real-IP {remote}
    header_upstream X-Forwarded-For {remote}
    header_upstream X-Forwarded-Port {server_port}
    header_upstream X-Forwarded-Proto {scheme}
  }

  proxy / frontend:3000 {
    header_upstream Host {host}
    header_upstream X-Real-IP {remote}
    header_upstream X-Forwarded-For {remote}
    header_upstream X-Forwarded-Port {server_port}
    header_upstream X-Forwarded-Proto {scheme}
  }

  root /

  log stdout
  errors stdout
  gzip
}

http://docker.for.mac.localhost/static {
  root /static
}

http://docker.for.mac.localhost/media {
  root /media
}

django settings.py

ALLOWED_HOSTS = [os.getenv("DJANGO_ALLOWED_HOSTS")]
    
CORS_ORIGIN_WHITELIST = [f'{os.getenv("DJANGO_ALLOWED_PROTOCOL")}://{os.getenv("DJANGO_ALLOWED_HOSTS")}']

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql_psycopg2",
        "NAME": os.getenv("POSTGRES_DB"),
        "USER": os.getenv("POSTGRES_USER"),
        "PASSWORD": os.getenv("POSTGRES_PASSWORD"),
        "HOST": "db",
        "PORT": "5432",
    }
}

nuxt.config.js (переменная baseURL переопределит API_URL среды)

axios: {
  baseURL: 'http://127.0.0.1:8000/b/api'
},
person wiseCoder    schedule 02.07.2020

сервер на хосте прослушивает порт 5000; он отправит строку response from host обратно в качестве ответа

echo "response from host" | nc -l -p 5000

докер по умолчанию работает в режиме моста (это более безопасно, чем в режиме хост-сети); процесс в докере получает адрес ipv4 для первого сетевого интерфейса на хосте, отличного от 127.0.0.1; этот адрес ipv4 передается докеру через переменную окружения HOSTIP; внутри докера есть команда nc, которая подключается к серверу по ip хоста и порту 5000; команда также читает ответ сервера.

HOST=$(ifconfig | grep 'inet ' | grep -v 127.0.0.1 | awk '{ print $2 }' | head -1 | sed -n 's/[^0-9]*\([0-9\.]*\)/\1/p'); docker run -e HOSTIP="${HOST}" --rm -it alpine /bin/sh -c 'echo "greetings from container" | nc $HOSTIP 5000 -v'

Выражение, которое вычисляет IPv4-адрес первого из перечисленных интерфейсов, действительно работает в OSX и Linux:

HOST=$(ifconfig | grep 'inet ' | grep -v 127.0.0.1 | awk '{ print $2 }' | head -1 | sed -n 's/[^0-9]*\([0-9\.]*\)/\1/p')

чтобы сделать его еще более общим: вы можете запустить сервер внутри другого контейнера докеров, который будет выглядеть следующим образом:

docker run --expose 5000 -p :5000:5000 --rm -it alpine /bin/sh -c 'echo "response from host" | nc -l -p 5000'

--expose 5000, контейнер докеров может принимать соединение через порт 5000

-p: 5000: 5000 механизм докеров на стороне хоста прослушивает порт 5000 на любом интерфейсе и перенаправляет соединения на порт 5000 в контейнерной сети (где запущен nc).

person MichaelMoser    schedule 23.03.2021

Для Windows Machine: -

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

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

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

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

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

localhost:32768 

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

person Lokesh S    schedule 17.09.2018
comment
Хотя этот ответ может предоставить полезную информацию для некоторых пользователей, это неправильный путь! Речь идет о доступе к службе , работающей в контейнере, с хост-машины. Однако вопрос касался доступа к службе , работающей на хосте, из контейнера. - person einjohn; 09.05.2019

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

person F. Kam    schedule 06.02.2020
comment
Вы можете проиллюстрировать, как вы это делаете? Я пробовал этот подход, но не добился большого успеха - person kmjb; 17.02.2020
comment
`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` - person F. Kam; 20.02.2020

если вы используете docker-compose, возможно, это сработает:

iptables -I INPUT ! -i eth0 -p tcp --dport 8001 -j ACCEPT

eth0 - это ваш сетевой интерфейс, который подключается к Интернету, а 8081 - порт хост-сервера.

лучший способ для правила iptables - iptables TRACE

person L.T    schedule 15.07.2020

Несмотря на множество длинных, непонятных ответов, короткий. Если ваша сеть моста докеров 172.17.0.0/16, выполните следующие действия:

  1. Привяжите свой контейнер к 172.17.0.1, например. -p 172.17.0.1:8080:8080 (какой бы ни был шлюз в вашей сети моста Docker)
  2. Просто войдите в порт 8080 172.17.0.1, например. curl http://172.17.0.1:8080/ из другого контейнера
person Tires    schedule 25.05.2021