Как разместить несколько веб-сайтов с Nginx и HAProxy, используя LXD в Ubuntu 16.04

Вступление

Https://linuxcontainers.org/[Linux container] - это группа процессов, которая изолирована от остальной системы посредством использования функций безопасности ядра Linux, таких как пространства имен и группы управления. Это конструкция, похожая на виртуальную машину, но гораздо более легкая; у вас нет лишних затрат на запуск дополнительного ядра или моделирование аппаратного обеспечения. Это означает, что вы можете легко создать несколько контейнеров на одном сервере. Используя контейнеры Linux, вы можете запускать несколько экземпляров целых операционных систем, ограниченных, на одном сервере, или связывать свое приложение и его зависимости в контейнере, не затрагивая остальную часть системы.

Например, представьте, что у вас есть сервер, и вы настроили несколько служб, включая веб-сайты, для своих клиентов. В традиционной установке каждый веб-сайт будет виртуальным хостом одного и того же экземпляра веб-сервера Apache или Nginx. Но с контейнерами Linux каждый веб-сайт будет настроен в своем собственном контейнере со своим собственным веб-сервером.

Мы можем использовать LXD для создания и управления этими контейнерами. LXD предоставляет сервис гипервизора для управления всем жизненным циклом контейнеров.

В этом руководстве вы будете использовать LXD для установки двух веб-сайтов на основе Nginx на одном сервере, каждый из которых будет ограничен собственным контейнером. Затем вы установите HAProxy в третий контейнер, который будет действовать как обратный прокси. Затем вы направите трафик в контейнер HAProxy, чтобы оба веб-сайта были доступны из Интернета.

Предпосылки

Для завершения этого урока вам понадобится следующее:

  • Один сервер Ubuntu 16.04, сконфигурированный с помощью учебного руководства Initial Server Setup с Ubuntu 16.04, с sudo non -руткит и брандмауэр.

  • Два полностью определенных доменных имени (FQDN), каждая запись DNS * A * указывает на IP-адрес вашего сервера. Чтобы настроить это, следуйте учебному руководству How для установки имени хоста с помощью DigitalOcean.

  • При желании добавьте 20 ГБ или более блочного хранилища, следуя инструкциям Getting Started with DigitalOcean Block Storage. Вы можете использовать это для хранения всех данных, связанных с контейнерами.

Шаг 1 - Добавление вашего пользователя в группу + lxd +

Войдите на сервер, используя учетную запись пользователя без полномочий root. Мы будем использовать эту не пользовательскую учетную запись для выполнения всех задач управления контейнерами. Чтобы это работало, вы должны сначала добавить этого пользователя в группу + lxd +. Сделайте это с помощью следующей команды:

sudo usermod --append --groups lxd

Выйдите из сервера и войдите снова, чтобы ваш новый сеанс SSH был обновлен с новым членством в группе. После входа в систему вы можете приступить к настройке LXD.

Шаг 2 - Настройка LXD

LXD должен быть правильно настроен, прежде чем вы сможете его использовать. Наиболее важным решением для конфигурации является тип хранилища для хранения контейнеров. Рекомендованным внутренним хранилищем для LXD является файловая система ZFS, которая хранится либо в предварительно выделенном файле, либо с помощью Block Storage. Чтобы использовать поддержку ZFS в LXD, установите пакет + zfsutils-linux +:

sudo apt-get update
sudo apt-get install zfsutils-linux

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

Вариант 1 - Использование предварительно выделенного файла

Выполните следующие действия, чтобы настроить LXD для использования предварительно выделенного файла для хранения контейнеров. Сначала выполните следующую команду, чтобы запустить процесс инициализации LXD:

sudo lxd init

Вам будет предложено предоставить несколько частей информации, как показано в следующем выводе. Мы выберем все значения по умолчанию, включая рекомендуемый размер предварительно выделенного файла, который называется * loop device *:

OutputName of the storage backend to use (dir or zfs) [default=zfs]:
Create a new ZFS pool (yes/no) [default=yes]?
Name of the new ZFS pool [default=lxd]:
Would you like to use an existing block device (yes/no) [default=no]?
Size in GB of the new loop device (1GB minimum) [default=15]:
Would you like LXD to be available over the network (yes/no) [default=no]?
Do you want to configure the LXD bridge (yes/no) [default=yes]?
Warning: Stopping lxd.service, but it can still be activated by:
 lxd.socket
LXD has been successfully configured.

