В ходе работы над одним из проектов критически важным оказалось отладить работу приложения с некоторой заданной конфигурацией Nginx-а, т. к. часть логики была реализована на нём. Не долго думая завернул эту конфигурацию nginx в контейнер, а само приложение было запущено у меня локально. Ну и очевидно, что nginx в контейнере не увидел моего приложения, хотя и приложение и контейнер были запущены на одной и той-же машине. Как же так получилось и что с эти делать?
Ну в общем-то если немного подумать головным мозгом, то проблема вполне очевидна — docker это изоляция и работает он в совей изолированной среде, включая сеть. Взаимодействие с хостом у нас организовано через сеть и среда выполнения docker-а имеет свою подсеть. Доступ к внешнему миру (включая хост, т. е. мой ноутбук) осуществляется через шлюз — специальный сетевой интерфейс доступный внутри контейнера.
И всё бы ничего, но IP адрес шлюза в контейнере динамический и мы не можем ссылаться на него внутри контейнера. В моём случае nginx должен обращаться к приложению, но вот какой IP ему прописать непонятно.
upstream backend {
server <тут динамический IP приложения>:3301;
}
Самый исчерпывающий ответ по этой проблеме нашёл здесь From inside of a Docker container, how do I connect to the localhost of the machine?
Суть в том, чтобы перед запуском контейнера поместить в переменную окружения адрес хоста на котором запущен контейнер, а потом передать его в контейнер и использовать там. Делается это так:
$ 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)
Что тут конкретно происходит примерно понятно, но подробно разбирать регулярки не вижу смысла — достаточно того, что оно работает.
После этого нам лишь надо добавить в конфигурацию контейнера запись о новом хосте используя директиву extra_hosts
ну или если вы запускаете докер вручную. то добавив параметр --add-host
. Это фактически запись, добавляемая в /etc/hosts контейнера.
В моём случае конфигурация docker-compose выглядит так:
version: '2.1'
services:
nginx:
image: <some image>
networks:
- backend
ports:
- "8080:8080"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
extra_hosts:
- "dockerhost:$DOCKERHOST"
networks:
backend:
enable_ipv6: false
driver: bridge
Ну и после этого в конфигурации nginx-а внутри контейнера мы можем ссылаться на наш хост используя имя dockerhost
. Типа вот так:
upstream backend {
server dockerhost:3301;
}
В общем проверено — метод прекрасно работает и существенно расширяет возможности использования docker-а для разработки.
Комментарии