HAProxy. Установка и настройка

Материал из megapuper
Перейти к: навигация, поиск

Установку будем проводить на Debian 11. Если текущая версия устраивает, то просто apt install haproxy. Если требуется последняя, то подключаем репозиторий.


Добавляем ключ репозитория

curl https://haproxy.debian.net/bernat.debian.org.gpg | gpg --dearmor > /usr/share/keyrings/haproxy.debian.net.gpg


Добавляем сам репозиторий

echo deb "[signed-by=/usr/share/keyrings/haproxy.debian.net.gpg]" http://haproxy.debian.net bullseye-backports-2.6 main > /etc/apt/sources.list.d/haproxy.list
apt update


Ставим HAProxy

apt-get install haproxy=2.6.\*


Конфигурирование HAProxy выполняется в файле /etc/haproxy/haproxy.cfg. Все основные настройки находятся в 4-х секциях:

  • global. Глобальные настройки, распространяемые на все публикации.
  • defaults. Настройки, применяемые по умолчанию, если они не указаны явно в публикации.
  • frontend. Правила обработки запросов, приходящих на сервер и передачи этих запросов серверам backend. Может быть несколько.
  • backend. Настройка конечных серверов, которые обрабатывают запросы и возвращают результаты. Может быть несколько.

Также есть возможность создать дополнительные секции, например userlist.


Простейший конфиг будет выглядеть примерно так

global
       log /dev/log    local0
       log /dev/log    local1 notice
       log 127.0.0.1   local2
       chroot /var/lib/haproxy
       stats timeout 30s
       user haproxy
       group haproxy
       daemon
       maxconn 10000

defaults
       log     global
       mode    http
       option  httplog
       option  dontlognull
       timeout connect 5000
       timeout client  50000
       timeout server  50000
       maxconn 10000

frontend http_front
       bind *:80
       mode http
       log global
       bind  *:1937 #for stats page
       stats enable
       stats uri /stats
       stats hide-version
       stats realm Haproxy\ Statistics
       stats auth username:password

       log-format %ci\ %ft\ %b/%s\ %ST\ %B\ %CC\ \%CS\ %tsc\ %ac/%fc/%bc/%sc/%rc\ %bq\ %hr\ %hs\ %{+Q}r
 
       monitor-uri /monitoruri

       default_backend homepage_back

backend homepage_back
       balance roundrobin
       server 192.168.150.54:80 check
       server 192.168.150.55:80 check

Конфиг определяет балансировщик нагрузки транспортного уровня (layer 4) с внешним именем http_front, прослушивающий порт 80, который затем направляет трафик к бэкенду по умолчанию с именем homepage_back, состоящий из двух веб-серверов. Трафик на них распределяется по очереди. По /stats подключается страница статистики, защищённая паролем.


Настройка балансировки нагрузки на прикладном уровне(layer 7)

Полезно, когда части веб-приложения расположены на разных хостах. Например, основная страница на одном хосте, а блог на другом. Это может быть достигнуто путем регулирования передачи соединения, например, по URL.

frontend http_front
       bind *:80
       stats uri /stats
       acl url_blog path_beg /blog
       use_backend blog_back if url_blog
       default_backend homepage_back

backend homepage_back
      balance roundrobin
      server 192.168.150.54:80 check
      server 192.168.150.55:80 check

backend blog_back
      server 192.168.150.56:80 check

Фронтенд объявляет правило ACL с именем url_blog, которое применяется ко всем соединениям с путями, начинающимися с /blog. Use_backend определяет, что соединения, соответствующие условию url_blog, должны обслуживаться бэкендом с именем blog_back, а все остальные запросы обрабатываются бэкендом по умолчанию.


frontend http_front
    bind 192.168.150.55:80
    acl url_stat path_end -i .css .js

    use_backend static if url_stat
    default_backend webserver

В данном случае слушаем веб-запросы и если они идут на файлы с расширениями .css или .js, передаем запрос на бэкэнд static. Все остальные запросы передаем на бэкэнд webserver.


Алгоритмы балансировки нагрузки

  • Roundrobin: каждый сервер используется по очереди в соответствии со своим весом. Это самый плавный и честный алгоритм, когда время обработки серверами остается равномерно распределенным. Этот алгоритм является динамическим, что позволяет регулировать вес сервера на лету.
  • Leastconn: выбирается сервер с наименьшим количеством соединений. Циклический перебор выполняется между серверами с одинаковой нагрузкой. Использование этого алгоритма рекомендуется для длинных сеансов, таких как LDAP, SQL, TSE и т.д., но он не очень подходит для коротких сеансов, таких как HTTP.
  • First: первый сервер с доступными слотами для подключения получает соединение. Серверы выбираются от самого низкого числового идентификатора до самого высокого, который по умолчанию соответствует положению сервера в ферме. Как только сервер достигает значения maxconn, используется следующий сервер.
  • Source: IP-адрес источника хешируется и делится на общий вес запущенных серверов, чтобы определить, какой сервер будет получать запрос. Таким образом, один и тот же IP-адрес клиента будет всегда доставаться одному и тому же серверу, в то время как серверы остаются неизменными.
  • Static-rr — серверы используются по очереди. Нагрузка распространяется равномерно, в зависимости от указанного веса. Вес не может быть изменен на лету.
  • Uri — запросы с одним и тем же URL (до знака вопроса) будут переправляться на один и тот же сервер.
  • Url_param — запросы с одинаковыми параметрами GET (все, что после знака вопроса) будут переправляться на один и тот же сервер.


