Назначение хостов для портов Docker

83

У меня настроен DNS с подстановочными знаками, чтобы все веб-запросы к пользовательскому домену (* .foo) сопоставлялись с IP-адресом хоста Docker. Если у меня есть несколько контейнеров с экземплярами Apache (или Nginx), каждый контейнер сопоставляет порт Apache (80) с некоторым внешним входящим портом.

Что я хотел бы сделать, так это сделать запрос к container-1.foo, который уже сопоставлен с правильным IP-адресом (хоста Docker) через мой собственный DNS-сервер, но проксирует запрос порта 80 по умолчанию на правильный внешний Docker. порт, чтобы правильный экземпляр Apache из указанного контейнера мог отвечать на основе личного домена. Точно так же container-2.foo будет прокси-сервером для apache второго контейнера и так далее.

Есть ли для этого готовое решение, лучше всего запустить прокси Nginx на хосте Docker, или я должен написать прокси node.js с потенциалом для управления контейнерами Docker (запуск / остановка / восстановление через Интернет ), или же...? Какие у меня есть варианты, которые сделали бы использование контейнеров Docker более естественным явлением, а не чем-то с посторонними портами и манипуляциями с контейнерами?

начальник манежа
источник
У меня тоже есть этот вопрос - насколько я могу судить, запуск каждого приложения в контейнере Docker, а затем выполнение маршрутизации на хосте с использованием сервера nginx (возможно, в его собственном контейнере) - это способ сделать это. Мне интересно, должен ли я запускать автономный сервер приложений (т.е. выставлять сервер php-fpm, puma и т. Д.) Или также включать (бессмысленно?) Экземпляр nginx.
Росс
Взгляните на github.com/dotcloud/hipache , который представляет собой обратный прокси-сервер, настраиваемый с помощью redis.
ZeissS

Ответы:

81

Этот ответ может быть немного запоздалым, но вам нужен автоматический обратный прокси. Я использовал для этого два решения:

  • jwilder / nginx-прокси
  • Traefik

