Я перехожу с локального на удаленный Docker, могу ли я узнать общедоступный IP-адрес демона?

avatar
John Somen
8 апреля 2018 в 10:04
112
2
2

Я использую Docker Compose для развертывания своих приложений. В моем docker-compose.yml у меня есть контейнер my-frontend, который должен знать общедоступный IP-адрес серверной части my-backend. Изображение my-frontend — это приложение NodeJS, которое запускается в браузере клиента.

До того, как я сделал это:

my-backend:
  image: my-backend:latest
  ports:
    - 81:80
my-frontend:
  image: my-frontend:latest
  ports:
    - 80:80
  environment:
    - BACKEND=http://localhost:81

Это прекрасно работает, когда я развертываю локальный демон Docker и когда клиент работает локально.

Сейчас я перехожу на удаленный демон Docker. В этой ситуации клиент больше не работает на том же хосте, что и демон Docker. Следовательно, мне нужно изменить переменную среды BACKEND в my-frontend:

  environment:
    - BACKEND=http://<ip-of-daemon>:81

Когда я жестко кодирую <ip-of-daemon> фактический IP-адрес демона Docker, все работает нормально. Но мне интересно, есть ли способ динамически заполнить это? Таким образом, я могу использовать один и тот же docker-compose.yml для любого удаленного демона Docker.

Источник
halfer
8 апреля 2018 в 15:31
0

Если интерфейс хочет иметь возможность связаться с сервером, то вам вообще не нужны порты. Все контейнеры будут присоединены к общей сети, и им будут присвоены сетевые псевдонимы, соответствующие именам контейнеров. Таким образом, ваш интерфейс может просто получить доступ к http://my-backend:81. Я бы предложил удалить эти записи port, если вам также не нужно выставлять их внешнему миру.

John Somen
8 апреля 2018 в 18:30
0

@halfer Мне нужно открыть порт бэкэнда и внешнего интерфейса. Образ внешнего интерфейса представляет собой контейнер nginx, который обслуживает файлы JS. Он вставляет переменную BACKEND в исходный код перед обслуживанием. Таким образом, интерфейс работает в браузере клиента вне сети докеров. Он должен иметь возможность связываться с серверной частью, поэтому этот порт также должен присутствовать.

halfer
8 апреля 2018 в 18:32
0

Хорошо, достаточно честно. Тем не менее, мое замечание остается в силе — попробуйте установить оболочку на внешний контейнер и пропинговать внутреннее сетевое имя my-backend. Таким образом, в Docker Compose вам не нужно знать его IP — достаточно использовать имя.

John Somen
8 апреля 2018 в 18:40
0

Контейнер my-frontend — это выделенный процесс nginx, отвечающий за обслуживание JS-файлов при вставке внутреннего URL-адреса в один из этих файлов. Однако клиент — это какой-то браузер, возможно, ваш браузер на вашем телефоне. Этот браузер ничего не знает о хосте my-backend? Это браузер подключается к контейнеру my-backend, а не процесс nginx в my-frontend.

John Somen
8 апреля 2018 в 18:44
0

Должно быть недоразумение. Я не спрашиваю об этом. Я спрашиваю, как динамически узнать IP-адрес демона докера, так как это также будет IP-адрес контейнера my-backend. Поэтому мне нужен IP-адрес my-backend для прохождения, а не для подключения изнутри my-frontend.

John Somen
8 апреля 2018 в 18:49
0

Я затрудняюсь объяснить это, кажется. Да, мне нужен IP-адрес my-backend в контейнере my-frontend. Нет, он мне не нужен для подключения с my-frontend к my-backend. Да, мне это нужно для передачи через браузер (конечный пользователь, клиент). Последнее я делаю через nginx и envsubst. Я ввожу IP-адрес my-backend во время обслуживания my-frontend.

John Somen
8 апреля 2018 в 18:51
1

Спасибо за редактирование! Термин public IP действительно имеет больше смысла. Я ценю ваши мысли.

John Somen
8 апреля 2018 в 18:54
0

Просто чтобы добавить, я считаю, что общедоступный IP-адрес my-backend равен IP-адресу демона докера. Вот почему я просил последнее, так как это также дало бы мне общедоступный IP-адрес my-backend.

Ответы (2)

avatar
halfer
8 апреля 2018 в 19:04
2

С Docker Compose все ваши контейнеры Docker будут отображаться на одном компьютере. Возможно, вы используете такие инструменты, как Swarm или Kubernetes, чтобы распределять свои контейнеры по разным хостам, что означает, что ваши внутренние и внешние контейнеры действительно будут доступны через разные общедоступные IP-адреса.

Обычным способом решения этой проблемы является использование внешнего прокси-сервера, такого как Traefik, на одной точке входа. Это означает, что с точки зрения браузера IP-адрес вашего интерфейса и сервера одинаков. Внутри прокси будет использовать правила фильтрации для направления трафика на правильное имя локальной сети. Обычный подход заключается в использовании префикса URL-адреса, например /backend/.

.

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

