Як з’єднатися з локальним контейнером Docker зсередини контейнера Docker?


1447

Отже, у мене Nginx працює в контейнері docker, у мене mysql працює на localhost, я хочу підключитися до MySql всередині свого Nginx. MySql працює на localhost і не відкриває порт зовнішньому світу, тому його прив'язує до localhost, не пов'язаному з ip адресою машини.

Чи є спосіб підключитися до цього MySql або будь-якої іншої програми на localhost з цього контейнера докера?

Це питання відрізняється від "Як отримати IP-адресу докерного хоста зсередини докерного контейнера" ​​через те, що IP-адреса хокера докера може бути загальнодоступним IP або приватним IP в мережі, яка може або може не можна досягти зсередини докерного контейнера (я маю на увазі загальнодоступний IP, якщо він розміщений на AWS або щось подібне). Навіть якщо у вас IP-адреса хокера докера, це не означає, що ви можете підключитися до хокера докера зсередини контейнера, враховуючи, що IP-адреса як вашої мережі Докер може бути перекритою, хостом, мостом, macvlan, жодним тощо, що обмежує доступність та IP-адреса.


Чому б також не прив’язати mysql до docker0?
ivant

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


Без цього network: hostви не можете повернутися з контейнера до хоста. Тільки хост для контейнера. Це основна ідеологія за контейнерами. Вони відокремлені як з міркувань стабільності, так і з безпеки.
FreeSoftwareServers

Відповіді:


1967

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

Станом на Docker 18.09.3, це не працює на Docker-for-Linux. Виправлення було представлено на 8 березня, 2019 і ми сподіваємося , будуть об'єднані в базу коду. До цього часу вирішується використання контейнера, як описано у відповіді qoomon .

2020-01: досягнуто певного прогресу . Якщо все піде добре, це має приземлитися в Докер 20.04


TLDR

Використовуйте --network="host"у вашій docker runкоманді, тоді 127.0.0.1ваш контейнер докера буде вказувати на вашого хокера докера.

Примітка. Цей режим працює лише на Docker для Linux відповідно до документації .


Зверніть увагу на режими роботи мережі контейнерів докер

Docker пропонує різні режими роботи мережі під час запуску контейнерів. Залежно від обраного режиму ви підключитесь до своєї бази даних MySQL, що працює на хості докера по-різному.

docker run --network = "міст" (за замовчуванням)

Docker створює міст, названий docker0за замовчуванням. IP-хост і контейнер докера мають 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 . Такий контейнер буде спільним мережевим стеком з хостом докера, і з точки зору контейнера 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 socket.


8
Дякую за таку детальну відповідь! З того, що я зібрав, використання хост-режиму - єдиний спосіб отримати цю функціональність через localhost. Я не намагався, але я б припустив, що ви можете створити окрему мережу для з'єднання контейнерів через власний міст, пропонуючи їм загальний "localhost".
Бен

26
Примітка для користувачів OSX: спочатку увійдіть у свою віртуальну машину docker (boot2docker), використовуючи "docker-machine ssh за замовчуванням", після чого запустіть "sudo ip addr show docker0". Продовжуйте звідти інструкції Томаса.
Charlie Dalsass

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.
chx

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/isissue/264

MacOS з більш ранніми версіями Docker

Докер для Mac v 17.12 до 18.02

Те саме, що вище, але використовувати docker.for.mac.host.internalзамість цього.

Докер для Mac v 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. Але для цілей розвитку це досить добре.
99Соно

Як я можу отримати доступ до порту, який відкривається в скажімо, 9093 .. Я намагаюся дозволити telnet docker.for.mac.localhost 9093. Це недосяжно, але якщо я пінг docker.for.mac.localhost, його досяжність. Я щось тут пропускаю?
Ахілл

1
Ім’я DNS docker.for.mac.host.internal слід використовувати замість docker.for.mac.localhost (досі діє) для роздільної здатності хоста з контейнерів, оскільки існує RFC, що забороняє використання піддоменів localhost. Див. Інструменти.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 БД).
Хорхе Орпінель

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 в будь-якій службі, до якої потрібен ваш контейнер для докерів.
Ендерленд

