© 2024 WebHive

Доступ из докер-контейнера к сети хоста

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

Комментарии