Настройка отказоустойчивого веб сервера на базе nginx и apache.
Рассмотрим настройку отказоустойчивых веб серверов.
В данном примере мы будем использовать nginx для балансировки нагрузки, а связку nginx + apache будем использовать как веб сервера.
Теперь рассмотрим данную реализацию подробнее. Мы можем использовать две схемы отказоустойчивости, это схема 1:
В данной схеме точкой отказа является балансировщик, но если вы не располагаете большим количеством серверов, данная схема подойдет.
Если вас интересует полная отказоустойчивость, то вам подойдет вторая схема:
В данной схеме задублирован каждый узел.
В рамках этой статьи мы рассмотрим реализацию схемы №1, как реализовать схему 2 я расскажу в конце статьи.
Теперь рассмотрим подробнее схему 1.
Нам понадобится:
1) Настроить DNS записи типа A на адрес балансировщика Nginx
2) Настроить балансировку нагрузки на сервере nginx
3) Настроить веб сервера на связке Nginx + Apache, где Nginx отдает статический контент, а Apache динамический
4) Настроить репликацию Mysql (тип Master-Master)
5) Настроить распределенную файловую систему GlusterFS для хранения сайтов
Перейдем к пункту 2, настроим балансировщик на базе Nginx.
Обновляем все пакеты:
1 |
apt-get update |
1 |
apt-get upgrade |
Удалим кэш пакетов и ненужные пакеты:
1 |
apt-get clean |
1 |
apt-get autoclean |
1 |
apt-get autoremove |
Устанавливаем веб сервер Nginx.
1 |
apt-get install nginx |
Удаляем дефолтные конфиги.
1 |
rm -f /etc/nginx/sites-available/* |
1 |
rm -f /etc/nginx/sites-enabled/* |
Создаем конфиг для нового сайта.
1 |
touch /etc/nginx/sites-available/newsite |
Приводим данный конфиг к виду:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
upstream http { ip_hash; server 192.168.10.10:80 max_fails=2 fail_timeout=2s; server 192.168.10.20:80 max_fails=2 fail_timeout=2s; server 192.168.10.30:80 max_fails=2 fail_timeout=2s; } server { server_name newsite.test.com; listen 80; location / { proxy_read_timeout 1200; proxy_connect_timeout 1200; proxy_pass http://http/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } |
В данном конфиге:
В секции upstream http описываются метод балансировки и адреса веб серверов на которые распределяется нагрузка
Параметр max_fails указывает максимальное число неудачных соединений с сервером
Параметр fail_timeout указывает максимальное время ожидания при обрыве связи с сервером
В секции server описывается адрес сайта и порт на котором работает сайт
В секции location указываются параметры проксирования, параметр proxy_pass указывает какую директиву из конфига использовать.
Если вы настраиваете хост https , то конфиг будет выглядеть так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
upstream https { server 192.168.10.10:80 max_fails=2 fail_timeout=2s; server 192.168.10.20:80 max_fails=2 fail_timeout=2s; server 192.168.10.30:80 max_fails=2 fail_timeout=2s; } server { server_name newsite.test.com; listen 443; ssl on; ssl_certificate /etc/nginx/SSL/hostname.pem; ssl_certificate_key /etc/nginx/SSL/server.key; location / { proxy_read_timeout 1200; proxy_connect_timeout 1200; proxy_pass http://http/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header HTTPS on; } } |
(adsbygoogle = window.adsbygoogle || []).push({});
В таком случае ssl сессии будет поднимать балансировщик, а не конечный веб сервер.
Сохраняем конфиг и включаем сайт (в примере используется конфиг без ssl).
1 |
ln -s /etc/nginx/sites-available/newsite /etc/nginx/sites-enabled/newsite |
Перезапускаем Nginx.
1 |
service nginx restart |
На этом настройка балансировщика завершена.
Перейдем к настройке вебсервера номер 1.
Обновляем все пакеты:
1 |
apt-get update |
1 |
apt-get upgrade |
Удалим кэш пакетов и ненужные пакеты:
1 |
apt-get clean |
1 |
apt-get autoclean |
1 |
apt-get autoremove |
Установим часовой пояс.
1 |
dpkg-reconfigure tzdata |
Установим NTP.
1 |
apt-get install ntp |
Устанавливаем веб сервер Apache2.
1 |
apt-get install apache2 |
Устанавливаем PHP.
1 |
apt-get install php5 libapache2-mod-php5 php5-mysql |
Устанавливаем Mysql сервер.
1 |
apt-get install mysql-server mysql-client |
Настраиваем безопасность Mysql.
1 |
mysql_secure_installation |
Устанавливаем значения firewall.
1 |
ufw allow OpenSSH |
1 |
ufw allow Apache |
1 |
ufw allow 3306/tcp |
1 |
ufw limit OpenSSH |
1 |
ufw enable |
Т.к. Apache будет нашим backend, настроим его на работу на localhost.
Открываем файл /etc/apache2/ports.conf
И редактируем директиву Listen, должно получиться так:
1 |
Listen 127.0.0.1:80 |
Включаем необходимые для работы модули Apache2.
1 |
a2enmod rewrite |
1 |
a2enmod ssl |
Для корректного отображения ip адресов в логах установим модуль rpaf.
1 |
apt-get install libapache2-mod-rpaf |
1 |
a2enmod rpaf |
Так же вы можете отключить лишние модули, например вот так отключается модуль status.
1 |
a2dismod status |
Удаляем дефолтные сайты.
1 |
rm -f /etc/apache2/sites-available/*.* |
1 |
rm -f /etc/apache2/sites-enabled/*.* |
Перезапускаем Apache2.
1 |
service apache2 restart |
Теперь установим Nginx, он будет frontend.
1 |
apt-get install nginx |
Удаляем дефолтные конфиги.
1 |
rm -f /etc/nginx/sites-available/* |
1 |
rm -f /etc/nginx/sites-enabled/* |
Повторяем данные операции на втором веб сервере.
Теперь перейдем к настройке распределенной файловой системе GlusterFS.
Данная фс нужна для хранения и репликации файлов сайтов между веб серверами.
На каждом из веб серверов создадим правила Firewall.
1 |
ufw allow 24007:24010/tcp |
1 |
ufw allow 49152:49153/tcp |
1 |
ufw allow 38465:38467/tcp |
1 |
ufw allow 111/tcp |
1 |
ufw allow 111/udp |
На каждом из веб серверов открываем файл /etc/hosts и прописываем полные адреса веб серверов.
Должно получиться примерно так:
1 2 3 |
127.0.0.1 localhost hostname 127.0.0.1 webserver1.test.com webserver1 second_ip webserver2.test.com webserver2 |
Обратите внимание, что имя сервера на котором идет настройка указывается на 127.0.0.1, dns имя второго веб сервера указывается на его внешний ip.
Устанавливаем Gluster FS (выполняем это действие на каждом из серверов).
1 |
apt-get install glusterfs-server |
Теперь переходим на первый веб сервер и выполняем команду.
1 |
gluster peer probe webserver2.test.com |
Где webserver2.test.com, dns имя второго веб сервера.
Проверяем объединились ли сервера в кластер.
1 |
gluster peer status |
Как видите сервера в кластере.
1 |
State: Peer in Cluster (Connected) |
Теперь создадим кластерное хранилище с именем volume1,
1 |
gluster volume create volume1 replica 2 transport tcp webserver1.test.com:/gluster-storage webserver2.test.com:/gluster-storage force |
В данной команде:
volume1 — название хранилища
replica 2 — количество серверов реплик
webserver1.test.com:/gluster-storage -В данном случае webserver1.test.com имя сервера gluster, а /gluster-storage путь к папке в которой будут храниться изменения в фс Gluster
Вывод команды должне быть таким:
1 |
volume create: volume1: success: please start the volume to access data |
Теперь включаем созданное хранилище.
1 |
gluster volume start volume1 |
Вывод команды должен быть таким:
1 |
volume start: volume1: success |
Теперь установим клиентскую часть, для подключения созданной фс.
Выполните данные действия на каждом веб сервере:
Устанавливаем необходимые компоненты.
1 |
apt-get install glusterfs-client |
Создаем директорию для монтирования (Выполняем на каждом веб сервере).
1 |
mkdir /storage-pool |
Редактируем файл /etc/fstab и добавляем в него строку с параметрами подключения (Выполняем на каждом веб сервере):
1 |
webserver1:/volume1 /storage-pool glusterfs defaults,_netdev,backupvolfile-server=webserver2 0 0 |
В данной строке указываются следующие параметры:
webserver1:/volume1 — Адрес сервера к которому идет подключение (желательно указывать серверу самого себя) и название хранилища.
/storage-pool — папка, куда будет смонтирована фс.
backupvolfile-server — адрес резервного сервера.
Монтируем общее хранилище(Выполняем на каждом веб сервере).
1 |
mount /storage-pool |
Теперь на каждом веб сервере настроим список ip, которым можно подключать хранилище.
Сделать это можно командой:
1 |
gluster volume set volume1 auth.allow gluster_client1_ip,gluster_client2_ip |
Где вместо gluster_client1_ip,gluster_client2_ip вводятся ip адреса веб серверов.
Теперь создадим папку с сайтами.
1 |
mkdir /storage-pool/hosting |
Далее откроем доступ к папке с сайтами, для этого редактируем файл /etc/apache2/apache2.conf и вносим в него следующие строки (Делаем это на каждом веб сервере):
1 2 3 4 5 |
<Directory /storage-pool/hosting> Options FollowSymLinks AllowOverride all Require all granted </Directory> |
Создадим конфиг для нового сайта. (Делаем на каждом веб сервере)
1 |
touch /etc/apache2/sites-available/newsite.conf |
Открываем конфиг в вводим следующее:
1 2 3 4 5 6 |
<VirtualHost *:80> ServerName newsite.test.com DocumentRoot /storage-pool/hosting/newsite CustomLog /var/log/apache2/newsite.access.log combined ErrorLog /var/log/apache2/newsite.error.log </VirtualHost> |
В данном примере:
Сайт работает на 80-м порту
Сайт доступен по DNS адресам newsite.test.com
Сайт расположен в директории – /storage-pool/hosting/newsite
(adsbygoogle = window.adsbygoogle || []).push({});
Создаем каталог с новым сайтом.
1 |
mkdir /storage-pool/hosting/newsite |
Включаем сайт (Делаем на каждом веб сервере):
1 |
a2ensite newsite.conf |
Перезагрузим конфиги apache2 (Делаем на каждом веб сервере).
1 |
service apache2 reload |
Создадим конфиг сайта newsite для Nginx (Делаем на каждом веб сервере).
1 |
touch /etc/nginx/sites-available/newsite.conf |
Открываем конфиг в вводим следующее:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
server { listen ip_adress:80; server_name newsite.test.com; charset utf-8; access_log off; error_log /var/log/nginx/site.error.log; location ~* \.(txt|jpg|jpeg|gif|png|bmp|swf|ico|css|js)$ { root /storage-pool/hosting/newsite; expires 7d; } location ~ /\.ht { deny all; } location / { root /storage-pool/hosting/newsite; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_pass http://127.0.0.1/; proxy_set_header Accept-Encoding ""; } } |
В данном конфиге:
Директива listen ip_adress:80 указывает на каком порту и ip работает сайт
Директива root указывает корневую директорию сайта
Директива server_name указывает dns имя сайта
Директива:
1 |
location ~* \.(txt|jpg|jpeg|gif|png|bmp|swf|ico|css|js |
Указывает тип статических файлов.
Директива expires указывает сколько дней хранить статический контент.
Директива:
1 2 |
location ~ /\.ht { deny all; |
Запрещает Nginx отдавать файлы начинающиеся с .ht
Директива:
1 2 3 4 |
proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_pass http://127.0.0.1/; proxy_set_header Accept-Encoding ""; |
Указывает что Nginx работает как обратный прокси и передает запросы на localhost.
Включаем сайт командой. (Делаем на каждом веб сервере).
1 |
ln -s /etc/nginx/sites-available/newsite.conf /etc/nginx/sites-enabled/newsite.conf |
Перезапускаем Nginx. (Делаем на каждом веб сервере).
1 |
service nginx restart |
Теперь в качестве примера установим CMS WordPress.
Скачиваем последнюю версию WordPress.
1 |
wget http://wordpress.org/latest.tar.gz |
Разархивируем архив с CMS.
1 |
tar -xzvf latest.tar.gz |
Копируем сайт.
1 |
cp -r ~/wordpress/* /storage-pool/hosting/newsite |
Теперь перейдем к настройке Mysql репликации.
Переходим на первый веб сервер и открываем файл /etc/mysql/my.cnf.
Изменяем в конфиге следующие строки:
1 2 3 4 |
server-id = 1 log_bin = /var/log/mysql/mysql-bin.log binlog_do_db = example_DB # bind-address = 127.0.0.1 |
В данном конфиге:
server-id – номер id mysql сервера
log_bin – путь к бинарному логу, в него пишутся изменения
binlog_do_db – название БД, которую мы будем реплицировать
# bind-address – строка закоментирована, т.к. сервер должен работать не только на localhost
Перезапускаем mysql сервер.
1 |
service mysql restart |
Перейдем к настройке репликации.
Подключаемся к Mysql.
1 |
mysql -u root -p |
Создадим пользователя replicator.
1 |
create user 'replicator'@'%' identified by 'password'; |
Создаем базу данных, которую мы будем реплицировать.
1 |
create database example_DB; |
Назначим права пользователю.
1 |
grant replication slave on *.* to 'replicator'@'%'; |
Проверить статус репликации можно командой:
1 |
show master status; |
Запоминаем параметры File (mysql-bin.000001) и Position (107). Эти параметры нам понадобятся на втором веб сервере.
Отключаемся от консоли mysql.
1 |
exit |
Переходим на второй веб сервер и правим конфиг файл /etc/mysql/my.cnf
Конфиг файл второго сервера будет отличаться только id.
1 2 3 4 |
server-id = 2 log_bin = /var/log/mysql/mysql-bin.log binlog_do_db = example_DB # bind-address = 127.0.0.1 |
Перезапускаем mysql на втором сервере.
1 |
service mysql restart |
Повторяем операции по созданию пользователя.
1 |
mysql -u root -p |
1 |
create user 'replicator'@'%' identified by 'password'; |
Создаем базу данных, которую мы будем реплицировать.
1 |
create database example_DB; |
Назначим права пользователю.
1 |
grant replication slave on *.* to 'replicator'@'%'; |
Запускаем процесс репликации.
1 |
slave stop; |
Параметры MASTER_LOG_FILE и MASTER_LOG_POS берем с первого сервера (вывод команды show master status;).
1 |
CHANGE MASTER TO MASTER_HOST = 'ip address first mysql server', MASTER_USER = 'replicator', MASTER_PASSWORD = 'password', MASTER_LOG_FILE = 'mysql-bin.000001', MASTER_LOG_POS = 107; |
1 |
slave start; |
Теперь посмотрим статус репликации:
1 |
SHOW MASTER STATUS; |
1 2 3 4 5 6 |
+------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000004 | 107 | example_DB | | +------------------+----------+--------------+------------------+ 1 row in set (0.00 sec) |
(adsbygoogle = window.adsbygoogle || []).push({});
Запоминаем название файла и параметр позиции, эти данные понадобятся нам при включении репликации на первом сервере.
Теперь вернемся на первый сервер и включим репликацию на нем:
1 |
slave stop; |
Меняем параметры MASTER_LOG_FILE и MASTER_LOG_POS полученные ранее из команды SHOW MASTER STATUS;
1 |
CHANGE MASTER TO MASTER_HOST = 'ip address second mysql server', MASTER_USER = 'replicator', MASTER_PASSWORD = 'password', MASTER_LOG_FILE = 'mysql-bin.000004', MASTER_LOG_POS = 107; |
1 |
slave start; |
Теперь репликация работает на двух серверах.
Откроем консоль mysql и выполним команды:
1 |
mysql -u root -p |
1 |
CREATE USER wordpressuser@localhost; |
1 |
SET PASSWORD FOR wordpressuser@localhost= PASSWORD("password"); |
1 |
GRANT ALL PRIVILEGES ON example_DB.* TO wordpressuser@localhost IDENTIFIED BY 'password'; |
1 |
FLUSH PRIVILEGES; |
1 |
exit |
Данными командами мы создали пользователя mysql для подключения из CMS WordPress к базе данных example_DB.
Теперь настроим CSM WordPress для работы с базой данных.
Копируем конфиг WordPress.
1 |
cp /storage-pool/hosting/newsite/wp-config-sample.php /storage-pool/hosting/newsite/wp-config.php |
Открываем файл wp-config.php и редактируем следующие поля:
1 2 3 4 5 6 7 |
// ** MySQL settings - You can get this info from your web host ** // /** The name of the database for WordPress */ define('DB_NAME', 'example_DB'); /** MySQL database username */ define('DB_USER', 'wordpressuser'); /** MySQL database password */ define('DB_PASSWORD', 'password'); |
Теперь настроим права на папку с сайтами.
1 |
chown -R www-data /storage-pool/hosting/ |
Теперь CSM wordpress сможет работать с базой данных.
На этом настройка схемы №1 окончена. При падении одного из веб серверов сайт http://newsite.test.com будет оставаться доступным.
Для реализации схемы №2 вам нужно добавить еще один балансировщик Nginx и создать в DNS две A записи вашего сайта, каждая из которых должна указывать на ip адрес одного из балансировщиков.
На этом реализация отказоустойчивого веб сервера завершена) Удачной настройки)
Комментарии