Установка и настройка отказоустойчивого балансировщика нагрузки на Debian(ubuntu) на основе Keepalived для бэкэндов php-fpm.
1.Конфигурация.
Операционная система: debian 8 minimal(net install) с доступом по ssh.
Server1: lb1.domain.local 10.4.1.181 – основной loadbalancer(MASTER)
Server2: lb.domain.local 10.4.1.182– резервный loadbalancer(BACKUP) и т.д. На обоих серверах по 2 сети, одна из которых смотрит в инет и будет иметь у активного балансера ip 190 (eth1).
VIP(virtual IP) – 10.4.1.190 — плавающий/расшаренный между балансировщиками нагрузки виртуальный IP-адрес,на который прописаны сайты в DNS. Можно использовать больше балансировщиков, для большей отказоустойчивости, например 4. Просто будем менять все(приоритет у серверов)
Кластер из для обработки web-приложений – 2 ноды, которые будут полностью дублировать друг-друга.
Web-server-1: nginx+php-fpm+gluserfs+mysql(with replication – с репликацией). ip 10.4.1.151
Web-server-2: nginx+php-fpm+gluserfs+mysql(with replication – с репликацией). ip 10.4.1.152
Что мы получим в итоге. По обращение по ip 10.4.1.190 мы всегда будем иметь рабочий сайт(если не упадут 2 машины ))) ), так же при падении одной из машин,или падению nginx’a будем получать уведомление по e-mail. В общем, получим отказоустойчивое решение, что немаловажно в наше время в ввиду повсеместного перевода всех бизнес-процессов в сеть и соответсвенно простой сервиса – потеря прибыли(убыток).
2.Установка и настройка Keepalived на балансерах
(в зависимостях подтянет ipvsadm-утилиту для администрирования ipvs (ip virtul server)). Саму балансировку настроим в самом конце, после всех манипуляций со всеми нодами. так же установим sendmail для отправки оповещений.
sudo su aptitude install keepalived sendmail -y
Включаем маршрутизацию пакетов на обоих балансерах
# nano /etc/sysctl.conf
net.ipv4.ip_forward = 1 net.ipv4.ip_nonlocal_bind = 1
Проверяем
sysctl -p
Видим:
net.ipv4.ip_forward = 1
net.ipv4.ip_nonlocal_bind = 1
Двигаемся далее – редактируем lb1(1-ый балансировщик);
nano /etc/keepalived/keepalived.conf
! this is who emails will go to on alerts notification_email { a.v.galushko86@gmail.com ! add a few more email addresses here if you would like } notification_email_from servers@domain.com ! I use the local machine to relay mail smtp_server 1.1.1.1 smtp_connect_timeout 30 ! each load balancer should have a different ID ! this will be used in SMTP alerts, so you should make ! each router easily identifiable lvs_id LVS_EXAMPLE_01 } vrrp_script chk_http_port { script "/usr/bin/killall -0 nginx" interval 2 weight 2 } vrrp_instance lb1 { interface eth0 state MASTER virtual_router_id 190 # должен быть одинаковым у кластера keepalived priority 150 ! send an alert when this instance changes state from MASTER to BACKUP smtp_alert authentication { auth_type PASS auth_pass cbrt32456 } track_script { chk_http_port } virtual_ipaddress { 10.1.9.190/32 dev eth0 } }
Здесь мы настроили сервис – наш сервер-1 будет главным – state master, вес ему поставили 101(далее другим ставим меньше на один), обратите внимание на virtaul_router_id – у нашей связки он должен быть одним, будет опрелять кластер из наших серверов ( в данном случае ставим 52 на всех), так же обратите внимание на auth_pass – пароль для нашего кластера. virtual_ipaddress – виртуальный адресс нашего кластера keepalived.
Виртуальный ip мы повешаем на первую(eth0) сетевую карту, можно это сделать и на вторую(eth1) – как хотите, это не принципиально.
Запускаем keepalived
sudo /etc/init.d/keepalived start
Проверяем его
ip addr show | grep 190
Видим это
inet 10.1.9.190/32 scope global eth0
Далее на втором серваке – lb2 (server балансировщик 2);
nano /etc/keepalived/keepalived.conf
vrrp_script chk_http_port { script "/usr/bin/killall -0 nginx" interval 2 weight 2 } vrrp_instance VI_1 { interface eth0 state BACKUP virtual_router_id 190 # одиноаковый id для кластера priority 100 authentication { auth_type PASS auth_pass cbrt2456 } track_script { chk_http_port } virtual_ipaddress { 10.4.1.190/32 dev eth0 } }
Здесь все аналогично первому, только роль backup и вес поменьше. Всё ок.
Запускаем keepaliver
sudo /etc/init.d/keepalived start
Проверяем его
ip addr show | grep 190
Видим это(если первый сервак выключить или остановить keepalived на 1 серваке)
inet 10.1.9.190/32 scope global eth0
Небольшое отступление. На самом деле настроек keepalived.conf очень много, ниже я приведу конфиг, в котором они описаны( на англ) для ознакомления
! This is a comment ! Configuration File for keepalived global_defs { ! this is who emails will go to on alerts notification_email { admins@example.com fakepager@example.com ! add a few more email addresses here if you would like } notification_email_from admins@example.com ! I use the local machine to relay mail smtp_server 127.0.0.1 smtp_connect_timeout 30 ! each load balancer should have a different ID ! this will be used in SMTP alerts, so you should make ! each router easily identifiable lvs_id LVS_EXAMPLE_01 } ! vrrp_sync_groups make sure that several router instances ! stay together on a failure - a good example of this is ! that the external interface on one router fails and the backup server ! takes over, you want the internal interface on the failed server ! to failover as well, otherwise nothing will work. ! you can have as many vrrp_sync_group blocks as you want. vrrp_sync_group VG1 { group { VI_1 VI_GATEWAY } } ! each interface needs at least one vrrp_instance ! each vrrp_instance is a group of VIPs that are logically grouped ! together ! you can have as many vrrp_instaces as you want vrrp_instance VI_1 { state MASTER interface eth0 lvs_sync_daemon_inteface eth0 ! each virtual router id must be unique per instance name! virtual_router_id 51 ! MASTER and BACKUP state are determined by the priority ! even if you specify MASTER as the state, the state will ! be voted on by priority (so if your state is MASTER but your ! priority is lower than the router with BACKUP, you will lose ! the MASTER state) ! I make it a habit to set priorities at least 50 points apart ! note that a lower number is lesser priority - lower gets less vote priority 150 ! how often should we vote, in seconds? advert_int 1 ! send an alert when this instance changes state from MASTER to BACKUP smtp_alert ! this authentication is for syncing between failover servers ! keepalived supports PASS, which is simple password ! authentication ! or AH, which is the IPSec authentication header. ! I don't use AH ! yet as many people have reported problems with it authentication { auth_type PASS auth_pass example } ! these are the IP addresses that keepalived will setup on this ! machine. Later in the config we will specify which real ! servers are behind these IPs ! without this block, keepalived will not setup and takedown the ! any IP addresses virtual_ipaddress { 192.168.1.11 ! and more if you want them } } ! now I setup the instance that the real servers will use as a default ! gateway ! most of the config is the same as above, but on a different interface vrrp_instance VI_GATEWAY { state MASTER interface eth1 lvs_sync_daemon_inteface eth1 virtual_router_id 52 priority 150 advert_int 1 smtp_alert authentication { auth_type PASS auth_pass example } virtual_ipaddress { 10.20.40.1 } } ! now we setup more information about are virtual server ! we are just setting up one for now, listening on port 22 for ssh ! requests. ! notice we do not setup a virtual_server block for the 10.20.40.1 ! address in the VI_GATEWAY instance. That's because we are doing NAT ! on that IP, and nothing else. virtual_server 192.168.1.11 22 { delay_loop 6 ! use round-robin as a load balancing algorithm lb_algo rr ! we are doing NAT lb_kind NAT nat_mask 255.255.255.0 protocol TCP ! there can be as many real_server blocks as you need real_server 10.20.40.10 22 { ! if we used weighted round-robin or a similar lb algo, ! we include the weight of this server weight 1 ! here is a health checker for this server. ! we could use a custom script here (see the keepalived docs) ! but we will just make sure we can do a vanilla tcp connect() ! on port 22 ! if it fails, we will pull this realserver out of the pool ! and send email about the removal TCP_CHECK { connect_timeout 3 connect_port 22 } } } ! that's all
Вот такой вот конфиг мануал.
3.Настройка проксирования и балансировки на nginx на lb1 и lb2.
Теперь настроим наши сервера на, чтобы они слушали другие сервера в нашей сети с php+mysql на борту и распределяли между ними нагрузку, и в случае выхода одного из серверов переключались на другой.
Установим nginx
sudo apt-get install nginx
Правим конфиги на обоих серваках
sudo nano /etc/nginx
upstream backend { server 10.4.1.151:80; server 10.4.1.152:80; } server { listen 80; server_name example.org; location ~* \.()$ { root /var/www/example.org; } location / { client_max_body_size 10m; client_body_buffer_size 128k; proxy_send_timeout 90; proxy_read_timeout 90; proxy_buffer_size 4k; proxy_buffers 16 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; proxy_connect_timeout 30s; proxy_pass https://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
Как мы видим на наш nginx будут слушать и распределять нагрузку между нашими 2 серверами с ip 10.4.1.151 и 10.4.1.152. На нах будет крутиться php-fpm+nginx+mysql+gluster-fs. В принципе вы можете иметь сколько угодно реплицируемых серверов.О их настройке будет написано ниже.
Данная конфигурация работает так:
1. Как только первая Master нода перестает работать, например: /etc/init.d/network stop
! Происходит переключение на вторую ноду BackUp, при этом теряется 2-3 пакета, it’s okay, не так страшен зверь как то с чем его едят :)
2. После того как 1-ая нода Master оживает, /etc/init.d/network start, обратного автопереключения не происходит :( т.е. иду на вторую ноду BackUp жму /etc/init.d/network stop и ппц, пинги до моего внешго IP перестают идти, до того момента пока я руками на первой ноде Master не сделаю еще дополнительно /etc/init.d/network restart
Мне показалось что это не очень живучая конфигурация, живущая лишь только словах и на вере в лучшее.
Может быть у кого-то будут соображения на этот счет, как оптимизировать данную конфигурацию, чтобы её можно было назвать “отказоустойчивой”? :)