Предлагаемый размер автоматически рассчитывается на основе доступного дискового пространства вашего сервера.

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

Вариант 2 - Использование блочного хранилища

Если вы собираетесь использовать блочное хранилище, вам нужно найти устройство, которое указывает на том блочного хранилища, которое вы создали, чтобы указать его в конфигурации LXD. Перейдите на вкладку * Volumes * на https://cloud.digitalocean.com [Панель управления DigitalOcean] l, найдите свой том, нажмите на всплывающее окно * More *, а затем нажмите * Инструкции по настройке *.

Найдите устройство, посмотрев на команду для форматирования тома. В частности, ищите путь, указанный в команде + sudo mkfs.ext4 -F +. На следующем рисунке показан пример тома. Вам нужна только та часть, которая подчеркнута:

image: https: //assets.digitalocean.com/articles/lxd_containers_ubuntu_1604/6rDyC1l.png [В инструкциях по настройке показано устройство для созданного хранилища блоков.]

В этом случае имя тома + / dev / disk / by-id / scsi-0D0_Volume_volume-fra1-01 +, хотя ваше имя может отличаться.

После определения тома вернитесь к своему терминалу и введите следующую команду, чтобы начать процесс инициализации LXD.

sudo lxd init

Вам будет представлен ряд вопросов. Ответьте на вопросы, как показано в следующем выводе:

OutputName of the storage backend to use (dir or zfs) [default=zfs]:
Create a new ZFS pool (yes/no) [default=yes]?
Name of the new ZFS pool [default=lxd]:

Когда вам будет предложено использовать существующее блочное устройство, выберите + yes + и укажите путь к вашему устройству:

Output of the "lxd init" commandWould you like to use an existing block device (yes/no) [default=no]?
Path to the existing block device:

Затем используйте значение по умолчанию для оставшихся вопросов:

Output of the "lxd init" commandWould you like LXD to be available over the network (yes/no) [default=no]?
Do you want to configure the LXD bridge (yes/no) [default=yes]?
Warning: Stopping lxd.service, but it can still be activated by:
 lxd.socket
LXD has been successfully configured.

После завершения процесса вы настроите сеть.

Настройка сети

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

изображение: https: //assets.digitalocean.com/articles/lxd_containers_ubuntu_1604/u9D79uB.png [сетевая конфигурация LXD]

Используйте значение по умолчанию для каждого параметра, но когда вас спросят о сети IPv6, выберите * Нет *, так как мы не будем использовать его в этом руководстве.

После того, как вы завершили настройку сети, вы готовы создать свои контейнеры.

Шаг 3 - Создание контейнеров

Мы успешно настроили LXD. Мы указали расположение хранилища и настроили сеть по умолчанию для всех вновь создаваемых контейнеров. Мы готовы к созданию и управлению некоторыми контейнерами, что мы будем делать с помощью команды + lxc +.

Давайте попробуем нашу первую команду, которая перечисляет доступные установленные контейнеры:

lxc list

Вы увидите следующий вывод:

Output of the "lxd list" commandGenerating a client certificate. This may take a minute...
If this is your first time using LXD, you should also run: sudo lxd init
To start your first container, try: lxc launch ubuntu:16.04

+------+-------+------+------+------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+------+-------+------+------+------+-----------+

Поскольку это первый раз, когда команда + lxc + связывается с гипервизором LXD, выходные данные позволяют нам знать, что команда автоматически создала сертификат клиента для безопасного взаимодействия с LXD. Затем он показывает некоторую информацию о том, как запустить контейнер. Наконец, команда показывает пустой список контейнеров, что ожидается, так как мы еще не создали ни одного.

Давайте создадим три контейнера. Мы создадим по одному для каждого веб-сервера и третий контейнер для обратного прокси. Цель обратного прокси-сервера - перенаправлять входящие соединения из Интернета на нужный веб-сервер в контейнере.

Мы будем использовать команду + lxc launch + для создания и запуска контейнера Ubuntu 16.04 (+ ubuntu: x +) с именем + web1 +. + X + в + ubuntu: x + является сокращением для первой буквы Xenial, кодовое имя Ubuntu 16.04. + ubuntu: + - это идентификатор предварительно сконфигурированного хранилища образов LXD.

Выполните следующие команды для создания контейнеров:

lxc launch ubuntu:x web1
lxc launch ubuntu:x web2
lxc launch ubuntu:x haproxy

