Глава 6. Построение кластеров и горизонтальное масштабирование при помощи LXC
Содержание
- Глава 6. Построение кластеров и горизонтальное масштабирование при помощи LXC
Исполнение приложений внутри контейнеров LXC предоставляется для некоторого удобного способа выделения и ограничения ресурсов, как мы уже видели в предыдущих главах. LXC также великолепен для создания кластеров приложений, например, некоторой фермы веб серверов, которая может масштабироваться горизонтально или вертикально.
Горизонтальное масштабирование является неким споособом добавления вычислительной мощности в некий кластер или какую- то группу ресурсов, которая выполняет общую задачу. Это обычно выполняется путём добавления большего числа серверов или виртуальных машин, или, в случае LXC, большего числа контейнеров для работы приложений. В противоположность ему вертикальное масштабирование выполняется путём добавления большего объёма оборудования или виртуальных ресурсов, таких как ЦПУ и оперативной памяти в физические серверы, ВМ или контейнеры.
В данной главе мы собирается собрать все полученные вами данные с тем, чтобы сделать следующее:
-
Создать некий протой кластер Apache, запустить на исполнение LXC на некоторой минимальной корневой файловой системе при помощи libvirt.
-
Реализовать некий веб кластер со множеством узлов Apache и HAProxy с применением Open vSwitch и некоторой сетки туннелей GRE
-
Продемонстрировать как добавлять больше контейнеров путйм повторного использования имеющейся файловой системы существующих экземпляров LXC.
LXC достаточно хорошо приспособлен для замены виртуальных машин в том смысле, что он может содержать некую завершённую корневую файловую систему для какого- то дистрибутива Linux, причём в этом случае единственным совместным с ОС хоста компонентом является его ядро. Приложения могут быть установлены в корневой файловой системе такого контейнера таким образом, что сам хост и все прочие контейнеры не могут совместно использовать их. Такая изоляция полезна если вы желаем исполнять различные версии одного и того же приложения и его зависимости, или различные дистрибутивы Linux все вместе.
С другой стороны libvirt LXC делает возможным исполнение некого отдельного процесса или какой- то группы процессов из двоичных файлов, которые являются совместным ресурсом ОС данного хоста для всех контейнеров. В этом случае все контейнеры совместно используют данную файловую систему хоста и только отделяют определённые каталоги. Это помогает в сценариях, в котрых данному приложению может не требоваться своя собственная выделенная файловая система если, например, данный дистрибутив в этом контейнере тот же самы, что и у самой ОС хоста. Масштабирование таких приложений является неким предметом гарантии того, что данная служба установлена на этом хосте и все необходимые файлы настроек присутсвуют в имеющейся минимальной корневой файловой системе данного контейнера. Затем мы можем некую копию данного файла настроек контейнера и имеющейся минимальной корневой файловой системы и запустить её без большого числа изменений.
В последующих двух разделах мы изучим оба сценария. Мы начнём с построения минимальной корневой файловой системы контейнеров Apache с libvirt и балансировки их нагрузки при помощи HAProxy, а затем перемещать для построения некоторого кластера Apache при помощи LXC, а также выделенные файловые системы и сетевую изоляцию посредством Open vSwitch с некоторой сеткой из туннелей GRE.
В данном разделе мы продемонстрируем как исполнять множество серверов Apache на одном и том же хосте с применением libvirt LXC и некоторой минимальной файловой корневой системы для кажодого контейнера. При этом все двоичные файлы и библиотеки Apache будут совместно испорльзоваться всеми контейнерами. Даже если такой подход будет не самым удобным для Apache, хотя и предоставляя более простые однопоточные процессы, он поможет нам продемонстрировать обсуждаемую концепцию наиболее практичным образом.
Для данного примера мы воспользуемся Ubuntu, хотя те же самые инструкции применимы и к CentOS, как мы это продемонстрировали в Главе 2, Установка и исполнение LXC в системах Linux. Ниже приводятся необходимые для данного примера шаги:
-
Давайте начнём с обновления имеющейся ОС и проверки того, что она работает с самой последней версией:
root@ubuntu:~# apt-get update && apt-get upgrade --yes && reboot root@lxc:~# lsb_release -a 2>/dev/null Distributor ID: Ubuntu Description: Ubuntu 16.04.1 LTS Release: 16.04 Codename: xenial root@ubuntu:~# root@ubuntu:~# uname -r 4.4.0-38-generic root@ubuntu:~#
-
Здесь показан самый последний пакет libvirt на Ubuntu Xenial на момент написания данной книги:
root@ubuntu:~# apt-cache policy libvirt-bin libvirt-bin: Installed: Candidate: 1.3.1-1ubuntu10.5 Version table: *** 1.3.1-1ubuntu10.5 500 500 http://rackspace.clouds.archive.ubuntu.com/ubuntu xenial-updates/main amd64 Packages 100 /var/lib/dpkg/status 1.3.1-1ubuntu10 500 500 http://rackspace.clouds.archive.ubuntu.com/ubuntu xenial/main amd64 Packages root@ubuntu:~#
-
Далее установим сами пакеты libvirt:
root@ubuntu:~# apt-get install libvirt-bin virtinst root@ubuntu:~# dpkg --list | grep libvirt ii libvirt-bin 1.3.1-1ubuntu10.5 amd64 programs for the libvirt library ii libvirt0:amd64 1.3.1-1ubuntu10.5 amd64 library for interfacing with different virtualization systems ii python-libvirt 1.3.1-1ubuntu1 amd64 libvirt Python bindings root@ubuntu:~#
-
Что удобно, libvirt создаёт для нас необходимый мост:
root@ubuntu:~# brctl show bridge name bridge id STP enabled interfaces virbr0 8000.5254003d3c43 yes virbr0-nic root@ubuntu:~#
- .
Мы будем применять сетевую среду
default
libvirt, давайте убедимся что она присутствует:root@ubuntu:~# export LIBVIRT_DEFAULT_URI=lxc:/// root@ubuntu:~# virsh net-list --all Name State Autostart Persistent ---------------------------------------------------------- default active yes yes root@ubuntu:~#
-
Чтобы проверить эту сетевую среду
default
и шлюз, которые будет использовать libvirt, выполните следующую команду:root@ubuntu:~# virsh net-dumpxml default <network> <name>default</name> <uuid>6585ac5b-3d81-4071-bb61-3aa22007834e</uuid> <forward mode='nat'> <nat> <port start='1024' end='65535'/> </nat> </forward> <bridge name='virbr0' stp='on' delay='0'/> <mac address='52:54:00:3d:3c:43'/> <ip address='192.168.122.1' netmask='255.255.255.0'> <dhcp> <range start='192.168.122.2' end='192.168.122.254'/> </dhcp> </ip> </network> root@ubuntu:~#
-
Инструментарий libvirt также запускает
dnsmasq
, который назначит все сетевые установки нуждающимся в них контейнерам LXC если мы настроим их на использование DHCP:root@ubuntu:~# ps axfww 5310 ? Ssl 0:00 /usr/sbin/libvirtd 5758 ? S 0:00 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/lib/libvirt/libvirt_leaseshelper 5759 ? S 0:00 \_ /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/lib/libvir/libvirt_leaseshelper
-
Мы будем применять назначаемые по умолчанию настройки
dnsmasq
, однако давайте обеспечим соответствие отведённого диапазона DHCP тому, о чём знаетlibvirt-net
из предыдущего вывода:root@ubuntu:~# cat /var/lib/libvirt/dnsmasq/default.conf | grep -vi "#" strict-order user=libvirt-dnsmasq pid-file=/var/run/libvirt/network/default.pid except-interface=lo bind-dynamic interface=virbr0 dhcp-range=192.168.122.2,192.168.122.254 dhcp-no-override dhcp-lease-max=253 dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts root@ubuntu:~#
Создание минимальной файловой системы корня для имеющихся контейнеров
Для данного примера мы теперь собираемся использовать предоставленные шаблоны или применить команду
debootstrap
для построения полностью завершённой файловой системы
нашего контейнера вместо того, чтобы создавать некую минимальную структуру каталога в хосте для необходимых
файлов настройки для Apache и имеющегося контейнера. Всё остальное будет в том же самом пространстве имён
mount, что и у ОС самого хоста, за исключением нескольких каталогов, которые мы собираемся привязать к
данному контейнеру.
Для создания необходимой минимальной корневой файловой системы для данного контейнера проследйте приведёнными ниже шагами:
-
Давайте начнём с создания всех каталогов; скопируем необходимые файлы и установим Apache на самом хосте:
root@ubuntu:~# cd /opt/ root@ubuntu:/opt# mkdir -p containers/http1/etc root@ubuntu:/opt# mkdir -p containers/http1/var/www/html root@ubuntu:/opt# apt-get install --yes apache2 ... root@ubuntu:/opt# cp -r /etc/apache2/ /opt/containers/http1/etc/ root@ubuntu:/opt# cp -r /etc/passwd /opt//containers/http1/etc/ root@ubuntu:/opt# cp -r /etc/shadow /opt//containers/http1/etc/ root@ubuntu:/opt# cp -r /etc/group /opt//containers/http1/etc/ root@ubuntu:/opt# cp -r /etc/mime.types /opt//containers/http1/etc/ root@ubuntu:/opt# cp -r /etc/init.d/ /opt//containers/http1/etc/ root@ubuntu:/opt# cp -r /etc/resolv.conf /opt/containers/http1/etc/ root@ubuntu:/opt# cp -r /etc/fstab /opt/containers/http1/etc/ root@ubuntu:/opt# cp -r /etc/apache2/ /opt/containers/http1/etc/ root@ubuntu:/opt# cp -r /etc/network/ /opt/containers/http1/etc/
-
Далее создадим для Apache страницу
index.html
и настроим этот веб сервер с его собственным уникальным файлом PID, который впоследствии позволит нам запустить множество процессов Apache:root@ubuntu:/opt# echo &qout;Apache in LXC http1&qout; > /opt/containers/http1/var/www/html/index.html root@ubuntu:/opt# cd containers/ root@ubuntu:/opt/containers# sed -i 's/\${APACHE_PID_FILE}/\/var\/run\/apache2\/apache2_http1.pid/g' http1/etc/apache2/apache2.conf
-
Настройте все сетевые файлы на применение DHCP с тем, чтобы мы могли усилить сервер
dnsmasq
, которыйlibvirtd
запустил ранее:root@ubuntu:/opt/containers# cat http1/etc/network/interfaces auto lo iface lo inet loopback auto eth0 iface eth0 inet dhcp root@ubuntu:/opt/containers#
Определение контейнера libvirt Apache
Чтобы построить контейнеры LXC при помощи libvirt, нам необходимо создать некий файл настроек, который содержит все атрибуты данных контейнеров. Применив имеющуюся структуру каталога, помещённую на своё место на предыдущих шагах, а также установленный на данном хосте Apache, мы можем определить такой файл настроек наших контейнеров. Мы уже видели некие аналогичные настройки, когда мы обсуждали libvirt в Главе 3, Операции командной строки с использованием инструментов Native и Libvirt. Чтобы просмотреть эти настройки выполните следующее:
root@ubuntu:/opt/containers# cat http1.xml
<domain type='lxc'>
<name>http1</name>
<memory>102400</memory>
<os>
<type>exe</type>
<init>/opt/containers/startup.sh</init>
</os>
<vcpu>1</vcpu>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/lib/libvirt/libvirt_lxc</emulator>
<filesystem type='mount'>
<source dir='/opt/containers/http1/etc/apache2/'/>
<target dir='/etc/apache2'/>
</filesystem>
<filesystem type='mount'>
<source dir='/opt/containers/http1/var/www/html/'/>
<target dir='/var/www/html'/>
</filesystem>
<filesystem type='mount'>
<source dir='/opt/containers/http1/etc/'/>
<target dir='/etc'/>
</filesystem>
<interface type='network'>
<source network='default'/>
</interface>
<console type='pty'/>
</devices>
</domain>
root@ubuntu:/opt/containers#
Что является новым в предыдущих настройках, так это то, что вместо описания
/sbin/init
в качестве init системы, мы настраиваем чтобы libvirt
применял персональный сценарий - startup.sh
. Этот сценарий может
быть чем угодно что мы пожелаем; в данном случае мы запустим построение сетевой среды в данном контейнере,
настройку его оболочки, исполнение dhclient
для получения
необходимых сетевых установок от dnsmasq
, а затем запуска
Apache и bash:
root@ubuntu:/opt/containers# cat startup.sh
#!/bin/bash
export
PATH=$PATH:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
export PS1=&qout;[\u@\h \W]\\$&qout;
echo &qout;Starting Networking&qout; >> /var/log/messages
/etc/init.d/networking start
/sbin/dhclient eth0
echo &qout;Starting httpd&qout; >> /var/log/messages
/etc/init.d/apache2 start
/bin/bash
root@ubuntu:/opt/containers#
Далее сделаем этот сценарий исполняемым:
root@ubuntu:/opt/containers# chmod u+x startup.sh
root@ubuntu:/opt/containers#
Корневой каталог нашего контейнера должен выглядеть следующим образом:
root@ubuntu:/opt/containers# ls -la http1
total 16
drwxr-xr-x 4 root root 4096 Oct 31 17:25 .
drwxr-xr-x 3 root root 4096 Oct 31 17:32 ..
drwxr-xr-x 4 root root 4096 Oct 31 17:27 etc
drwxr-xr-x 3 root root 4096 Oct 31 17:25 var
root@ubuntu:/opt/containers#
Имеются всего два каталога! Теперь мы готовы к определению самого контейнера:
root@ubuntu:/opt/containers# virsh define http1.xml
Domain http1 defined from http1.xml
root@ubuntu:/opt/containers#
Запуск контейнера libvirt Apache
Имея на своём месте все необходимые компоненты, давайте запустим данный контейнер и убедимся что он исполняется:
root@ubuntu:/opt/containers# virsh start http1
Domain http1 started
root@ubuntu:/opt/containers# virsh list --all
Id Name State
----------------------------------------------------
19032 http1 running
root@ubuntu:/opt/containers# ps axfww
...
10592 ? S 0:00 /usr/lib/libvirt/libvirt_lxc --name http1
--console 23 --security=apparmor --handshake 26 --veth vnet1
10594 ? S 0:00 \_ /bin/bash /opt/containers/startup.sh
10668 ? Ss 0:00 \_ /sbin/dhclient eth0
10694 ? Ss 0:00 \_ /usr/sbin/apache2 -k start
10698 ? Sl 0:00 | \_ /usr/sbin/apache2 -k start
10699 ? Sl 0:00 | \_ /usr/sbin/apache2 -k start
10697 ? S 0:00 \_ /bin/bash
root@ubuntu:/opt/containers#
При выводе списка всех процессов данного хоста отметьте как все контейнеры запускались из нашего
сценария libvirt_lxc
, который является предком процесса данного
сценария startup.sh
, который в конечном счёте запускает
Apache.
Подключитесь к контейнеру и убедитесь что он способен получить некий IP адрес и шлюз по умолчанию
от dnsmasq
:
root@ubuntu:/opt/containers# virsh console http1
[root@ubuntu /]#ip a s
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group
default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
state UP group default qlen 1000
link/ether 52:54:00:92:cf:12 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.122.216/24 brd 192.168.122.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe92:cf12/64 scope link
valid_lft forever preferred_lft forever
[root@ubuntu /]#ip r s
default via 192.168.122.1 dev eth0
192.168.122.0/24 dev eth0 proto kernel scope link src 192.168.122.10
[root@ubuntu /]# Ctrl + ]
Давайте подключимся к Apache из ОС хоста:
root@ubuntu:/opt/containers# curl 192.168.122.216
Apache in LXC http1
root@ubuntu:/opt/containers#
Замечание | |
---|---|
IP адрес |
Выполните следующие шаги для масштабирования Apache при помощи libvirt LXC и HAProxy:
-
При наличии одного исполняющегося контейнера Apache давайте быстро создадим некий второй, скопировав имеющуюся простую структуру каталога и настройки libvirt из этого контейнера
http1
:root@ubuntu:/opt/containers# cp -r http1 http2 root@ubuntu:/opt/containers# cp http1.xml http2.xml root@ubuntu:/opt/containers#
-
Всё что нам требуется изменить, это само имя данного контейнера, его PID файл для Apache, а также его индексный файл:
root@ubuntu:/opt/containers# sed -i 's/http1/http2/g'http2.xml root@ubuntu:/opt/containers# sed -i 's/http1/http2/g'http2/etc/apache2/apache2.conf root@ubuntu:/opt/containers# echo "Apache in LXC http2" > /opt/containers/http2/var/www/html/index.html
-
определите такой новый контейнер и проверьте его структуры каталога которая содержит необходимую корневую файловую систему и все файлы настроек для обоих контейнеров:
root@ubuntu:/opt/containers# virsh define http2.xml Domain http2 defined from http2.xml root@ubuntu:/opt/containers# ls -la total 28 drwxr-xr-x 4 root root 4096 Oct 31 19:57 . drwxr-xr-x 3 root root 4096 Oct 31 17:32 .. drwxr-xr-x 4 root root 4096 Oct 31 17:25 http1 -rw-r--r-- 1 root root 868 Oct 31 17:31 http1.xml drwxr-xr-x 4 root root 4096 Oct 31 19:56 http2 -rw-r--r-- 1 root root 868 Oct 31 19:57 http2.xml -rwxr--r-- 1 root root 418 Oct 31 19:44 startup.sh root@ubuntu:/opt/containers#
-
Давайте запустим полученный новый контейнер и убедимся что оба экземпляра работают:
root@ubuntu:/opt/containers# virsh start http2 Domain http2 started root@ubuntu:/opt/containers# virsh list --all Id Name State ---------------------------------------------------- 10592 http1 running 11726 http2 running
-
Для получения дополнительной информации обо всех контейнерах Apache выполните следующую команду:
root@ubuntu:~# virsh dominfo http1 Id: 15720 Name: http1 UUID: defd17d7-f220-4dca-9be9-bdf40b4d9164 OS Type: exe State: running CPU(s): 1 CPU time: 35.8s Max memory: 102400 KiB Used memory: 8312 KiB Persistent: yes Autostart: isable Managed save: no Security model: apparmor Security DOI: 0 Security label: libvirt-defd17d7-f220-4dca-9be9-bdf40b4d9164 (enforcing) root@ubuntu:~# virsh dominfo http2 Id: 16126 Name: http2 UUID: a62f9e9d-4de3-415d-8f2d-358a1c8bc0bd OS Type: exe State: running CPU(s): 1 CPU time: 36.5s Max memory: 102400 KiB Used memory: 8300 KiB Persistent: yes Autostart: disable Managed save: no Security model: apparmor Security DOI: 0 Security label: libvirt-a62f9e9d-4de3-415d-8f2d-358a1c8bc0bd (enforcing) root@ubuntu:~#
Замечание Вывод
dominfo
предоставляет полезную информацию об имеющейся у данного контейнера памяти и использовании ЦПУ, которую вы можете применять для мониторинга, выдачи сообщений и автоматического масштабирования, как мы это увидим в Главе 7, Мониторинг и резервное копирование в мире с контейнерами. Отметим, чтоOS Type
установлен вexe
, так как системой init контейнера является некий сценарий. -
Давайте протестируем возможность соединения с Apache в этом новом контейнере; замените имеющийся IP вашего экземпляра, если это необходимо:
root@ubuntu:/opt/containers# curl 192.168.122.242 Apache in LXC http2 root@ubuntu:/opt/containers#
-
Оба процесса Apache доступны из данного хоста благодаря имеющемуся у них общему мосту, к которому они подключены. Чтобы осуществить к нему доступ извне ОС данного хоста мы можем установить HAProxy на данном сервере, причём с адресами IP этих контейнеров в качестве лежащих в его основе серверов:
root@ubuntu:~# echo "nameserver 8.8.8.8" > /etc/resolv.conf root@ubuntu:~# apt-get install --yes haproxy root@ubuntu:~# cat /etc/haproxy/haproxy.cfg global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin stats timeout 30s user haproxy group haproxy daemon ca-base /etc/ssl/certs crt-base /etc/ssl/private ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS ssl-default-bind-options no-sslv3 defaults log global mode http option httplog option dontlognull timeout connect 5000 timeout client 50000 timeout server 50000 frontend http bind :80 reqadd X-Forwarded-Proto:\ http default_backend http_nodes backend http_nodes mode http balance roundrobin option httpclose option forwardfor option redispatch option httpchk GET / cookie JSESSIONID prefix server http1 192.168.122.216:80 check inter 5000 server http1 192.168.122.242:80 check inter 5000 root@ubuntu:~#
Указанные IP адреса определяют в строках данного сервера в его разделе
backend
имеющихся настроек HAProxy те, которые принадлежат нашим контейнерам LXC libvirt.В разделе
frontend
данных настроек мы сообщаем HAProxy выполнять ожидание (listen) на порту80
связываться со всеми интерфейсами. В соответствующем разделеbackend
мы определяем необходимые IP обоих контейнеров LXC. Вам может понадобиться замена обозначенных IP контейнеров на те, которыеdnsmasq
предоставляет в вашей системе. -
Перезапустите HAProxy, так как в Ubuntu он автоматически запускается сразу после установки пакета:
root@ubuntu:~# service haproxy restart root@ubuntu:~#
-
Затем убедитесь что HAProxy запущен и выполняет ожидание по порту
80
в данном хосте:root@ubuntu:~# pgrep -lfa haproxy 1957 /usr/sbin/haproxy-systemd-wrapper -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid 1958 /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds 1960 /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds root@ubuntu:~# root@ubuntu:~# netstat -antup | grep -i listen | grep -w 80 tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1960/haproxy tcp6 0 0 :::80 :::* LISTEN 9693/apache2 root@ubuntu:~#
-
Мы настроили HAProxy на использование карусельного метода (round robin) для выбора серверных узлов; давайте свяжемся с ними несколько раз и убедимся что мы соединились с Apache в каждом контейнере LXC.
root@ubuntu:~# curl localhost Apache in LXC http1 root@ubuntu:~# curl localhost Apache in LXC http2 root@ubuntu:~#
-
Наконец, мы можем остановить один из конейнеров и убедиться что HAProxy удалит его из карусели:
root@ubuntu:~# virsh destroy http2 Domain http2 destroyed root@ubuntu:~# virsh list --all Id Name State ---------------------------------------------------- 15720 http1 running - http2 shut off root@ubuntu:~# curl localhost Apache in LXC http1 root@ubuntu:~# curl localhost Apache in LXC http1 root@ubuntu:~#
Apache может быть не лучшим приложением для исполнения во множестве контейнеров в одном и том же хосте. Тем не менее, это помогло нам продемонстрировать как просто масштабировать приложения, исполняющиеся в минимальных контейнерах с применением LXC libvirt, полагаясь на HAProxy, или как построить некую среду со множеством арендаторов. Дополнительным преимуществом при совместном использовании двоичных кодов всеми контейнерами состоит в том, что их обновление не требует изменений для каждого экземпляра LXC, вместо этого вы выполняете изменения в ОС хоста, которые будут видны из всех контейнеров данного сервера. Предыдущая установка может выглядеть простой, однако она предоставляет некий мощный способ масштабирования служб в LXC контейнерах с малым весом, которые не требуют большого дискового пространства.
Исполнение множества контейнеров в одном и том же хосте с минимальной файловой системой для каждого великолепно подходит для ряда сценариев, однако давайте далее сосредоточимся на более сложном примере с развёртыванием множества серверов. Следующая схема отображает реализацию, которую мы собираемся построить в данном разделе:
Мы собираемся использовать три сервера - lxc-lb
,
lxc-node-01
и lxc-node-02
.
Хост lxc-lb
будет размещать некий контейнер исполняющий HAProxy, а
далее HAProxy на самом таком сервере. Серверы lxc-node-01
и
lxc-node-02
будут иметь контейнеры, исполняющие Apache. Все экземпляры
LXC будут взаимодействовать в некоторой выделенной частной сетевой среде через сетку туннелей GRE, подключённых
к OVS. Данная сетка GRE OVS создаст сетевую изоляцию между всеми контейнерами и самим хостом, а также потенциально
и прочими контейнерами и их сетевыми средами. Все контейнеры получат свои собственные сетевые настройки от
dnsmasq
, исполняемого в хосте
lxc-lb
.
Для данного развёртывания мы применяем три экземпляра EC2 из ASW, работающих под управлением самого последнего выпуска Ubuntu Xenial.
Настройка хоста балансировки нагрузки
Чтобы настроить необходимый хост балансировки нагрузки выполните следующие шаги:
-
Давайте запустим сам сервер
lxc-lb
. Проверим что версии LXC доступны и установим самую последнюю:root@lxc-lb:~# apt-get update && apt-get upgrade --yes && reboot root@lxc-lb:~# apt-cache policy lxc lxc: Installed: (none) Candidate: 2.0.5-0ubuntu1~ubuntu16.04.2 Version table: 2.0.5-0ubuntu1~ubuntu16.04.2 500 500 http://us-east-1.ec2.archive.ubuntu.com/ubuntu xenial-updates/main amd64 Packages 2.0.0-0ubuntu2 500 500 http://us-east-1.ec2.archive.ubuntu.com/ubuntu xenial/main amd64 Packages root@lxc-lb:~# root@lxc-lb:~# apt-get install --yes lxc ... root@lxc-lb:~# dpkg --list | grep lxc ii liblxc1 2.0.5-0ubuntu1~ubuntu16.04.2 amd64 Linux Containers userspace tools (library) ii lxc 2.0.5-0ubuntu1~ubuntu16.04.2 all Transitional package for lxc1 ii lxc-common 2.0.5-0ubuntu1~ubuntu16.04.2 amd64 Linux Containers userspace tools (common tools) ii lxc-templates 2.0.5-0ubuntu1~ubuntu16.04.2 amd64 Linux Containers userspace tools (templates) ii lxc1 2.0.5-0ubuntu1~ubuntu16.04.2 amd64 Linux Containers userspace tools ii lxcfs 2.0.4-0ubuntu1~ubuntu16.04.1 amd64 FUSE based filesystem for LXC ii python3-lxc 2.0.5-0ubuntu1~ubuntu16.04.2 amd64 Linux Containers userspace tools (Python 3.x bindings) root@lxc-lb:~# root@lxc-lb:~# lxc-create --version 2.0.5 root@lxc-lb:~#
-
После установки необходимых пакетов и шаблонов LXC мы завершаем также с имеющимся мостом Linux, причём мы не собирваемся его применять:
root@lxc-lb:~# brctl show bridge name bridge id STP enabled interfaces lxcbr0 8000.000000000000 no root@lxc-lb:~#
-
Далее установите OVS и создайте неций новый мост с именем
lxcovsbr0
:root@lxc-lb:~# apt-get install --yes openvswitch-switch ... root@lxc-lb:~# ovs-vsctl add-br lxcovsbr0 root@lxc-lb:~# ovs-vsctl show 482cf359-a59e-4482-8a71-02b0884d016d Bridge "lxcovsbr0" Port "lxcovsbr0" Interface "lxcovsbr0" type: internal ovs_version: "2.5.0" root@lxc-lb:~#
-
Сетевая среда LXC по умолчанию использует свою подсеть
10.0.3.0/24
; мы собираемся заменить её на192.168.0.0/24
. Это поможет нам в тех случаях, когда мы уже имеем некую существующую сетевую среду LXC и мы желаемя запустить некую новую, а также изолировать определённые наборы контейнеров и к тому же поможет нам проедмонстрировать данную концепцию:root@lxc-lb:~# cat /etc/default/lxc-net | grep -vi &qout;#&qout; USE_LXC_BRIDGE=&qout;true&qout; LXC_BRIDGE=&qout;lxcbr0&qout; LXC_ADDR=&qout;10.0.3.1&qout; LXC_NETMASK=&qout;255.255.255.0&qout; LXC_NETWORK=&qout;10.0.3.0/24&qout; LXC_DHCP_RANGE=&qout;10.0.3.2,10.0.3.254&qout; LXC_DHCP_MAX=&qout;253&qout; root@lxc-lb:~# cat /etc/lxc/default.conf lxc.network.type = veth lxc.network.link = lxcbr0 lxc.network.flags = up lxc.network.hwaddr = 00:16:3e:xx:xx:xx root@lxc-lb:~#
-
Заменим имя имеющегося моста Linux на соотвестующее имя только что созданного нами моста OVS и заменим эту сетевую среду:
root@lxc-lb:~# sed -i 's/lxcbr0/lxcovsbr0/g' /etc/default/lxc-net root@lxc-lb:~# sed -i 's/10.0.3/192.168.0/g' /etc/default/lxc-net root@lxc-lb:~# sed -i 's/lxcbr0/lxcovsbr0/g' /etc/lxc/default.conf
-
Служба
dnsmasq
настроена для сети10.0.3.0/24
, однако после любого перезапуска она должна ожидать определённую ранее нами новую подсеть. Давайте перезанрузим данный сервер чтобы убедиться что эти изменения вступили в силу:root@lxc-lb:~# pgrep -lfa dnsmasq 10654 dnsmasq -u lxc-dnsmasq --strict-order --bind-interfaces --pid-file=/run/lxc/dnsmasq.pid --listen-address 10.0.3.1 --dhcp-range 10.0.3.2,10.0.3.254 --dhcp-lease-max=253 --dhcp-no-override --except-interface=lo --interface=lxcbr0 --dhcp-leasefile=/var/lib/misc/dnsmasq.lxcbr0.leases --dhcp-authoritative root@lxc-lb:~# root@lxc-lb:~# reboot
-
Как и ожидалось,
dnsmasq
теперь будет предлагать IP для подсети192.168.0.0/24
:root@lxc-lb:~# pgrep -lfa dnsmasq 1354 dnsmasq -u lxc-dnsmasq --strict-order --bind-interfaces --pid-file=/run/lxc/dnsmasq.pid --listen-address 192.168.0.1 --dhcp-range 192.168.0.2,192.168.0.254 --dhcp-lease-max=253 --dhcp-no-override --except-interface=lo --interface=lxcovsbr0 --dhcp-leasefile=/var/lib/misc/dnsmasq.lxcovsbr0.leases --dhcp-authoritative root@lxc-lb:~#
-
Проверим имеющийся мост OVS; он должен быть поднятым и настроенным на некий IP:
root@lxc-lb:~# ip a s lxcovsbr0 4: lxcovsbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1 link/ether ee:b0:a2:42:22:4e brd ff:ff:ff:ff:ff:ff inet 192.168.0.1/24 scope global lxcovsbr0 valid_lft forever preferred_lft forever inet6 fe80::ecb0:a2ff:fe42:224e/64 scope link valid_lft forever preferred_lft forever root@lxc-lb:~#
Создание контейнера балансировки нагрузки
Для создания требуемого контейнера балансировки нагрузки следуйте данным шагам:
-
Мы намереваемся применять имеющиеся шаблоны Ubuntu для создания необходимой корневой файловой системы требующегося нам контейнера HAProxy:
root@lxc-lb:~# lxc-create --name haproxy --template ubuntu root@lxc-lb:~# lxc-start --name haproxy root@lxc-lb:~#
-
Наш мост OVS теперь должен иметь все интерфейсы контейнеров добавленными в качестве порта - для данного примера
vethUY97FY
:root@lxc-lb:~# ovs-vsctl show 482cf359-a59e-4482-8a71-02b0884d016d Bridge &qout;lxcovsbr0&qout; Port &qout;lxcovsbr0&qout; Interface &qout;lxcovsbr0&qout; type: internal Port &qout;vethUY97FY&qout; Interface &qout;vethUY97FY&qout; ovs_version: &qout;2.5.0&qout; root@lxc-lb:~# root@lxc-lb:~# ip a s vethUY97FY 6: vethUY97FY@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master ovs-system state UP group default qlen 1000 link/ether fe:d1:f3:ca:9e:83 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet6 fe80::fcd1:f3ff:feca:9e83/64 scope link valid_lft forever preferred_lft forever root@lxc-lb:~#
-
Подключитесь к только что созданному новоме контейнеру и убедитесь что он получил некий IP адрес от работающего на том же самом хосте DHCP:
root@lxc-lb:~# lxc-attach --name haproxy root@haproxy:~# ifconfig eth0 Link encap:Ethernet HWaddr 00:16:3e:76:92:0a inet addr:192.168.0.26 Bcast:192.168.0.255 Mask:255.255.255.0 inet6 addr: fe80::216:3eff:fe76:920a/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:16 errors:0 dropped:0 overruns:0 frame:0 TX packets:12 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:1905 (1.9 KB) TX bytes:1716 (1.7 KB) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) root@haproxy:~# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.0.1 0.0.0.0 UG 0 0 0 eth0 192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 root@haproxy:~#
-
Данный контейнер должен иметь связь с имеющимся хостом и всемирным Интернентом. Давайте проверим это прежде чем двинемся далее:
root@haproxy:~# ping -c 3 192.168.0.1 PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data. 64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=0.218 ms 64 bytes from 192.168.0.1: icmp_seq=2 ttl=64 time=0.045 ms 64 bytes from 192.168.0.1: icmp_seq=3 ttl=64 time=0.046 ms --- 192.168.0.1 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2000ms rtt min/avg/max/mdev = 0.045/0.103/0.218/0.081 ms root@haproxy:~# ping google.com -c 3 PING google.com (216.58.217.110) 56(84) bytes of data. 64 bytes from iad23s42-in-f14.1e100.net (216.58.217.110): icmp_seq=1 ttl=48 time=2.55 ms 64 bytes from iad23s42-in-f14.1e100.net (216.58.217.110): icmp_seq=2 ttl=48 time=2.11 ms 64 bytes from iad23s42-in-f14.1e100.net (216.58.217.110): icmp_seq=3 ttl=48 time=2.39 ms --- google.com ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2002ms rtt min/avg/max/mdev = 2.113/2.354/2.555/0.191 ms root@haproxy:~# exit exit root@lxc-lb:~#
Если связь не работает, проверьте что ваш сервер dnsmasq
назначает
IP адреса как положено и что данный контейнер подключен к своему мосту OVS, а также что имеющийся интерфейс
моста поднять с неким IP адресом у него самого.
Построение туннеля GRE
GRE (Generic Routing Encapsulation, Общая инкапсуляция маршрутов) является протоколом туннелирования, который делает возможным построение сетей точка-точка поверх IP (Internet Protocol). Мы можем применить его для построения некоторой сетки между имеющимися коммутаторами OVS на своих трёх хостах, таким образом соединив все контейнеры LXC в некую изолированную сетевую среду. Каждый сервер (или экземпляр EC2 в нашем примере) будет соединён друг с другом. Имеющиеся OVS предоставляют некий удобный метод для установления таких туннелей GRE.
Всё ещё находясь на своём хосте балансировки нагрузки, создайте два туннеля GRE к другим двум серверам, в случае необходимости заменив указанные IP:
root@lxc-lb:~# ovs-vsctl add-port lxcovsbr0 gre0 -- set interface gre0 type=gre options:remote_ip=10.1.34.124
root@lxc-lb:~# ovs-vsctl add-port lxcovsbr0 gre1 -- set interface gre1 type=gre options:remote_ip=10.1.34.57
root@lxc-lb:~#
Замечание | |
---|---|
Отметим, что предыдущие адреса являются адресами реалных серверов, в не рассматриваемых контейнеров. |
Прослушивание всех портов в имеющемся мосту теперь отобразит также и все порты GRE:
root@lxc-lb:~# ovs-vsctl show
482cf359-a59e-4482-8a71-02b0884d016d
Bridge &qout;lxcovsbr0&qout;
Port &qout;gre1&qout;
Interface &qout;gre1&qout;
type: gre
options: {remote_ip=&qout;10.1.34.57&qout;}
Port &qout;vethRIC2BJ&qout;
Interface &qout;vethRIC2BJ&qout;
Port &qout;lxcovsbr0&qout;
Interface &qout;lxcovsbr0&qout;
type: internal
Port &qout;gre0&qout;
Interface &qout;gre0&qout;
type: gre
options: {remote_ip=&qout;10.1.34.124&qout;}
ovs_version: &qout;2.5.0&qout;
root@lxc-lb:~#
Так как мы создали некую сетку между OVS, могут возникнуть некие зацикливания пакетов. Для предотвращения топологических циклов нам необходимо включить в OVS STP (Spanning Tree Protocol, Протокол остовного дерева). STP является протоколом второго уровня, который предотвращает сетевые циклы при создании избыточных и взаимосвязанных соединений между коммутаторами. Чтобы включить его в имеющемся коммутаторе OVS выполните следующую команду:
root@lxc-lb:~# ovs-vsctl set bridge lxcovsbr0 stp_enable=true
root@lxc-lb:~#
Когда будут выполнениы все предыдущие этапы, теперь наш первый хост настроен. В следующем разделе мы собираемся настроить остальные свои серверы аналогичным образом.
Настройка узлов Apache
Для настройки своих узлов Apache выполните эти шаги:
-
На первом узле Apache установите LXC и OVS и создаёте требующийся мост:
root@lxc-node-01:~# apt-get update && apt-get --yes upgrade && reboot root@lxc-node-01:~# apt-get install --yes lxc root@lxc-node-01:~# apt-get install --yes openvswitch-switch root@lxc-node-01:~# ovs-vsctl add-br lxcovsbr0 root@lxc-node-01:~# ifconfig lxcovsbr0 up
-
Поменяйте имеющееся имя этого моста и измените его подсеть:
root@lxc-node-01:~# sed -i 's/lxcbr0/lxcovsbr0/g' /etc/lxc/default.conf root@lxc-node-01:~# sed -i 's/lxcbr0/lxcovsbr0/g' /etc/default/lxc-net root@lxc-node-01:~# sed -i 's/10.0.3/192.168.0/g' /etc/default/lxc-net
-
Создайте необходимые туннели GRE к остальным двум серверам, заменив при необходимости их IP:
root@lxc-node-01:~# ovs-vsctl add-port lxcovsbr0 gre0 -- set interface gre0 type=gre options:remote_ip=10.1.34.23 root@lxc-node-01:~# ovs-vsctl add-port lxcovsbr0 gre1 -- set interface gre1 type=gre options:remote_ip=10.1.34.57 root@lxc-node-01:~# ovs-vsctl show 625928b0-b57a-46b2-82fe-77d541473f29 Bridge &qout;lxcovsbr0&qout; Port &qout;gre0&qout; Interface &qout;gre0&qout; type: gre options: {remote_ip=&qout;10.1.34.23&qout;} Port &qout;gre1&qout; Interface &qout;gre1&qout; type: gre options: {remote_ip=&qout;10.1.34.57&qout;} Port &qout;lxcovsbr0&qout; Interface &qout;lxcovsbr0&qout; type: internal ovs_version: &qout;2.5.0&qout; root@lxc-node-01:~#
-
Включите на самом мосту STP:
root@lxc-node-01:~# ovs-vsctl set bridge lxcovsbr0 stp_enable=true root@lxc-node-01:~#
-
Code
New-VM -Name VM01 -Generation 2
-
Затем давайте создадим некий контейнер с именем
apache
:root@lxc-node-01:~# lxc-create --name apache --template ubuntu root@lxc-node-01:~# lxc-start --name apache
-
Самое время для создания окончательного узла аналогичным образом:
root@lxc-node-02:~# apt-get update && apt-get upgrade --yes && reboot root@lxc-node-02:~# apt-get install --yes lxc root@lxc-node-02:~# apt-get install --yes openvswitch-switch root@lxc-node-02:~# ovs-vsctl add-br lxcovsbr0 root@lxc-node-02:~# ifconfig lxcovsbr0 up root@lxc-node-02:~# sed -i 's/lxcbr0/lxcovsbr0/g' /etc/lxc/default.conf root@lxc-node-02:~# sed -i 's/lxcbr0/lxcovsbr0/g' /etc/default/lxc-net root@lxc-node-02:~# sed -i 's/10.0.3/192.168.0/g' /etc/default/lxc-net
-
Создадим туннели GRE:
root@lxc-node-02:~# ovs-vsctl add-port lxcovsbr0 gre0 -- set interface gre0 type=gre options:remote_ip=10.1.34.23 root@lxc-node-02:~# ovs-vsctl add-port lxcovsbr0 gre1 -- set interface gre1 type=gre options:remote_ip=10.1.34.124 root@lxc-node-02:~# ovs-vsctl show 7b8574ce-ed52-443e-bcf2-6b1ddbedde4c Bridge &qout;lxcovsbr0&qout; Port &qout;gre0&qout; Interface &qout;gre0&qout; type: gre options: {remote_ip=&qout;10.1.34.23&qout;} Port &qout;gre1&qout; Interface &qout;gre1&qout; type: gre options: {remote_ip=&qout;10.1.34.124&qout;} Port &qout;lxcovsbr0&qout; Interface &qout;lxcovsbr0&qout; type: internal ovs_version: &qout;2.5.0&qout; root@lxc-node-02:~#
-
Также включим на этом коммутаторе GRE:
root@lxc-node-02:~# ovs-vsctl set bridge lxcovsbr0 stp_enable=true root@lxc-node-02:~#
-
Наконец, создадим и запустим свой контейнер Apache:
root@lxc-node-02:~# lxc-create --name apache --template ubuntu root@lxc-node-02:~# lxc-start --name apache
Установка Apache и HAProxy с тестированием связи
Имея настроенными все серверы, запущенными все контейнеры и установленными все туннели GRE давайте
проверим имеющиеся связи между всеми экземплярами LXC. Так как все контейнеры являются частью одной и той
же сетевой среды, причём соединёнными друг с другом посредством коммутаторов OVS при помощи туннелей GRE,
они должны иметь возможность для взаимодейсвия друг с другом. Что ещё более важно, все контейнеры Apache
будут получать свои сетевые настройки через DHCP от исполняемой на нашем сервере
lxc-lb
службы dnsmasq
.
Чтобы проверить, что все контейнеры сданы внаём, мы можем проверить имеющийся файл владения
dnsmasq
выполнив следующую команду:
root@lxc-lb:~# cat /var/lib/misc/dnsmasq.lxcovsbr0.leases
1478111141 00:16:3e:84:cc:f3 192.168.0.41 apache *
1478111044 00:16:3e:74:b3:8c 192.168.0.165 * *
1478110360 00:16:3e:76:92:0a 192.168.0.26 haproxy *
root@lxc-lb:~#
-
Выдача в аренду может занять несколько секунд, вам может понадобиться проверить этот файл нескоько раз прежде чем какие- то IP запушутся. Когда все контейнеры получат IP, нам следует иметь возможность просмотреть их при перечислении всех контейнеров во всех серверах:
root@lxc-lb:~# lxc-ls -f NAME STATE AUTOSTART GROUPS IPV4 IPV6 haproxy RUNNING 0 - 192.168.0.26 - root@lxc-lb:~# root@lxc-node-01:~# lxc-ls -f NAME STATE AUTOSTART GROUPS IPV4 IPV6 apache RUNNING 0 - 192.168.0.165 - root@lxc-node-01:~# root@lxc-node-02:~# lxc-ls -f NAME STATE AUTOSTART GROUPS IPV4 IPV6 apache RUNNING 0 - 192.168.0.41 - root@lxc-node-02:~#
-
Далее давайте установим HAProxy в имеющемся контейнере
haproxy
в узле сервераlxc-lb
и проверим связи между контейнерами:root@lxc-lb:~# lxc-attach --name haproxy root@haproxy:~# ping -c3 192.168.0.165 PING 192.168.0.165 (192.168.0.165) 56(84) bytes of data. 64 bytes from 192.168.0.165: icmp_seq=1 ttl=64 time=0.840 ms 64 bytes from 192.168.0.165: icmp_seq=2 ttl=64 time=0.524 ms 64 bytes from 192.168.0.165: icmp_seq=3 ttl=64 time=0.446 ms --- 192.168.0.165 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 1999ms rtt min/avg/max/mdev = 0.446/0.603/0.840/0.171 ms root@haproxy:~# ping -c3 192.168.0.41 PING 192.168.0.41 (192.168.0.41) 56(84) bytes of data. 64 bytes from 192.168.0.41: icmp_seq=1 ttl=64 time=1.26 ms 64 bytes from 192.168.0.41: icmp_seq=2 ttl=64 time=0.939 ms 64 bytes from 192.168.0.41: icmp_seq=3 ttl=64 time=1.05 ms --- 192.168.0.41 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2001ms rtt min/avg/max/mdev = 0.939/1.086/1.269/0.142 ms root@haproxy:~# root@haproxy:~# apt-get update && apt-get install haproxy ...
Замечание Если вы строите данный пример развёртывания в некотором облаке поставщика и подвис
apt-get update
, попытайтесь уменьшить установку MTU своего интерфейсаeth0
внутри всех контейнеров LXC следующим образом:ifconfig eth0 mtu 1400
. -
Давайте просмотрим имеющийся файл настроек
haproxy.cfg
:root@haproxy:~# cat /etc/haproxy/haproxy.cfg global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin stats timeout 30s user haproxy group haproxy daemon ca-base /etc/ssl/certs crt-base /etc/ssl/private ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+ AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES: RSA+3DES:!aNULL:!MD5:!DSS ssl-default-bind-options no-sslv3 defaults log global mode http option httplog option dontlognull timeout connect 5000 timeout client 50000 timeout server 50000 frontend http bind :80 reqadd X-Forwarded-Proto:\ http default_backend http_nodes backend http_nodes mode http balance roundrobin option httpclose option forwardfor option redispatch option httpchk GET / cookie JSESSIONID prefix server http1 192.168.0.165:80 check inter 5000 server http1 192.168.0.41:80 check inter 5000 root@haproxy:~#
Все настройки HAProxy почти идентичны тем, которые мы применяли ранее в данной главе.
Замечание Отметим, что все IP адреса в соответствующих разделах
backend
в файле настроек данного HAProxy те же самые, что и у соответствующих контейнеров, исполняющихся в наших серверахlxcnode-01/02
. -
Перезапустите HAProxy и убедитесь что он работает:
root@haproxy:~# service haproxy restart root@haproxy:~# ps axfww PID TTY STAT TIME COMMAND 1 ? Ss 0:00 /sbin/init 38 ? Ss 0:00 /lib/systemd/systemd-journald 59 ? Ss 0:00 /usr/sbin/cron -f 62 ? Ssl 0:00 /usr/sbin/rsyslogd -n 143 ? Ss 0:00 /sbin/dhclient -1 -v -pf /run/dhclient.eth0.pid -lf /var/lib/dhcp/dhclient.eth0.leases -I -df /var/lib/dhcp/dhclient6.eth0.leases eth0 167 ? Ss 0:00 /usr/sbin/sshd -D 168 pts/2 Ss+ 0:00 /sbin/agetty --noclear --keep-baud pts/2 115200 38400 9600 vt220 169 lxc/console Ss+ 0:00 /sbin/agetty --noclear --keep-baud console 115200 38400 9600 vt220 412 ? Ss 0:00 /usr/sbin/haproxy-systemd-wrapper -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid 413 ? S 0:00 \_ /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds 414 ? Ss 0:00 \_ /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds root@haproxy:~#
Отметите внимание, что в предыдыдущем выводе, в отличии от приведённого ранее в данной главе примера с libvirt LXC, тепрерь основным родительским процессом у контейнера является сам процесс init.
-
Установите в двух других контейнерах Apache и создайте для каждого по некоторой странице
index.html
:root@lxc-node-01:~# lxc-attach --name apache root@apache:~# apt-get install --yes apache2 root@apache:~# echo &qout;Apache on LXC container on host lxc-node-01&qout; > /var/www/html/index.html root@lxc-node-02:~# lxc-attach --name apache root@apache:~# apt-get install --yes apache2 root@apache:~# echo &qout;Apache on LXC container on host lxc-node-02&qout; > /var/www/html/index.html
-
Внутри самого контейнера
haproxy
подключитесь к порту80
, по которому проводит прослушивание HAProxy и имеющийся балансировщик нагрузки должет перенаправлять все запросы на наши контейнеры Apache:root@haproxy:~# apt-get install --yes curl root@haproxy:~# curl localhost Apache on LXC container on host lxc-node-01 root@haproxy:~# curl localhost Apache on LXC container on host lxc-node-02 root@haproxy:~# exit exit root@lxc-lb:~#
-
Мы также должны иметь возможность соединиться с HAProxy из самого хоста
lxc-lb
, так как ОС этого хоста может общаться со всеми имеющимися контейнерами через свой коммутатор OVS:root@lxc-lb:~# apt-get install curl root@lxc-lb:~# curl 192.168.0.26 Apache on LXC container on host lxc-node-01 root@lxc-lb:~# curl 192.168.0.26 Apache on LXC container on host lxc-node-02 root@lxc-lb:~#
Предыдущий адрес
192.168.0.26
является адресом IP самого контейнераhaproxy
; замените его на какой- то назначенныйdnsmasq
в вашей системе. -
Наконец мы можем установит HAProxy на самом сервере
lxc-lb
, что позволит нам соединяться со всеми серверами Apache из внешнего мира если, например, данный хостlxc-lb
имеет некий общедоступный IP адрес. В данном случае мы не должны совсем иметь исполняемым HAProxy в определённом контейнере, хотя мы и можем повторно воспользоваться теми же самыми настройками:root@lxc-lb:~# apt-get install haproxy ... root@lxc-lb:~#
Скопируйте все настройки из имеющегося контейнера (перечисленные ранее в данном разделе) и перезапустите сервер HAProxy:
root@lxc-lb:~# service haproxy restart root@lxc-lb:~# curl 10.1.34.23 Apache on LXC container on host lxc-node-01 root@lxc-lb:~# curl 10.1.34.23 Apache on LXC container on host lxc-node-02 root@lxc-lb:~#
Замечание | |
---|---|
Отметим, что IP адрес |
Со всем этим мы имеем некую простую установку, которую можно применять в промышленном исполнении для создания высокодоступных служб и их горизонтального масштабирования путём добавления большего числа серверов и контейнеров под неким балансировщиком нагрузки, таким как HAProxy или Nginx.
Масштабирование службы Apache
Подобные приведённым выше установки могут быть полность атоматизированы посредством создания моментальных снимков имеющихся файловых систем контейнеров и фалов настроек с уже установленными службами; затем применяйте такие копии для запуска новых контейнеров по запросу.
Чтобы продемонстрировать как вручную масштабировать Apache добавляя большее число контейнеров, пройдите следующие шаги:
-
Для начала остановите один из экземпляров Apache:
root@lxc-node-01:~# lxc-ls -f NAME STATE AUTOSTART GROUPS IPV4 IPV6 apache RUNNING 0 - - - root@lxc-node-01:~# lxc-stop --name apache
-
Затем скопируйте его корневую файловую систему и имеющийся файл настроек LXC:
root@lxc-node-01:~# cd /var/lib/lxc root@lxc-node-01:/var/lib/lxc# ls -alh total 12K drwx------ 3 root root 4.0K Nov 2 16:53 . drwxr-xr-x 43 root root 4.0K Nov 2 15:02 .. drwxrwx--- 3 root root 4.0K Nov 2 16:53 apache root@lxc-node-01:/var/lib/lxc# cp -rp apache/ apache_new root@lxc-node-01:/var/lib/lxc#
-
Измените соответствующее имя имя на имя нового контейнера и удалите все имеющиеся MAC адреса из данного файла настроек. LXC динамически назначит некие новые при запуске данного контейнера:
root@lxc-node-01:/var/lib/lxc# sed -i 's/apache/apache_new/g' apache_new/config root@lxc-node-01:/var/lib/lxc# sed -i '/lxc.network.hwaddr/d' apache_new/config root@lxc-node-01:/var/lib/lxc#
-
Теперь у нас имеются два контейнера на этом хосте:
root@lxc-node-01:/var/lib/lxc# lxc-ls -f NAME STATE AUTOSTART GROUPS IPV4 IPV6 apache STOPPED 0 - - - apache_new STOPPED 0 - - - root@lxc-node-01:/var/lib/lxc#
-
Давайте запустим их оба:
root@lxc-node-01:/var/lib/lxc# lxc-start --name apache root@lxc-node-01:/var/lib/lxc# lxc-start --name apache_new root@lxc-node-01:/var/lib/lxc# lxc-ls -f NAME STATE AUTOSTART GROUPS IPV4 IPV6 apache RUNNING 0 - - - apache_new RUNNING 0 - - - root@lxc-node-01:/var/lib/lxc#
-
Так как мы скопировали корневую фаловую систему целиком из своего первоначального контейнера, имеющаяся служба Apache уже установлена в этом новом экземпляре. Теперь запустите её и убедитесь что она исполняется:
root@lxc-node-01:/var/lib/lxc# lxc-attach --name apache_new root@apache:/# /etc/init.d/apache2 start [ ok ] Starting apache2 (via systemctl): apache2.service. root@apache:/# ps ax PID TTY STAT TIME COMMAND 1 ? Ss 0:00 /sbin/init 37 ? Ss 0:00 /lib/systemd/systemd-journald 50 ? Ss 0:00 /sbin/ifup -a --read-environment 60 ? Ss 0:00 /usr/sbin/cron -f 62 ? Ssl 0:00 /usr/sbin/rsyslogd -n 97 ? S 0:00 /bin/sh -c /sbin/dhclient -1 -v -pf /run/dhclient.eth0.pid -lf /var/lib/dhcp/dhclient.eth0.leases -I -df /var/lib/dhcp/dhclient6.eth0.leases eth0 ? 98 ? S 0:00 /sbin/dhclient -1 -v -pf /run/dhclient.eth0.pid -lf /var/lib/dhcp/dhclient.eth0.leases -I -df /var/lib/dhcp/dhclient6.eth0.leases eth0 125 pts/3 Ss 0:00 /bin/bash 168 ? Ss 0:00 /usr/sbin/apache2 -k start 171 ? Sl 0:00 /usr/sbin/apache2 -k start 172 ? Sl 0:00 /usr/sbin/apache2 -k start 246 pts/3 R+ 0:00 ps ax root@apache:/#
Аналогичный данному процесс может быть полностью автоматизирован при помощи такой службы как Jenkins и распространён по различным серверам для достижения некоторого уровня автоматического масштабирования. Мы изучим такую настройку далее более подробно в Главе 7, Мониторинг и резервное копирование в мире с контейнерами.
Применение LXC для масштабирования различных рабочих нагрузок требует служб посредников, таких как HAProxy или Nginx и исполнения всех реальных служб в контейнера. Сетевая связность и сегментация может достигаться с применением программно определяемых сетевых сред с использованием OVS и туннелей GRE.
В данной главе мы изучили как запускать Apache в простых контейнерах LXC на основе libvirt, которые не требуют всей корневой файловой системы, а вместо этого некий минимальный набор из каталогов с общими исполняемыми кодами и библиотеками из ОС самого хоста. Мы также создали какой- то кластер Apache на множестве серверов под неким балансировщиком нагрузки и продемонстрировали пример достаточно эффективного способа его масштабирования путём дупликации каких- то контейнеров LXC.
В следующей главе мы будем основываться на том, что вы изучали до сих пор и покажем как осуществлять мониторинг и резервное копирование LXC, а также создавать автоматически масштабируемую службу при помощи Jenkins и Sensu.