Со временем я предпочитаю использовать Traefik. В основном потому, что он хорошо документирован и поддерживается, а также имеет больше функций (балансировка нагрузки с разными стратегиями и приоритетами, проверки работоспособности, автоматические выключатели, автоматические сертификаты SSL с ACME / Let's Encrypt, ...).


Использование jwilder / nginx-proxy

При запуске образа Docker Джейсона Уайлдера nginx-proxy для контейнера Docker вы получаете сервер nginx, настроенный как обратный прокси-сервер для других ваших контейнеров без конфигурации для поддержки.

Просто запустите другие контейнеры с VIRTUAL_HOSTпеременной окружения, и nginx-proxy обнаружит их ip: port и обновит конфигурацию nginx за вас.

Допустим, ваш DNS настроен так, что *.test.localсопоставляется с IP-адресом вашего хоста Docker, а затем просто запустите следующие контейнеры, чтобы запустить быструю демонстрацию:

# start the reverse proxy
docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock jwilder/nginx-proxy

# start a first container for http://tutum.test.local
docker run -d -e "VIRTUAL_HOST=tutum.test.local" tutum/hello-world

# start a second container for http://deis.test.local
docker run -d -e "VIRTUAL_HOST=deis.test.local" deis/helloworld

Использование Traefik

При запуске контейнера Traefik вы получаете настроенный обратный прокси-сервер, который будет перенастраивать свои правила пересылки с учетом меток докеров, найденных на ваших контейнерах.

Допустим, ваш DNS настроен так, что *.test.localсопоставляется с IP-адресом вашего хоста Docker, а затем просто запустите следующие контейнеры, чтобы запустить быструю демонстрацию:

# start the reverse proxy
docker run --rm -it -p 80:80 -v /var/run/docker.sock:/var/run/docker.sock traefik:1.7 --docker

# start a first container for http://tutum.test.local
docker run -d -l "traefik.frontend.rule=Host:tutum.test.local" tutum/hello-world

# start a second container for http://deis.test.local
docker run -d -l "traefik.frontend.rule=Host:deis.test.local" deis/helloworld
Thomasleveil
источник
-v /var/run/docker.sock:/tmp/docker.sockЭто опасное решение? Контейнер этого прокси-сервера nginx имеет доступ к демону хоста докеров? Может ли это быть дыра в безопасности?
Mikl
возможно. Также обратите внимание, что отказ от совместного использования также /var/run/docker.sockне является гарантией того, что хост докера не может быть использован из контейнера. Безопасность Docker - это отдельная тема.
Thomasleveil
Есть ли известные проблемы безопасности? Когда вы можете добраться до хоста докера из контейнера.
Mikl
Эксплойт существовал в прошлом, и теперь проблема устранена, но в будущем могут быть обнаружены новые эксплойты. Docker не о добавлении безопасности, а о простоте развертывания
Thomasleveil
5
Вы также можете запускать nginx-proxy и docker-gen отдельно, чтобы сокет докера не монтировался в контейнере nginx.
Джейсон Уайлдер
42

Вот два возможных ответа: (1) настроить порты напрямую с помощью Docker и использовать Nginx / Apache для прокси-сервера vhosts или (2) использовать Dokku для управления портами и vhosts для вас (именно так я научился использовать метод 1).

Метод 1а (прямое назначение портов с помощью докера)

Шаг 1. Настройте nginx.conf или Apache на хосте с желаемыми назначениями номеров портов. Этот веб-сервер, работающий на хосте, будет выполнять проксирование виртуального хоста. Что касается Docker, то здесь нет ничего особенного - это обычный хостинг vhost. Далее, на шаге 2, следует особая часть, чтобы заставить Docker использовать правильный номер порта хоста.

Шаг 2. Принудительно назначьте номера портов в Docker с помощью «-p», чтобы установить сопоставление портов Docker, и «-e», чтобы установить пользовательские переменные среды в Docker, как показано ниже:

port=12345 # <-- the vhost port setting used in nginx/apache
IMAGE=myapps/container-1
id=$(docker run -d -p :$port -e PORT=$port $IMAGE)
# -p :$port will establish a mapping of 12345->12345 from outside docker to
# inside of docker.
# Then, the application must observe the PORT environment variable
# to launch itself on that port; This is set by -e PORT=$port.

# Additional goodies:
echo $id # <-- the running id of your container
echo $id > /app/files/CONTAINER # <-- remember Docker id for this instance
docker ps # <-- check that the app is running
docker logs $id # <-- look at the output of the running instance
docker kill $id # <-- to kill the app

Метод 1b Жестко запрограммированный порт приложения

... если ваше приложение использует жестко запрограммированный порт, например порт 5000 (т.е. не может быть настроен через переменную среды PORT, как в методе 1a), то его можно жестко запрограммировать через Docker следующим образом:

publicPort=12345
id=$(docker run -d -p $publicPort:5000 $IMAGE)
# -p $publicPort:5000 will map port 12345 outside of Docker to port 5000 inside
# of Docker. Therefore, nginx/apache must be configured to vhost proxy to 12345,
# and the application within Docker must be listening on 5000.

Метод 2 (пусть Докку выяснит порты)

На данный момент довольно неплохим вариантом для управления хостами Docker является Dokku . Возможным вариантом может стать использование Флинна , но на данный момент Флинн только начинает работать и еще не совсем готов. Поэтому пока мы переходим к Dokku: после выполнения инструкций по установке Dokku для одного домена включите vhosts, создав файл "VHOST":

echo yourdomain.com > /home/git/VHOST
# in your case: echo foo > /home/git/VHOST

Теперь, когда приложение отправляется через SSH в Dokku (см. Документацию Dokku, чтобы узнать, как это сделать), Dokku будет смотреть на файл VHOST и для конкретного отправленного приложения (скажем, вы нажали «контейнер-1»), он сгенерирует следующий файл:

/home/git/container-1/nginx.conf

И в нем будет следующее содержание:

upstream container-1 { server 127.0.0.1:49162; }
server {
  listen      80;
  server_name container-1.yourdomain.com;
  location    / {
    proxy_pass  http://container-1;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $remote_addr;
  }
}

Когда сервер перезагружается, Dokku гарантирует, что Docker запускает приложение с портом, сопоставленным с его первоначально развернутым портом (здесь 49162), вместо того, чтобы случайным образом назначать другой порт. Для достижения этого детерминированного назначения Dokku сохраняет изначально назначенный порт /home/git/container-1/PORTи при следующем запуске устанавливает для PORTсреды это значение, а также сопоставляет назначения портов Docker с этим портом как на стороне хоста, так и на стороне приложения. Это отличается от первого запуска, когда Dokku установит, PORT=5000а затем определит, какой случайный порт Dokku отображает на стороне VPS на 5000 на стороне приложения. Это нормально (и может даже измениться в будущем), но это работает!

Под капотом VHOST работает так: после выполнения git push приложения через SSH Dokku выполнит обработчики, которые находятся внутри /var/lib/dokku/plugins/nginx-vhosts. Эти хуки также находятся здесь в исходном коде Dokku и отвечают за запись nginx.confфайлов с правильными настройками vhost. Если у вас нет этого каталога /var/lib/dokku, попробуйте запустить dokku plugins-install.

Дэвид Бэрд
источник
3

С помощью docker вы хотите, чтобы внутренние IP-адреса оставались нормальными (например, 80), и выясните, как подключить случайные порты.

Один из способов справиться с ними - использовать обратный прокси, такой как hipache. Направьте на него свой DNS, а затем вы сможете перенастроить прокси по мере того, как ваши контейнеры поднимаются и опускаются. Взгляните на http://txt.fliglio.com/2013/09/protyping-web-stuff-with-docker/, чтобы узнать, как это может работать.

Если вы ищете что-то более надежное, вы можете взглянуть на «обнаружение служб». (посмотрите на обнаружение службы с помощью докера: http://txt.fliglio.com/2013/12/service-discovery-with-docker-docker-links-and-beyond/ )

Бен Шварц
источник