Поскольку мы впервые создаем контейнер, первая команда загружает образ контейнера из Интернета и кэширует его локально. Следующие два контейнера будут созданы значительно быстрее.

Здесь вы можете увидеть пример вывода из создания контейнера + web1 +.

OutputCreating web1
Retrieving image: 100%
Starting web1

Теперь, когда мы создали три пустых контейнера vanilla, давайте использовать команду + lxc list +, чтобы показать информацию о них:

lxc list

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

Выход

+---------+---------+-----------------------+------+------------+-----------+
|  NAME   |  STATE  |         IPV4          | IPV6 |    TYPE    | SNAPSHOTS |
+---------+---------+-----------------------+------+------------+-----------+
| haproxy | RUNNING | 10.10.10.10 (eth0)    |      | PERSISTENT | 0         |
+---------+---------+-----------------------+------+------------+-----------+
| web1    | RUNNING | 10.10.10.100 (eth0)   |      | PERSISTENT | 0         |
+---------+---------+-----------------------+------+------------+-----------+
| web2    | RUNNING | 10.10.10.200 (eth0)   |      | PERSISTENT | 0         |
+---------+---------+-----------------------+------+------------+-----------+

Запомните имена контейнеров и соответствующие им адреса IPv4. Они понадобятся вам для настройки ваших услуг.

Шаг 4 - Настройка контейнеров Nginx

Давайте подключимся к контейнеру + web1 + и настроим первый веб-сервер.

Для подключения мы используем команду + lxc exec +, которая принимает имя контейнера и команды для выполнения. Выполните следующую команду для подключения к контейнеру:

lxc exec web1 -- sudo --login --user ubuntu

Строка + - + обозначает, что параметры команды для + lxc + должны останавливаться на этом, а остальная часть строки будет передана как команда, которая будет выполнена внутри контейнера. Команда + sudo --login --user ubuntu +, которая обеспечивает оболочку входа для предварительно сконфигурированной учетной записи + ubuntu + внутри контейнера.

Оказавшись внутри контейнера, наше приглашение оболочки теперь выглядит следующим образом.

Outputubuntu@web1:~$

Этот пользователь * ubuntu * в контейнере предварительно настроил доступ + sudo + и может запускать команды + sudo + без ввода пароля. Эта оболочка ограничена внутри контейнера. Все, что мы запускаем в этой оболочке, остается в контейнере и не может попасть на хост-сервер.

Давайте обновим список пакетов экземпляра Ubuntu внутри контейнера и установим Nginx:

sudo apt-get update
sudo apt-get install nginx

Давайте отредактируем веб-страницу по умолчанию для этого сайта и добавим текст, который проясняет, что этот сайт размещен в контейнере + web1 +. Откройте файл + / var / www / html / index.nginx-debian.html:

sudo nano /var/www/html/index.nginx-debian.html

Сделайте следующее изменение в файле:

Отредактированный файл /var/www/html/index.nginx-debian.html

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx !</title>
<style>
   body {
       width: 35em;
       margin: 0 auto;
       font-family: Tahoma, Verdana, Arial, sans-serif;
   }
</style>
</head>
<body>
<h1>Welcome to nginx !</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
...

Мы отредактировали файл в двух местах и ​​специально добавили текст + в контейнер LXD web1 +. Сохраните файл и выйдите из редактора.

Теперь выйдите из контейнера и вернитесь обратно на хост-сервер:

logout

Повторите эту процедуру для контейнера + web2 +. Войдите в систему, установите Nginx, а затем отредактируйте файл + / var / www / html / index.nginx-debian.html +, чтобы упомянуть + web2 +. Затем выйдите из контейнера + web2 +.

Давайте используем + curl + для проверки работоспособности веб-серверов в контейнерах. Нам нужны IP-адреса веб-контейнеров, которые были показаны ранее.

curl http://10.10.10.100/

Выход должен быть:

Output of "curl http://10.10.10.100/" command<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx !</title>
<style>
   body {
       width: 35em;
       margin: 0 auto;
       font-family: Tahoma, Verdana, Arial, sans-serif;
   }
</style>
</head>
<body>
<h1>Welcome to nginx !</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
...

Также проверьте второй контейнер, используя команду + curl + и его IP-адрес, чтобы убедиться, что он также настроен правильно. С обоими настроенными контейнерами мы можем перейти к настройке HAProxy.

Шаг 5 - Настройка контейнера HAProxy

