Как получить доступ к порту хоста из контейнера докеров
У меня есть докер-контейнер, в котором работают дженкинсы. В рамках процесса сборки мне нужно получить доступ к веб-серверу, который выполняется локально на главной машине. Есть ли способ, которым веб-сервер хоста (который может быть настроен для работы на порту) может быть открыт контейнеру jenkins?
EDIT: я запускаю docker изначально на машине Linux.
UPDATE:
В дополнение к @larsks ответьте ниже, чтобы получить IP-адрес хост-IP с хост-машины, я делаю следующее:
ip addr show docker0 | grep -Po 'inet \K[\d.]+'
Ответы
Ответ 1
При запуске Docker изначально на Linux вы можете получить доступ к службам хоста, используя IP-адрес интерфейса docker0
. Изнутри контейнера это будет ваш маршрут по умолчанию.
Например, в моей системе:
$ ip addr show docker0
7: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::f4d2:49ff:fedd:28a0/64 scope link
valid_lft forever preferred_lft forever
И внутри контейнера:
# ip route show
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 src 172.17.0.4
Довольно легко извлечь этот IP-адрес с помощью простой оболочки
script:
#!/bin/sh
hostip=$(ip route show | awk '/default/ {print $3}')
echo $hostip
Вам может потребоваться изменить правила iptables
на вашем хосте, чтобы разрешить
соединения из контейнеров Docker. Что-то вроде этого будет делать
Хитрость:
# iptables -A INPUT -i docker0 -j ACCEPT
Это позволит получить доступ к любым портам на хосте от Docker
контейнеры. Обратите внимание:
-
Правила iptables упорядочены, и это правило может или не может выполнять
правильная вещь в зависимости от того, какие другие правила приходят перед ней.
-
вы сможете получить доступ только к хост-сервисам, которые либо (а)
прослушивание INADDR_ANY
(aka 0.0.0.0) или явно
прослушивание интерфейса docker0
.
Ответ 2
Для macOS и Windows
Docker v 18.03 и выше (с 21 марта 2018 г.)
Используйте свой внутренний IP-адрес или подключитесь к специальному DNS-имени host.docker.internal
который будет host.docker.internal
во внутренний IP-адрес, используемый хостом.
Ожидается поддержка Linux https://github.com/docker/for-linux/issues/264
MacOS с более ранними версиями Docker
Докер для Mac v 17.12 до 18.02
То же, что и выше, но вместо этого используйте docker.for.mac.host.internal
.
Докер для Mac с 17.06 по 17.11
То же, что и выше, но вместо этого используйте docker.for.mac.localhost
.
Докер для Mac 17.05 и ниже
Чтобы получить доступ к хост-машине из док-контейнера, вы должны прикрепить IP-псевдоним к вашему сетевому интерфейсу. Вы можете связать любой IP-адрес, который хотите, просто убедитесь, что вы не используете его ни с чем другим.
sudo ifconfig lo0 alias 123.123.123.123/24
Затем убедитесь, что ваш сервер прослушивает IP-адрес, упомянутый выше или 0.0.0.0
. Если он прослушивает localhost 127.0.0.1
он не примет соединение.
Затем просто укажите свой док-контейнер на этот IP, и вы получите доступ к хост-машине!
Для тестирования вы можете запустить что-то вроде curl -X GET 123.123.123.123:3000
внутри контейнера.
Псевдоним будет сбрасываться при каждой перезагрузке, поэтому при необходимости создайте сценарий запуска.
Решение и дополнительная документация здесь: https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds
Ответ 3
Используйте --net="host"
в вашей команде docker run
--net="host"
, тогда localhost
в вашем контейнере Docker будет указывать на ваш хост Docker.
Ответ 4
Решение с docker-compose: для доступа к сервису на основе хоста вы можете использовать параметр network_mode
https://docs.docker.com/compose/compose-file/#network_mode
version: '3'
services:
jenkins:
network_mode: host
Ответ 5
В настоящее время самый простой способ сделать это на Mac и Windows - использовать host host.docker.internal
, который разрешает IP-адрес хост-машины. К сожалению, он не работает на Linux (по состоянию на апрель 2018 года).
Ответ 6
Я создал Docker-контейнер для выполнения именно этого https://github.com/qoomon/docker-host
Затем вы можете просто использовать имя контейнера dns для доступа к хост-системе, например
curl http://dockerhost:9200
Ответ 7
Мы обнаружили, что более простым решением для всего этого сетевого мусора является использование доменного сокета для службы. Если вы все равно пытаетесь подключиться к хосту, просто смонтируйте сокет как том, и вы уже в пути. Для postgresql это было так просто:
docker run -v /var/run/postgresql:/var/run/postgresql
Затем мы просто настраиваем соединение с нашей базой данных, чтобы использовать сокет вместо сети. Буквально так просто.
Ответ 8
Вы можете получить доступ к локальному веб-серверу, который работает на вашем хост-компьютере, двумя способами.
-
Подход 1 с публичным IP
Используйте общедоступный IP-адрес хост-машины для доступа к веб-серверу в контейнере док-станции Jenkins.
-
Подход 2 с хост-сетью
Используйте "--net host" для добавления док-контейнера Jenkins в стек сети хоста. Контейнеры, развернутые в стеке хоста, имеют полный доступ к интерфейсу хоста. Вы можете получить доступ к локальному веб-серверу в Docker-контейнере с частным IP-адресом хост-машины.
NETWORK ID NAME DRIVER SCOPE
b3554ea51ca3 bridge bridge local
2f0d6d6fdd88 host host local
b9c2a4bc23b2 none null local
Запустите контейнер с хост-сетью. Eg: docker run --net host -it ubuntu
и запустите ifconfig
чтобы получить список всех доступных сетевых IP-адресов, доступных из док-контейнера.
Например: я запустил сервер nginx на своем локальном хост-компьютере и смог получить доступ к URL-адресам веб-сайтов nginx из док-контейнера Ubuntu.
docker run --net host -it ubuntu
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a604f7af5e36 ubuntu "/bin/bash" 22 seconds ago Up 20 seconds ubuntu_server
Доступ к веб-серверу Nginx (работающему на локальном хосте) из док-контейнера Ubuntu с IP-адресом частной сети.
[email protected]:/# curl 192.168.x.x -I
HTTP/1.1 200 OK
Server: nginx/1.15.10
Date: Tue, 09 Apr 2019 05:12:12 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 Mar 2019 14:04:38 GMT
Connection: keep-alive
ETag: "5c9a3176-264"
Accept-Ranges: bytes
Ответ 9
Я изучил различные решения и нашел это наименее хакерское решение:
- Определите статический IP-адрес для IP-адреса шлюза моста.
- Добавьте IP-адрес шлюза в качестве дополнительной записи в директиву
extra_hosts
.
Единственным недостатком является то, что если у вас есть несколько сетей или проектов, вы должны убедиться, что их диапазон IP-адресов не конфликтует.
Вот пример Docker Compose:
version: '2.3'
services:
redis:
image: "redis"
extra_hosts:
- "dockerhost:172.20.0.1"
networks:
default:
ipam:
driver: default
config:
- subnet: 172.20.0.0/16
gateway: 172.20.0.1
Затем вы можете получить доступ к портам на хосте из контейнера, используя имя хоста "dockerhost".
Ответ 10
Когда у вас есть два изображения докеров, которые уже созданы, и вы хотите связать два контейнера друг с другом.
Для этого вы можете удобно запускать каждый контейнер со своим собственным именем и использовать флаг -link для обеспечения связи между ними. Вы не получите этого во время сборки докеров.
Когда вы находитесь в таком сценарии, как я, и это ваш
docker build -t "centos7/someApp" someApp/
Это ломается, когда вы пытаетесь
curl http://172.17.0.1:localPort/fileIWouldLikeToDownload.tar.gz > dump.tar.gz
и вы застряли на "curl/wget", не возвращающем "маршрут к хосту".
Причиной является безопасность, установленная на месте докерером, которая по умолчанию запрещает связь с контейнером по отношению к хосту или другим контейнерам, запущенным на вашем хосте.
Это было довольно неожиданно для меня, я должен сказать, вы ожидаете, что эхосистемы докеровских машин, работающих на локальной машине, просто безупречно могут получить доступ друг к другу без особого препятствия.
Объяснение этого подробно описано в следующей документации.
http://www.dedoimedo.com/computers/docker-networking.html
Приводятся два быстрых обхода, которые помогут вам двигаться, снижая сетевую безопасность.
Самая простая альтернатива - просто отключить брандмауэр - или разрешить все. Это означает, что нужно выполнить необходимую команду, которая может быть остановлена на системной остановке firewalld, iptables -F или эквивалентной.
Надеемся, что эта информация поможет вам.