2
Я злегка модифікували своє рішення , щоб бути сумісним з одними мережами: export DOCKERHOST=$(docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}}{{end}}' <NETWORK-NAME> | awk -F "/" 'NR==1{print $1}') Де <NETWORK-NAME> може бути міст або назва мережі , як це визначено Докер-композит (зазвичай шлях-ім'я - network_name ).
діресіс

1
Потрібно додати коментар: використовувати dockerhostяк хост для db-з'єднання (як правило, замінити на localhostконфігураційний файл).
Джастін

дивне рішення, але це єдине, що змушує xdebug працювати під Docker з php cli
Едді

Acl перестав працювати після цього розчину в гапрокси. Будь-яка ідея чому?
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 зовні (якщо не використовується брандмауер).
користувач1226868

5
Розетки не масштабуються так само, як TCP, оскільки вони частіше блокують і можуть спричинити дивну поведінку. Використовуйте TCP, коли це можливо.
Joel E Salas

3
@JoelESalas У вас є джерело для цієї претензії?
Приват

Я знайшов це найпростішим рішенням. Великий палець на користувача833482! Ви повинні частіше сприяти 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).

Гаразд, ваш сервер localhost має інтерфейс докер-інтерфейсу docker0 з ip адресою 172.17.0.1 . Ваш контейнер розпочався з мережевих налаштувань за замовчуванням --net = "міст" .

  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 до мого localhost, на якому було запущено Azure Storage EmulatorіCosmosDB Emulator .

За Azure Storage Emulatorзамовчуванням прослуховується 127.0.0.1 , в той час як ви можете змінити IP-межу, також я шукав рішення, яке би працювало з налаштуваннями за замовчуванням.

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


13

Дуже просто і швидко, перевірте свій хост-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" та порт вашого хоста, в якому працює БД


У HaProxy це рішення чомусь перестало працювати з acl, працює лише налаштування за замовчуванням.
HyukHyukBoi

1
Єдине рішення, яке працює в системі Linux. +1
Рафік Фархад

11

Жодна з відповідей не працювала для мене під час використання Docker Toolbox в Windows 10 Home, але 10.0.2.2 зробив це, оскільки він використовує VirtualBox, який виставляє хост до VM за цією адресою.


2
Це працює. Навіть не потрібно вказувати --network = хост. виглядає так, що 10.0.2.2 встановлений як IP за замовчуванням для хоста. Дякую.
TheManish

Але чи можу я використовувати цей статичний IP для всіх версій Windows та Mac? Як я можу обробляти його для декількох платформ за допомогою скрипту?
151291

Це працювало для мене. Просто запустіть ipconfig на своєму хості (windows) та отримайте IP-адресу підEthernet adapter vEthernet (DockerNAT)
Kihats

10

Для тих, хто в Windows, припускаючи, що ви використовуєте драйвер мостової мережі, вам потрібно спеціально прив’язати MySQL до ip-адреси мережевого інтерфейсу гіпер-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


По-перше, моя відповідь спрямована на дві групи людей: тих, хто використовує 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дзвінка) всередині вашого контейнера, ви побачите, що мережеві інтерфейси ті ж, що і на хості Докера (наприклад, ваш ноутбук).

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

Ось так ви підключаєте контейнер NGINX до MySQL, що працює на localhost.


1
Важливо зауважити, що хост- режим пропонує кращу продуктивність, оскільки він використовує мережевий стек ОС.
sivabudh

2
Дуже хороший момент. Хоча можливо підключитись із контейнера до хост-сервісу з невикористаним IP- файлом docs.docker.com/docker-for-mac/networking . Не приємне рішення ... але працює.
Xavier Huppé

Хороші речі тут. Як потрапив всередину контейнера з --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-клієнта та сервера на контейнер докера.
Майкл

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 відкрити db для зовнішнього світу, що не тільки дуже погано, але й суперечить тому, що хоче зробити автор. Він прямо говорить: "MySql працює на localhost і не відкриває порт зовнішньому світу, тому він пов'язаний з localhost"

Щоб відповісти на коментар ivant

"Чому б не прив'язати також mysql до docker0?"

Це неможливо. У документації на mysql / mariadb прямо вказано, що не можна прив'язуватися до кількох інтерфейсів. Ви можете прив'язати лише 0, 1 або всі інтерфейси.

