Задача
В двух датацентрах хостятся одинаковые web-сервисы (Microsoft Exchange 2016) на нескольких серверах (в ДЦ каждом по два сервера).
Запросы к web-сервисам могут приходить как от процессов в одном из датацентров (пользователи VDI), так и из внешнего интернета.
Датацентры неравноправны. Один из них - основной (постоянно обслуживает основную массу запросов), второй - резервный (постоянно обслуживает меньшую часть запросов).
Зачача - настроить отказоустойчивый опенсорсный балансировщик, который бы мог бы пережить следующие дизастеры:
- падение одного или нескольких бекенд-серверов.
- падение одной из нод балансировщика (либо падение процесса балансировщика).
- нарушение связи между датацентрами.
Решение
Функционал high reliability реализуется с помощью демона, реализующего протокол VRRP, например - keepalived. Демон следит за состоянием нод кластера и если активная нода выходит из строя, то переключает нагрузку (передает IP-адрес) на запасную (пассивную) ноду.
Кроме keepalived можно использовать heartbeat.
keepalived попроще, а heartbeat пофункциональнее и имеет несколько иное назначение.
Будем настраивать active-passive связку из двух haproxy + keeapalived.
На каждой ноде будет практически однаково настроен haproxy. В конфигурациях backend-серверов будут прописаны серверы, находящиеся в одном датацентре с нодой балансировщика.
В конфигурации keepalived на каждой ноде балансировщика будет прописан скрипт, проверяющий состояние процесса haproxy и состояние сервиса. Нода балансировщика может считаться здоровой, если жив процесс haproxy и сервис доступен через балансировщик.
Настройка haproxy
haproxy - балансировщик. Осуществляет проверку состояния backend-серверов, балансирует нагрузку на них (в соответствии с кинфигурацией) и предоставляет к ним доступ через frontend.
Установка:
sudo apt-get update && sudo apt-get -y install haproxy
Вот пример настройки haproxy (/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 expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon
######## Default values for all entries till next defaults section
defaults
option dontlognull # Do not log connections with no requests
option redispatch # Try another server in case of connection failure
option contstats # Enable continuous traffic statistics updates
option logasap
retries 3 # Try to connect up to 3 times in case of failure
timeout connect 5s # 5 seconds max to connect or to stay in queue
timeout http-keep-alive 1s # 1 second max for the client to post next request
timeout http-request 15s # 15 seconds max for the client to send a request
timeout queue 30s # 30 seconds max queued on load balancer
timeout tarpit 1m # tarpit hold tim
backlog 10000 # Size of SYN backlog queue
mode tcp #alctl: protocol analyser
option tcplog #alctl: log format
log global #alctl: log activation
timeout client 300s #alctl: client inactivity timeout
timeout server 300s #alctl: server inactivity timeout
default-server inter 3s rise 2 fall 3 #alctl: default check parameters
frontend ft_exchange_tcp
bind *:443 name https #alctl: listener https configuration.
maxconn 100000 #alctl: connection max (depends on capacity)
default_backend exchange_2016_backend #alctl: default farm to use
backend exchange_2016_backend
balance roundrobin
# maximum SSL session ID length is 32 bytes.
stick-table type binary len 32 size 30k expire 10s
acl clienthello req_ssl_hello_type 1
acl serverhello rep_ssl_hello_type 2
# use tcp content accepts to detects ssl client and server hello.
tcp-request inspect-delay 5s
tcp-request content accept if clienthello
# no timeout on response inspect delay by default.
tcp-response content accept if serverhello
# SSL session ID (SSLID) may be present on a client or server hello.
# Its length is coded on 1 byte at offset 43 and its value starts
# at offset 44.
# Match and learn on request if client hello.
stick on payload_lv(43,1) if clienthello
# Learn on response if server hello.
stick store-response payload_lv(43,1) if serverhello
fullconn 100000
option httpchk GET /ews/healthcheck.htm "HTTP/1.0\r\nHost: exch2016.domain.com"
server exch_server1 exch1.domain.com:443 maxconn 100000 check check-ssl verify none
server exch_server2 exch2.domain.com:443 maxconn 100000 check check-ssl verify none
email-alert mailers mta
email-alert level info
email-alert from haproxy-alert@domain.com
email-alert to admin@domain.com
mailers mta
mailer smtp1 smtp.domain.com:25
frontend stats
bind *:8080
mode http
stats enable
# stats auth admin:adminpassword
stats uri /
Тут настраивается единственный frontend для единственного backend в режиме tcp.
Балансировка - round-robin.
Прописан session sticking, чтобы клиент не прыгал по серверам в пределах одной сессии.
Проверка состояния backend-серверов осуществляется с помощью запроса:
option httpchk GET /ews/healthcheck.htm "HTTP/1.0\r\nHost: exch2016.domain.com"
Если ответ 200, то backend-сервер считается живым.
Для второй ноды конфигурация такая же, но список backend-серверов другой:
server exch_server3 exch3.domain.com:443 maxconn 100000 check check-ssl verify none server exch_server4 exch4.domain.com:443 maxconn 100000 check check-ssl verify none
Настройка keepalived
keepalived следит за состоянием нод в пределах виртуального роутера (нод keepalive с одинаковым параметром virtual_router_id) и с заданным интервалом вычисляет приоритет (priority) ноды (в зависимости от результатов выполнения скрипта). Если приоритет ноды меняется - происходят выборы новой master-ноды. Если backup-нода обнаруживает недоступность master-ноды - она становится master-нодой.
Установка keepalived:
sudo apt-get update && sudo apt-get install keepalived
Вот конфигурация основной (master) ноды (/etc/keepalived/keepalived.conf):
global_defs { notification_email { admin@domain.com } notification_email_from haproxy-alert@domain.com smtp_server smtp.domain.com:25 smtp_connect_timeout 30 } vrrp_script chk_haproxy { script "/usr/bin/killall -0 haproxy && /usr/bin/curl -k 'https://localhost/ews/healthcheck.htm'" interval 2 weight 2 } vrrp_instance VI_1 { state MASTER interface ens160 virtual_router_id 101 priority 101 advert_int 1 smtp_alert authentication { auth_type PASS auth_pass superpassword } virtual_ipaddress { 172.30.129.131 } track_script { chk_haproxy } }
Тут прописаны секции:
- global_defs - глобальные параметры, в частности - параметры оповещения.
- vrrp_script chk_haproxy - сценарий проверки сосотяния haproxy - проверка наличия процесса haproxy и проверка доступности сервиса через haproxy, а также - интервал проверки и её вес (количество поинтов, которые прибавляются к приоритету, в случае успешной проверки).
- vrrp_instance VI_1 - описание инстанса VRRP. В этой секции некоторые параметры имеют различные значения на master и slave нодах): interface - имя сетевого интерфейса, на котором работает виртуальный IP, priority - приоритет ноды (нода с максимальным приоритетом забирает себе виртуальный IP). Параметры virtual_router_id (идентификатор виртуального роутера) и секция authentication должны быть одинаковыми на обоих нодах.
Вот конфигурация резервной (slave) ноды:
global_defs { notification_email { admin@domain.com } notification_email_from haproxy-alert@domain.com smtp_server smtp.domain.com:25 smtp_connect_timeout 30 } vrrp_script chk_haproxy { script "/usr/bin/killall -0 haproxy && /usr/bin/curl -k 'https://localhost/ews/healthcheck.htm'" interval 2 weight 2 } vrrp_instance VI_1 { state MASTER interface ens192 virtual_router_id 101 priority 100 advert_int 1 smtp_alert authentication { auth_type PASS auth_pass superpassword } virtual_ipaddress { 172.30.129.131 } track_script { chk_haproxy } }
Подключение клиентов
Для подключения клиентов:
- Для внутренних клиентов мы создаем запись в DNS, которая указывает на виртуальный IP, а клиенты подключаются к сервису по DNS-имени.
- Для внешних клиентов делаем port-mapping с внешнего IP на внутренний виртуальный IP.
Ссылки
https://www.digitalocean.com/community/tutorials/how-to-set-up-highly-available-haproxy-servers-with-keepalived-and-floating-ips-on-ubuntu-14-04
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/load_balancer_administration/ch-initial-setup-vsa
https://tecadmin.net/setup-ip-failover-on-ubuntu-with-keepalived/
Discussion