Присвоєння vhosts портам 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 (запуск / зупинка / reuild через Інтернет ), або ...? Які у мене є варіанти, які б зробили використання контейнерів Docker більш схожим на природну подію, а не на щось із сторонніми портами та жонглюванням контейнерами?


У мене також є це запитання - наскільки я можу зрозуміти, запуск кожного додатка в контейнері Docker, а потім виконання маршрутизації на хості за допомогою сервера nginx (можливо, у власному контейнері) - це спосіб це зробити. Мені цікаво, чи варто мені запускати сервер додатків автономно (тобто виставляти сервер php-fpm, puma тощо) або включати також (безглуздий?) Екземпляр nginx.
Росс

Погляньте на github.com/dotcloud/hipache , який є зворотним проксі, який можна налаштувати за допомогою redis.
ZeissS

Відповіді:


81

Ця відповідь може запізнитися, але вам потрібен автоматичний зворотний проксі-сервер. Для цього я використав два рішення:

  • jwilder / nginx-proxy
  • Траефік

З часом я віддаю перевагу використанню 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

-v /var/run/docker.sock:/tmp/docker.sockЦе небезпечне рішення? Контейнер, який цей проксі-сервер nginx має доступ до демона хоста докера? Чи може це бути можливою дірою в безпеці?
Mikl

можливо. Також зауважте, що відсутність спільного використання /var/run/docker.sockне є гарантією того, що хост докера не можна використовувати з контейнера. Безпека Docker - це тема сама по собі.
Томаслевей

Чи є відомі проблеми безпеки? Коли ви можете зв’язати хост докера з контейнера.
Мікл

Експлойт існував у минулому, і проблема тепер виправлена, але нові експлойти можуть бути знайдені в майбутньому. Docker - це не про додавання безпеки, це про простоту розгортання
Томаслевей

5
Ви також можете запустити nginx-proxy та docker-gen окремо, щоб сокет docker не був встановлений на контейнері nginx.
Джейсон Уайлдер

42

Ось два можливих відповіді: (1) порти установки безпосередньо з Докер і використовувати Nginx / Apache для проксі в ВХости, або (2) використання Докку для управління портами і ВХости для вас (який , як я навчився робити метод 1).

Спосіб 1а (безпосередньо призначити порти за допомогою докера)

Крок 1: Налаштуйте nginx.conf або Apache на хості з необхідними номерами портів. Цей веб-сервер, що працює на хості, буде виконувати проксі-сервер vhost. Щодо 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, як у способі 1а), тоді його можна кодувати через 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 ВХости є Докку . Найближчим варіантом може бути використання Flynn , але на даний момент Flynn тільки починає працювати і не зовсім готовий. Тому зараз ми йдемо з Dokku: дотримуючись інструкцій з встановлення Dokku, для одного домену увімкніть vhosts, створивши файл "VHOST":

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

Тепер, коли додаток передається через SSH до Dokku (див. Документи Dokku про те, як це зробити), Dokku перегляне файл VHOST, а для конкретного додатка, що натискається (скажімо, ви натиснули "container-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

За допомогою докера ви хочете, щоб внутрішні ips залишалися нормальними (наприклад, 80) і з'ясовували, як підключити випадкові порти.

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

Якщо ви шукаєте щось більш надійне, можливо, ви захочете поглянути на "виявлення послуг". (погляд на виявлення служби за допомогою docker: http://txt.fliglio.com/2013/12/service-discovery-with-docker-docker-links-and-beyond/ )

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.