Як висновок, я НЕ знайшов жодного способу дістатися до бази даних (лише localhost) на хості з контейнера докера. Це безумовно здається дуже поширеною схемою, але я не знаю, як це зробити.


4
з хоста докера ви все ще можете підключитися до сервера MySQL за допомогою 172.17.42.1адреси. Але ваша примітка правильна інакше. Так само я відредагував свою відповідь у hostрежимі мереж, який дозволяє тримати прив’язаний сервер MySQL 127.0.0.1, дозволяючи контейнерам підключатися до нього
Thomasleveil

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

4

Ось моє рішення: воно працює для мого випадку

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

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

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

  • створити скрипт sh: run_docker.sh

    #! бін / баш

    HOSTIP = `ip -4 addr показати область глобальної розробки eth0 | grep inet | awk '{print \ $ 2}' | вирізати -d / -f 1`


      docker run -it -d - назва веб-програми \
                  --add-host = local: $ {HOSTIP} \
                  -p 8080: 8080 \
                  -e DATABASE_HOST = $ {HOSTIP} \
                  -е DATABASE_PORT = 3306 \
                  -e DATABASE_NAME = демонстрація \
                  -e DATABASE_USER = корінь \
                  -e DATABASE_PASSWORD = корінь \
                  sopheamak / springboot_docker_mysql

  
  • бігати з докер-композитором

    версія: '2.1'

    послуги:
    tomcatwar: extra_hosts: - "місцевий: 10.1.2.232" зображення: sopheamak / springboot_docker_mysql
    порти: - 8080: 8080 навколишнє середовище: - DATABASE_HOST = локальний - DATABASE_USER = корінь - DATABASE_PASSWORD = корінь - DATABASE_NAME = демонстрація - 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 : Різні сервіси також дозволяють отримати доступ через сокет на основі файлової системи. Ця розетка може бути встановлена ​​в контейнер у вигляді прив'язуваного об'єму, що дозволяє отримувати доступ до послуги хоста, не переходячи через мережу. Для доступу до двигуна docker ви часто бачите приклади встановлення /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}'

Це було б більш послідовно, оскільки ви завжди використовуєте альпійський для виконання команди.

Подібно до відповіді Маріано, ви можете використовувати ту саму команду, щоб встановити змінну середовища

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

3

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

Ми маємо вирішити дві проблеми

  1. Отримання IP хоста
  2. Зробити нашу послугу localhost доступною для Docker

Першу проблему можна вирішити за допомогою зображення докера -хоста 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.

По-перше, нам потрібно знайти назву мостової мережі, якою використовується докер 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

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
arvindd

3

Вам потрібно знати шлюз ! Моє рішення з локальним сервером полягало в тому, щоб виставити його під 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


2

CGroups та Namespace відіграють головну роль в екосистемі контейнерів.

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

Ось основне розуміння підходу до рішення, якого ви можете дотримуватися,

Використовуйте мережевий простір імен

Коли контейнер нереалізований із зображення, визначається і створюється мережевий інтерфейс. Це дає контейнеру унікальну IP-адресу та інтерфейс.

$ docker run -it alpine ifconfig

Змінюючи простір імен на хост, мережі контейнерів не залишаються ізольованими до свого інтерфейсу, процес отримає доступ до мережевого інтерфейсу хост-машин.

$ 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 на хості, запустити та налагодити свою програму. Але, не рекомендую йти цим шляхом. Сподіваюся, це допомагає.


2

Спробуйте це:

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

Це працювало для мене. Сподіваюся, що це допоможе!


1

Для машини Windows:

Запустіть команду нижче, щоб відкрити докерський порт випадковим чином під час збирання

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

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

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

У наведеному вище списку контейнерів ви бачите порт, призначений як 32768. Спробуйте отримати доступ

localhost:32768 

Ви можете побачити сторінку mediawiki


5
Хоча ця відповідь може надати корисну інформацію для деяких користувачів, це неправильно ! Йдеться про доступ до послуги, що працює в контейнері, з хост-машини. Питання, однак, стосувалося доступу до послуги, що працює на хості з контейнера.
einjohn


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-хост як змінну середовища в контейнер. Потім контейнер отримує доступ до хоста за допомогою цієї змінної.


Чи можете ви проілюструвати, як ви це робите? Я спробував такий підхід, але не досяг великого успіху
kmjb

`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.