Мы настроим HAProxy как прокси перед этими контейнерами. Если вам нужно больше информации о том, как это работает, просмотрите учебник An Введение в HAProxy и балансировку нагрузки понятия. Мы будем направлять трафик в каждый контейнер на основе используемого нами доменного имени. Мы будем использовать домен + example.com + в следующем примере конфигурации, который представляет собой special зарезервированный домен для документации, подобной этому учебному пособию. Мы сделаем первый веб-сайт доступным с именами хостов + example.com + и + www.example.com +. Второй веб-сайт будет по адресу + www2.example.com +. Замените ваши собственные доменные имена вместо этих доменных имен.

Войдите в контейнер + haproxy +:

lxc exec haproxy -- sudo --login --user ubuntu

Обновите список инсталляционных пакетов и установите HAProxy:

sudo apt-get update
sudo apt-get install haproxy

После завершения установки мы можем настроить HAProxy. Файл конфигурации для HAProxy находится по адресу + / etc / haproxy / haproxy.cfg +. Откройте файл в вашем любимом текстовом редакторе.

sudo nano /etc/haproxy/haproxy.cfg

Во-первых, мы внесем пару изменений в раздел + defaults +. Мы добавим параметр «+ forwardfor », чтобы сохранить реальный исходный IP-адрес веб-клиента, и добавим параметр « http-server-close +», который позволяет повторно использовать сеанс и снижает задержку.

/etc/haproxy/haproxy.conf

global
...
defaults
   log global
   mode    http
   option  httplog
   option  dontlognull


   timeout connect 5000
   timeout client  50000
   timeout server  50000
...

Далее мы настроим внешний интерфейс так, чтобы он указывал на два наших внутренних контейнера. Добавьте новый раздел + frontend + с именем + www_frontend +, который выглядит следующим образом:

/etc/haproxy/haproxy.conf

        # Bind to port 80 (www) on the container

   # It matches if the HTTP Host: field mentions any of the hostnames (after the '-i').



   # Redirect the connection to the proper server cluster, depending on the match.

Команды + acl + соответствуют именам хостов веб-серверов и перенаправляют запросы в соответствующий раздел + backend +.

Затем мы определяем два новых раздела + backend +, по одному для каждого веб-сервера, и называем их + web1_cluster + и + web2_cluster + соответственно. Добавьте следующий код в файл, чтобы определить бэкэнды:

/etc/haproxy/haproxy.conf

   # We set the X-Client-IP HTTP header. This is useful if we want the web server to know the real client IP.

   # This backend, named here "web1", directs to container "web1.lxd" (hostname).

Опция + balance + обозначает стратегию распределения нагрузки. В этом случае мы выбираем наименьшее количество соединений. Опция + http-request + устанавливает заголовок HTTP с реальным IP-адресом веб-клиента. Если мы не установим этот заголовок, веб-сервер запишет IP-адрес HAProxy в качестве исходного IP-адреса для всех соединений, что затруднит анализ источника вашего трафика. Опция + server + указывает произвольное имя для сервера (+ web1 +), за которым следуют имя хоста и порт сервера.

LXD предоставляет DNS-сервер для контейнеров, поэтому + web1.lxd + разрешает IP-адрес, связанный с контейнером + web1 +. Другие контейнеры имеют свои собственные имена хостов, такие как + web2.lxd + и + haproxy.lxd +.

Параметр + check + указывает HAPRoxy выполнить проверку работоспособности на веб-сервере, чтобы убедиться, что он доступен.

Чтобы проверить правильность конфигурации, выполните следующую команду:

/usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -c

Выход должен быть

Выход

Configuration file is valid

Давайте перезагрузим HAProxy, чтобы он прочитал новую конфигурацию.

sudo systemctl reload haproxy

Теперь выйдите из контейнера, чтобы вернуться к хосту.

logout

Мы настроили HAProxy для работы в качестве обратного прокси-сервера, который перенаправляет все соединения, которые он получает через порт + 80 +, на соответствующий веб-сервер в двух других контейнерах. Давайте проверим, что + haproxy + действительно перенаправляет запросы в правильный веб-контейнер. Выполните эту команду:

curl --verbose --header 'Host: web2.example.com' http://10.10.10.10

Это делает запрос к HAProxy и устанавливает заголовок HTTP + host +, который HAProxy должен использовать для перенаправления соединения на соответствующий веб-сервер.

Выход должен быть

