Docker, лекция 14. Контейтеры балансировки нагрузки
В этой лекции рассмотрим, как можно использовать веб-сервер NGINX для балансировки запросов между двумя контейнерами, запущенными на хосте.
В Docker есть два основных способа взаимодействия контейнеров друг с другом. Первый — через links, которые конфигурируют контейнер с переменными среды и изменением host файла, позволяя им общаться. Второй — использование шаблонов Service Discovery, в котором используется информация, предоставленная третьими сторонами, в этом случае это будет API докера.
В шаблоне Service Discovery приложение использует стороннюю систему для определения местоположения целевой службы. Например, если наше приложение хочет общаться с базой данных, оно сначала спросит API, каков IP-адрес базы данных. Этот шаблон позволяет вам быстро перенастроить и масштабировать вашу архитектуру с повышенной отказоустойчивостью, чем фиксированные пути.
Имя компьютера, на котором запущен Docker, называется Docker. Для доступа к службам используется имя docker вместо localhost или 0.0.0.0.
NGINX Proxy
Мы хотим запустить службу NGINX, которая может динамически обнаруживать и обновлять свою конфигурацию баланса нагрузки при загрузке новых контейнеров. К счастью, это уже существует и называется nginx-proxy.
Nginx-proxy принимает HTTP-запросы и передает их в соответствующий контейнер на основе имени хоста запроса. Это прозрачно для пользователя и происходит без каких-либо дополнительных расходов ресурсов.
При запуске прокси-контейнера необходимо настроить три параметра. Первый — это привязка контейнера к порту 80 на хосте с использованием -p 80:80. Это гарантирует, что все HTTP-запросы обрабатываются прокси.
Второе — смонтировать файл docker.sock. Это соединение с демоном Docker, работающим на хосте, которое позволяет контейнерам получать доступ к его метаданным через API. Nginx-прокси использует это для прослушивания событий, а затем обновляет конфигурацию NGINX на основе IP-адреса контейнера. Монтирование файла работает так же, как и для каталогов, используя -v /var/run/docker.sock:/tmp/docker.sock:ro. Мы указываем: ro, чтобы ограничить доступ только для чтения.
Наконец, мы можем установить необязательный -e DEFAULTHOST = <домен>. Если запрос приходит и не указывает на определенные хосты, то выбирается указанный контейнер, в котором запрос будет обработан. Это позволяет вам запускать несколько веб-сайтов с разными доменами на одном компьютере с помощью отката на известный веб-сайт.
Попробуем на примере:
docker run -d -p 80:80 -e DEFAULT_HOST=proxy.example -v /var/run/docker.sock:/tmp/docker.sock:ro --name nginx jwilder/nginx-proxy
Поскольку мы используем DEFAULT_HOST, любые поступающие запросы будут направлены в контейнер, которому назначен HOST proxy.example.
Вы можете сделать запрос к веб-серверу, используя curl http://docker. Поскольку у нас нет контейнеров, он вернет ошибку 503.
Один хост
Nginx-прокси теперь прослушивает события, которые Docker вызывает при запуске / остановке. Был создан пример веб-сайта katacoda/docker-http-server, который возвращает имя контейнера, на котором он работает. Это позволяет нам проверить, что наш прокси работает должным образом. Внутренне это приложение PHP и Apache2, прослушивающее порт 80.
Чтобы Nginx-прокси начал отправлять запросы в контейнер, нужно указать переменную среды VIRTUAL_HOST. Эта переменная определяет домен, откуда будут поступать запросы, и должен обрабатываться контейнером.
В этом примере установим наш HOST равным DEFAULT_HOST, чтобы он принимал все запросы.
docker run -d -p 80 -e VIRTUAL_HOST=proxy.example katacoda/docker-http-server
Если выполнить запрос к нашему прокси с помощью curl http://docker, тогда запрос будет обработан контейнером с сайтом.
Кластер
Теперь мы успешно создали контейнер для обработки наших HTTP-запросов. Если мы запустим второй контейнер с тем же VIRTUAL_HOST, то nginx-proxy настроит систему в циклическом сценарии с балансировкой нагрузки. Это означает, что первый запрос будет отправлен в один контейнер, второй запрос — во второй контейнер, а затем будет повторяться по кругу. Нет ограничений на количество работающих узлов.
docker run -d -p 80 -e VIRTUAL_HOST=proxy.example katacoda/docker-http-server
Если мы выполним запрос к нашему прокси с помощью curl http://docker, тогда запрос будет обработан нашим первым контейнером. Второй HTTP-запрос вернет другое имя компьютера, что означает, что он был обработан нашим вторым контейнером.
Итоговая конфигурация NGINX
Хотя nginx-proxy автоматически создает и настраивает NGINX для нас, если вам интересно, как выглядит окончательная конфигурация, вы можете вывести полный файл конфигурации с помощью docker exec, как показано ниже.
docker exec nginx cat /etc/nginx/conf.d/default.conf