Любой из этих подходов позволит одному IP-адресу отображаться как "общие" порты - это решает проблему прослушивания одного и того же IP-адреса на 80/443 более чем в одном контейнере. Вам нужно стараться избегать нестандартных портов для внутренних вызовов, поскольку некоторые сети могут их блокировать (например, мобильные сети, корпоративные среды с брандмауэрами).

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

Обновление в зависимости от вашего варианта использования

Из вашего вопроса я изначально предположил, что вы ожидаете, что ваши контейнеры будут вращаться на произвольных хостах в ферме Docker. Фактически, ваш текущий подход, подтвержденный в комментариях, — это несколько неподключенных хостов Docker, поэтому всякий раз, когда вы развертываете, ваши контейнеры гарантированно используют общедоступный IP-адрес. Теперь я немного лучше понимаю цель вашего вопроса — вы хотели указать базовый URL-адрес для своего бэкэнда, включая полностью определенный домен, нестандартный порт и префикс пути URL-адреса.

Как я указал в обсуждении, в этом, вероятно, нет необходимости, поскольку вы можете поместить префикс URL-адреса прокси-сервера (/backend) в интерфейсе NginX. Это устраняет необходимость в нестандартном порте.

Если вы хотите указать собственный префикс серверной части (например, /backend/v1 для версии вашего API), вы можете сделать это в переменных env в конфигурации Docker Compose.

Если вам нужно обратиться к полному адресу бэкенда в вашем JavaScript для подключения к серверам AJAX/WebSocket, вы можете просто получить его из window.location.host. В вашей среде разработки это будет голый IP-адрес, а в вашей удаленной среде это звучит так, как будто у вас есть домен.

Дополнение

Некоторая путаница в этом вопросе была связана с тем, какие IP-адреса мы имеем в виду. Например:

Я считаю, что общедоступный IP-адрес my-backend равен IP-адресу демона Docker

Ваш хост Docker имеет несколько IP-адресов, и публичный адрес — лишь один из них. Например, виртуальный сетевой интерфейс docker0 — это IP-адрес вашего узла Docker в локальной сети, и если вы запросите IP-адрес своего узла Docker, это действительно будет правильный ответ (хотя, конечно, он недоступен в общедоступном Интернете). ).

На самом деле, я бы сказал, что адрес локальной сети принадлежит демону (поскольку его устанавливает Docker), а общедоступный IP-адрес — нет (это особенность коробки, а не Docker).

На любом из ваших хостов Docker введите следующую команду:

ifconfig docker0

Это даст вам некоторую информацию об IP-адресе вашего хоста и будет полезно, если контейнер Docker хочет связаться с хостом (например, если вы хотите подключиться к службе, которая не работает в контейнере). Весьма полезно передать здесь IP-адрес в контейнер как env var, чтобы разрешить это соединение.

halfer
8 апреля 2018 в 22:08
1

(Я удалил свои предыдущие комментарии и резюмировал обсуждение в виде обновления ответа, так что это может быть полезно для будущих читателей. Дайте мне знать, если я что-то упустил).

John Somen
9 апреля 2018 в 07:04
1

Я также удалил свои комментарии, так как ваше резюме охватывает их. Большое спасибо за ваше руководство!

avatar
jonhid
8 апреля 2018 в 10:09
0
my-backend:
  image: my-backend:latest
  ports:
    - 81:80
my-frontend:
  image: my-frontend:latest
  ports:
    - 80:80
  environment:
    - BACKEND="${BACKEND_ENV}"

Где находится BACKEND_ENV, а для переменной среды задан IP-адрес демона Docker.

На машине, где выполняется docker-compose, установите переменную среды раньше.

экспорт BACKEND_ENV="http://remoteip..."

Или просто запустите интерфейс, указывающий на удаленный адрес

docker run -p 80:80 -e BACKEND='http://remote_backend_ip:81' my-frontend:latest
jonhid
8 апреля 2018 в 10:49
0

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

jonhid
8 апреля 2018 в 10:51
0

Отредактировал мой ответ

John Somen
8 апреля 2018 в 10:52
0

По сути, я хочу преобразовать ${BACKEND_ENV} в вашем примере в IP-адрес демона докера, в идеале динамически/автоматически. Я бы предпочел не устанавливать переменную среды вручную.

jonhid
8 апреля 2018 в 11:15
0

Вы также можете запустить внешний интерфейс, указывающий на удаленный внутренний IP-адрес без docker-compose.. но в любом случае вы должны сообщить внешнему интерфейсу внутренний IP-адрес.

John Somen
8 апреля 2018 в 11:22
0

Да, я понимаю. Но поскольку внутренний IP-адрес всегда будет таким же, как IP-адрес демона докера, я ищу более элегантный/динамичный способ.

Shobhit Chittora
8 апреля 2018 в 12:25
1

@JohnSomen Обычно у людей есть обратный прокси-сервер перед своими внутренними серверами, что позволяет абстрагироваться от их точных IP-адресов. Так что вам просто нужно знать домен вашего сервиса ( xyz.com ), как переменную ENV. Надеюсь это поможет!

John Somen
8 апреля 2018 в 15:12
0

@ShobhitChittora Имеет смысл ... Я подумаю. Спасибо за идею!