Output of "curl --verbose --header 'Host: web2.example.com' http://10.10.10.10" command...
> GET / HTTP/1.1
> Host:
> User-Agent: curl/7.47.0
> Accept: */*
>
...
<
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx !</title>
<style>
...

HAProxy правильно понял запрос и направил его в контейнер + web2 +. Там веб-сервер обслуживает страницу индекса по умолчанию, которую мы редактировали ранее, и показывает текст + на контейнере LXD web2 +. Теперь давайте направим внешние запросы в HAProxy, чтобы мир мог получить доступ к нашим веб-сайтам.

Шаг 6 - Пересылка входящих соединений в контейнер HAProxy

Последняя часть головоломки - подключение обратного прокси к Интернету. Нам нужно настроить наш сервер так, чтобы он перенаправлял все соединения, которые он может получать из Интернета через порт + 80 +, в контейнер + haproxy +.

HAProxy установлен в контейнере и по умолчанию недоступен из Интернета. Чтобы решить эту проблему, мы создадим правило «+ iptables +» для пересылки соединений.

Команде + iptables + требуется два IP-адреса: публичный IP-адрес сервера (`) и приватный IP-адрес контейнера `+ haproxy +` (`), который вы можете получить с помощью ` + lxc list + `команда.

Выполните эту команду, чтобы создать правило:

sudo iptables -t nat -I PREROUTING -i eth0 -p TCP -d /32 --dport 80 -j DNAT --to-destination :80

Вот как команда ломается:

  • + -t nat + указывает, что мы используем таблицу + nat +.

  • + -I PREROUTING + указывает, что мы добавляем правило в цепочку PREROUTING.

  • + -i eth0 + определяет интерфейс * eth0 *, который является общедоступным интерфейсом по умолчанию для Droplets.

  • + -p TCP + говорит, что мы используем протокол TCP.

  • + -d / 32 + указывает IP-адрес назначения для правила.

  • + - dport 80 +: указывает порт назначения.

  • + -j DNAT + говорит, что мы хотим выполнить переход к месту назначения NAT (DNAT).

  • + - to destination: 80 + говорит о том, что мы хотим, чтобы запрос перешел на IP-адрес контейнера с HAProxy.

Узнайте больше об IPTables в How Iptables Firewall Works и https://www.digitalocean.com/community/tutorials/ iptables-essentials-common-firewall-rules-and-команды [IPtables Essentials: Общие правила и команды брандмауэра].

Наконец, чтобы сохранить эту команду + iptables + и применить ее после перезагрузки, мы устанавливаем пакет + iptables-persistent +:

sudo apt-get install iptables-persistent

При установке пакета вам будет предложено сохранить текущие правила iptables. Примите и сохраните все текущие правила + iptables.

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

Чтобы проверить, что два веб-сервера действительно доступны из Интернета, подключитесь к каждому с вашего локального компьютера с помощью команды + curl +, например:

curl --verbose --header 'Host: example.com' 'http://'
curl --verbose --header 'Host: web2.example.com' 'http://'

Эти команды устанавливают HTTP-соединения с общедоступным IP-адресом сервера и добавляют поле заголовка HTTP с опцией + - header +, которую HAProxy будет использовать для обработки запроса, как вы это делали в шаге 5.

Вот вывод первой команды + curl +:

Output*   Trying ...
* Connected to  () port 80 (#0)
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
...
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx !</title>
<style>
   body {
...

Вот вывод второй команды + curl +:

Output*   Trying ...
* Connected to  () port 80 (#0)
> GET / HTTP/1.1
> Host: web2.example.com
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
...
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx !</title>
<style>
   body {
...

В обоих случаях отображается правильный веб-сайт.

Заключение

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

Вы также можете добавить MySQL в новый контейнер, а затем установить CMS, например WordPress, для запуска каждого веб-сайта. Вы также можете использовать этот процесс для поддержки более старых версий программного обеспечения. Например, если для установки CMS требуется более старая версия программного обеспечения, например PHP5, вы можете установить Ubuntu 14.04 в контейнере (+ lxc launch ubuntu: t +) вместо попытки понизить версии менеджера пакетов, доступные в Ubuntu. 16,04.

Наконец, LXD предоставляет возможность делать снимки полного состояния контейнеров, что упрощает создание резервных копий и откат контейнеров в более позднее время. Кроме того, если мы устанавливаем LXD на двух разных серверах, то можно подключить их и переносить контейнеры между серверами через Интернет.

Related