Примеры использования


  • HTTPS запросы

Frontend:

frontend https-frontend
   bind *:443 ssl crt /etc/ssl/domaincert.pem
   reqadd X-Forwarded-Proto:\ https
   default_backend https-backend

Backend:

backend https-backend
   redirect scheme https if !{ ssl_fc }
   server back1 192.168.150.54:80 check
   server back2 192.168.150.55:80 check


  • Распределение запросов по весу (weight)

Backend:

backend weight-backend
   ...
   server back1 192.168.150.54:80 weight 100
   server back2 192.168.150.55:80 weight 80

в данном примере запросы будут отправляться чаще на сервер back1


  • Поддержка sticky session

Backend:

backend sticky-backend
   ...
   server back1 192.168.150.54:80 cookie check
   server back2 192.168.150.55:80 cookie check

Поддержка sticky session позволит перенаправлять http-запросы пользователя всегда на один и тот же сервер. Это необходимо в том случае, когда не предусмотрен механизм хранения PHP-сессий в общем каталоге.


  • Защита паролем

Сделаем необходимость вводить пароль при подключении к серверу.

Получаем хеш пароля

echo -n 'password' | md5sum

В haproxy создаем список пользователей

userlist http-users
   user user1 password 5f4dcc3b5aa765d61d8327deb882cf99

Backend:

backend web-servers
   ...
   acl AuthAccept http_auth(http-users)
   http-request auth realm Site if !AuthAccept


  • Распределение запросов по серверам с помощью url_reg

С помощью url_reg можно распределить запросы по группам серверов исходя из URL страницы.

Frontend:

frontend https-frontend
   acl url_page1 url_reg -i ^/page1/[a-z0-9]{10}/(img|doc)/$
   acl url_page2 url_reg -i ^/page2/[a-zA-Z0-9]*/$
   use_backend back1 if url_page1
   use_backend back2 if url_page2
   default_backend www

в данном примере ищем страницы, которые начинаются на page1, затем слеш и 10 любых символов в нижнем регистре и/или цифр, еще один слеш и в конце либо img, либо doc - этому урлу присваиваем acl url_page1. Второй урл — page2, затем слеш и любое количество символов в нижнем регистре регистре и/или цифры — acl url_page2. Для url_page1 используем группу серверов back1, для url_page2 - back2. По умолчанию все запросы отправляем на backend www

Backend:

backend back1
   server www1 192.168.150.54:80 check
   server www2 192.168.150.53:80 check

backend back2
   server www3 192.168.150.55:80 check
   server www4 192.168.150.56:80 check

В работе url_reg и use_backend есть нюанс — Haproxy найдет все возможные acl для запросов, а перенаправит на тот use_backend, который первым встретится в конфигурации. Таким образом, если адрес страницы будет соответствовать нескольким acl, результат работы может быть непредсказуем. В этом случае, необходимо более частный acl ставить выше при описании use_backend.


Примеры директив

Заблокировать url если путь начинается с /admin

http-request deny if { path beg -i -m /admin }


Включение http/2(alpn h2) http1.1 тоже оставляем

bind *:443 ssl cert iwad.pem alpn h2,http/1.1


Запретить доступ из сети 192.168.0.0/24

http-request deny if { src 192.168.10.0/24 }


Примеры форматов для логов

frontend tcp_frontend
log-format "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq"
frontend engy_frontend
log-format %ci:%cp\ [%t]\ %ft\ %b/%s\ %Tq/%Tw/%Tc/%Tr/%Tt\ %ST\ %B\ %CC\ %CS\ %tsc\ %ac/%fc/%bc/%sc/%rc\ %sq/%bq\ %hr\ %hs\ {valid:%[ssl_c_verify],User:%{+Q}[ssl_c_s_dn(cn)]}
frontend https_frontend
log-format %ci:%cp\ [%t]\ %ft\ %b/%s\ %ST\ %B\ %CC\ %CS\ %tsc\ %ac/%fc/%bc/%sc/%rc\ %sq/%bq\ %hr\ %hs\ {valid:%[ssl_c_verify],User:%{+Q}[ssl_c_s_dn(cn)]}
frontend http_frontend
log-format %ci\ %ft\ %b/%s\ %ST\ %B\ %CC\ \%CS\ %tsc\ %ac/%fc/%bc/%sc/%rc\ %bq\ %hr\ %hs\ %{+Q}r
frontend mail_frontend
log-format "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq"
frontend k8s_api_frontend
log-format "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq"