Keepalived что это
Перейти к содержимому

Keepalived что это

  • автор:

Что такое Keepalived

Обновлено и опубликовано

Опубликовано: 24.01.2023

Keepalived —

легкое приложение для обеспечения отказоустойчивости сервисов и балансировки нагрузки.

Keepalived реализует набор средств проверки работоспособности, позволяя определять рабочие ноды кластера и менять состояние участников. Также keepalived позволяет выполнять набор хуков для автоматизации процесса при смене данного состояния. Высокая доступность достигается протоколом маршрутизации с виртуальным резервированием (VRRP).

Подробная документация представлена на сайте keepalived.readthedocs.io, но на английском языке. На русском инструкции ограничиваются примерами по настройке приложения.

Keepalived может быть установлен на все популярные дистрибутивы Linux. По умолчанию, он есть во многих официальных репозиториях и может быть установлен одной из двух команд:

apt install k eepalived

yum install k eepalived

* первая команда для deb (Debian / Ubuntu / Astra Linux), вторая для rpm (Rocky Linux / РЕД ОС).

Среди аналогов можно выделить:

Также в качестве аналога k eepalived часто приводят HAProxy. Тут важно сделать оговорку, что последний выполняет балансировку, пропуская трафик через себя, в то время как k eepalived позволяет определить рабочую ноду для прямого обращения. Кстати, k eepalived и HAProxy, иногда, используют вместе.

Встречается в статьях

Мини-инструкции:

  1. Шпаргалка по настройке SELinux для различных программ
  2. Установка, настройка и создание кластера с помощью keepalived

Keepalived: настройка высокой доступности и плавающих IP адресов в CentOS 7

date

17.03.2022

user

Андрей

directory

CentOS, Linux

comments

комментариев 6

В этой статье мы рассмотрим настройку отказоустойчивой конфигурации из двух прокси серверов squid для доступа пользователей в Интернет из корпоративной сети с простой балансировкой нагрузки через Round Robin DNS. Для построения отказоустойчивой конфигурации мы создадим HA-кластер с помощью keepalived.

HA-кластер — это группа серверов с заложенной избыточностью, которая создается с целью минимизации времени простоя приложения, в случае аппаратных или программных проблем одного из членов группы. Исходя из этого определения, для работы HA-кластера необходимо реализовать следующее:

    Проверка состояния серверов;

Обе эти задачи позволяет выполнить keepalived. Keepalived – системный демон на Linux системах, позволяющего организовать отказоустойчивость сервиса и балансировку нагрузки. Отказоустойчивость достигается за счет “плавающего» IP адреса, который переключается на резервный сервер в случае отказа основного. Для автоматического переключения IP адреса между серверами keepalived используется протокол VRRP (Virtual Router Redundancy Protocol), он стандартизирован, описан в RFC (https://www.ietf.org/rfc/rfc2338.txt).

Принципы работы протокола VRRP

В первую очередь нужно рассмотреть теорию и основные определения протокола VRRP.

  • VIP — Virtual IP, виртуальный IP адрес, который может автоматически переключаться между серверами в случае сбоев;
  • Master — сервер, на котором в данный момент активен VIP;
  • Backup — сервера на которые переключится VIP, в случае сбоя мастера;
  • VRID — Virtual Router ID, сервера объединенные общим виртуальным IP(VIP) образуют так называемый виртуальный роутер, уникальный идентификатор которого, принимает значения от 1 до 255. Сервер может одновременно состоять в нескольких VRID, при этом для каждой VRID должны использоваться уникальные виртуальные IP адреса.

Общий алгоритм работы:

    Master сервер с заданным интервалом отправляет VRRP пакеты на зарезервированный адрес multicast (многоадресной) рассылки 224.0.0.18, а все slave сервера слушают этот адрес. Multicast рассылка — это когда отправитель один, а получателей может быть много.

Важно. Для работы серверов в режиме multicast, сетевое оборудование должно поддерживать передачу multicast трафика.

Установка и настройка keepalived на CentOS

Установку и настройку будем проводить на примере серверов proxy-serv01 и proxy-serv02 на Centos 7 с установленным прокси сервером Squid. В нашей схеме мы будем использовать простейший способ распределения (балансировки) нагрузки — Round Robin DNS. Этот способ предполагает, что для одного имени в DNS регистрируется несколько IP адресов, и клиенты, при запросе получают поочередно сначала один адрес, потом другой. Поэтому нам понадобится два виртуальных IP адреса, которые будут зарегистрированы в DNS на одно имя и на которые в итоге будут обращаться клиенты. Схема сети:

настройка отказоустойчивого балансировщика нагрузки с плавающим IP адресом с помощью keepalived

У каждого Linux сервера есть два физических сетевых интерфейса: eth1 с белым IP адресом и доступом в Интернет, и eth0 в локальной сети.

В качестве реальных IP адресов серверов используются:
192.168.2.251 — для proxy-server01
192.168.2.252 — для proxy-server02

В качестве виртуальных IP адресов, которые будут автоматически переключаться между серверами в случае сбоев используются:
192.168.2.101
192.168.2.102

Важно. При настройке VRRP, в качестве адреса для виртуального IP не используется реальный адрес сервера, так как, в случае сбоя, его адрес переместится на соседний, и при восстановлении, он окажется изолированным от сети. Дело в том, чтобы вернуть свой адрес, нужно отправить в сеть VRRP пакет, но не будет IP адреса, с которого это возможно сделать.

Установить пакет keepalived нужно на обоих серверах, командой:

yum install keepalived

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

/etc/keepalived/keepalived.conf

Цветом выделены строки с отличающимися параметрами:

на сервере proxy-serv01 на сервере proxy-serv02
keepalived - конфиг master сервера keepalived - конфиг backup сервера

Разберем опции более подробно:

  • vrrp_instance — секция, определяющая экземпляр VRRP;
  • state — начальное состояние при запуске;
  • interface — интерфейс, на котором будет работать VRRP;
  • virtual_router_id — уникальный идентификатор VRRP экземпляра, должен совпадать на всех серверах;

Примечание. Можно встретить множество примеров, в которых при настройке VRRP используется опция authentication. Однако в документации keepalived упоминается о том, что аутентификация была удалена из VRRPv2 в спецификации RFC3768(https://tools.ietf.org/html/rfc3768) в 2004 году, так как не обеспечивала реальной безопасности. Рекомендуется избегать использования этой опции.

Если текущая сетевая конфигурация не позволяет использовать multicast, в keepalived есть возможность использовать unicast, т.е. передавать VRRP пакеты напрямую серверам, которые задаются списком. Чтобы использовать unicast, понадобятся опции:

  • unicast_src_ip — адрес источник для VRRP пакетов;
  • unicast_peer — блок IP адресов серверов, на которые будут рассылаться VRPP пакеты.

Таким образом, наша конфигурация определяет два VRRP экземпляра, proxy_ip1 и proxy_ip2. При штатной работе, сервер proxy-serv01 будет MASTER для виртуального IP 192.168.2.101 и BACKUP для 192.168.2.102, а сервер proxy-serv02 наоборот, будет MASTER для виртуального IP 192.168.2.102, и BACKUP для 192.168.2.101.

Если на сервере активирован файрвол, то нужно добавить разрешающие правила для multicast траффика и vrrp протокола с помощью iptables:

iptables -A INPUT -i eth0 -d 224.0.0.0/8 -j ACCEPT
iptables -A INPUT -p vrrp -i eth0 -j ACCEPT

Активируем автозагрузки и запустим службу keepalived на обоих серверах:

systemctl enable keepalived
systemctl start keepalived

После запуска службы keepalived, виртуальные IP будут присвоены интерфейсам из конфигурационного файла. Посмотрим текущие IP адреса на интерфейсе eth0 серверов:

На сервере proxy-serv01:

ip a show eth0 master keepalived

На сервере proxy-serv02:

ip a show eth0 backup keepalived

Keepalived: отслеживание состояния приложений и интерфейсов

Благодаря протоколу VRRP штатно обеспечивается мониторинг состояния сервера, например, при полном физическом отказе сервера, или сетевого порта на сервере или коммутаторе. Однако, возможны и другие проблемные ситуации:

  • ошибка в работе службы прокси сервера — клиенты, которые попадут на виртуальный адрес этого сервера, будут получать сообщение в браузере с ошибкой, что прокси сервер недоступен;
  • отказ в работе второго интерфейса в интернет — клиенты, которые попадут на виртуальный адрес этого сервера, будут получать сообщение в браузере с ошибкой, что не удалось установить соединение.

Для обработки перечисленных выше ситуаций, воспользуемся следующими опциями:

  • track_interface — мониторинг состояния интерфейсов, переводит VRRP экземпляр в состояние FAULT, если один из перечисленных интерфейсов находится в состоянии DOWN;
  • track_script — мониторинг с использованием скрипта, который должен возвращать 0 если проверка завершилась успешно , 1 — если проверка завершилась с ошибкой.

Обновим конфигурацию, добавим мониторинг интерфейса eth1 (по умолчанию, VRRP экземпляр будет проверять интерфейс, к которому он привязан, т.е. в текущей конфигурации eth0):

track_interface < eth1

Директива track_script запускает скрипт с параметрами, определенными в блоке vrrp_script, который имеет следующий формат:

vrrp_script  < script interval - периодичность запуска скрипта, по умолчанию 1 секунда fall - количество раз, которое скрипт вернул не нулевое значение, при котором перейти в состояние FAULT rise - количество раз, которое скрипт вернул нулевое значение, при котором выйти из состояния FAULT timeout - время ожидания, пока скрипт вернет результат, после которого вернуть ненулевое значение. weight - значение, на которое будет уменьшен приоритет сервера, в случае перехода в состояние FAULT. По умолчанию 0, что означает, что сервер перейдет в состояние FAULT, после неудачного выполнения скрипта за количество раз, определенное параметром fall. >

Настроим мониторинг работы Squid. Проверить, что процесс активен, можно командой:

Создадим vrrp_script, с параметрами периодичности выполнения каждые 3 секунды. Этот блок определяется за пределами блоков vrrp_instance.

vrrp_script chk_squid_service < script "/usr/sbin/squid -k check" interval 3 >

Добавим наш скрипт в мониторинг, внутри обоих блоков vrrp_instance:

track_script

Теперь при ошибке в работе службы прокси Squid, виртуальный IP адрес переключится на другой сервер.

Вы можете добавить дополнительные действия при изменении состояния сервера.

Если Squid настроен на прием подключений с любого интерфейса, т.е. http_port 0.0.0.0:3128, то при переключении виртуального IP адреса, никаких проблем не возникнет, Squid будет принимать подключения на новом адресе. Но, если настроены конкретные IP адреса, например:

http_port 192.168.2.101:3128 http_port 192.168.2.102:3128

то Squid не узнает о том, что в системе появился новый адрес, на котором нужно слушать запросы от клиентов. Для обработки подобных ситуаций, когда нужно выполнить дополнительные действия при переключении виртуального IP адреса, в keepalived заложена возможность выполнения скрипта при наступлении события изменения состояния сервера, например, с MASTER на BACKUP, или наоборот. Реализуется опцией:

notify "путь к исполняемому файлу"

Keepalived: тестирование переключения при отказе

После настройки виртуальных IP, проверим, насколько корректно происходит обработка сбоев. Первая проверка — имитация сбоя одного из серверов. Отключим от сети внутренний сетевой интерфейс eth0 сервера proxy-serv01, при этом он перестанет отправлять VRRP пакеты и сервер proxy-serv02 должен активировать у себя виртуальный IP адрес 192.168.2.101. Результат проверим командой:

На сервере proxy-serv01:

keepalived - state DOWN

На сервере proxy-serv02:

keepalived - state up

Как и ожидалось, сервер proxy-serv02 активировал у себя виртуальный IP адрес 192.168.2.101. Посмотрим, что при этом происходило в логах, командой:

cat /var/log/messages | grep -i keepalived

Keepalived_vrrp[xxxxx]: Kernel is reporting: interface eth0 DOWN Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) Entering FAULT STATE Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) removing protocol VIPs. Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) Now in FAULT state
Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) Transition to MASTER STATE

VRRP Entering FAULT STATEVRRP_Instance Transition to MASTER STATE

И проверим, что после включения в сеть интерфейса eth0 на сервере proxy-serv01, виртуальный IP 192.168.2.101 переключится обратно.

Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) forcing a new MASTER election Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) Transition to MASTER STATE Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) Entering MASTER STATE Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) setting protocol VIPs. Keepalived_vrrp[xxxxx]: Sending gratuitous ARP on eth0 for 192.168.2.101
Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) Received advert with higher priority 255, ours 100 Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) Entering BACKUP STATE Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) removing protocol VIPs.

Вторая проверка – имитация сбоя интерфейса внешний сети, для этого отключим от сети внешний сетевой интерфейс eth1 сервера proxy-serv01. Результат проверки проконтролируем по логам.

Keepalived_vrrp[xxxxx]: Kernel is reporting: interface eth1 DOWN Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) Entering FAULT STATE Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) removing protocol VIPs. Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) Now in FAULT state
Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) Transition to MASTER STATE Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) Entering MASTER STATE Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) setting protocol VIPs. Keepalived_vrrp[xxxxx]: Sending gratuitous ARP on eth0 for 192.168.2.101

Keepalived Now in FAULT state

Третья проверка — имитация сбоя работы службы прокси Squid, для этого вручную оставим службу командой: systemctl stop squid Результат проверки проконтролируем по логам.

Keepalived_vrrp[xxxxx]: VRRP_Script(chk_squid_service) failed Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) Entering FAULT STATE Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) removing protocol VIPs. Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) Now in FAULT state
Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) Transition to MASTER STATE Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) Entering MASTER STATE Keepalived_vrrp[xxxxx]: VRRP_Instance(proxy_ip1) setting protocol VIPs. Keepalived_vrrp[xxxxx]: Sending gratuitous ARP on eth0 for 192.168.2.101

Все три проверки пройдены успешно, keepalived настроен корректно. В продолжении этой статьи будет произведена настройка HA-кластера с помощью Pacemaker, и рассмотрена специфика каждого из этих инструментов.

Итоговый конфигурационный файл /etc/keepalived/keepalived.conf для сервера proxy-serv01:

vrrp_script chk_squid_service < script "/usr/sbin/squid -k check" interval 3 >vrrp_instance proxy_ip1 < state MASTER interface eth0 virtual_router_id 1 priority 255 virtual_ipaddress < 192.168.2.101/24 dev eth0 label eth0:1 >track_interface < eth1 >track_script < chk_squid_service >> vrrp_instance proxy_ip2 < state BACKUP interface eth0 virtual_router_id 2 priority 100 virtual_ipaddress < 192.168.2.102/24 dev eth0 label eth0:2 >track_interface < eth1 >track_script < chk_squid_service >>

Итоговый конфигурационный файл /etc/keepalived/keepalived.conf для сервера proxy-serv02:

vrrp_script chk_squid_service < script "/usr/sbin/squid -k check" interval 3 >vrrp_instance proxy_ip1 < state BACKUP interface eth0 virtual_router_id 1 priority 100 virtual_ipaddress < 192.168.2.101/24 dev eth0 label eth0:1 >track_interface < eth1 >track_script < chk_squid_service >> vrrp_instance proxy_ip2 < state MASTER interface eth0 virtual_router_id 2 priority 255 virtual_ipaddress < 192.168.2.102/24 dev eth0 label eth0:2 >track_interface < eth1 >track_script < chk_squid_service >>

Предыдущая статьяПредыдущая статья Следующая статья Следующая статья

Отказоустойчивый кластер с балансировкой нагрузки с помощью keepalived

Сегодня я расскажу о том, как быстро собрать отказоустойчивый кластер с балансировкой нагрузки с помощью keepalived на примере DNS-серверов.

Итак, предположим, что у нас есть сервер, который должен работать без перебоев. Его нельзя просто так взять и выключить посреди рабочего дня — клиенты или пользователи не поймут. Тем не менее любой сервер время от времени надо обслуживать, ставить обновления, менять аппаратную конфигурацию или сетевые настройки. Кроме того, нужно быть готовым к росту нагрузки, когда мощности сервера перестанет хватать. У сервера должна быть предусмотрена возможность быстрого масштабирования. Если вы озаботились этими проблемами, то вам нужно организовать отказоустойчивый кластер.

Чаще всего такие задачи приходится делать с HTTP-серверами. Я сегодня покажу сборку кластера на примере DNS, потому что опробовал технологию именно на нем, но с минимальными изменениями то же самое можно сделать и с серверами, работающими по TLS или HTTP.

Лирическое отступление о проблемах DNS

В принципе, DNS задуман так, чтобы необходимости городить огород с кластерами не возникало. В каждой зоне можно прописать множество NS-записей, в каждой сети можно раздать список DNS-серверов с помощью DHCP. DNS-сервера умеют реплицировать зоны, поэтому они хорошо масштабируются. Однако на практике это плохо работает. Когда я попробовал добавить 2-й DNS-сервер, то обнаружил, что

  1. Половина пользователей сидят со статическими настроенными адресами DNS-серверов. Ставят себе 4 восьмерки в качестве primary и локальный DNS в качестве secondary.
  2. Многие Linux-сервера не умеют из коробки корректно обновлять настройки DNS. Там такой зоопарк из glibc, nsswitch.conf, resolv.conf, NetworkManager, resolvconf, systemd-resolved, hosts, dhclient.conf и т. п., которые конфликтуют между собой, что рассчитывать на автоматическое обновление по DHCP просто не приходится.
  3. Windows шлет запросы одновременно на все сервера, но обязательно дожидается ответа или таймаута от 1-го
  4. Linux сначала обращается к 1-му DNS в списке и только в случае ошибки переходит к следующему.

Если долгое время в сети используется DNS-сервер с определенным IP, то он оказывается прописан в десятках разных мест. Например:

  • Директива resolver в nginx.conf
  • daemon.json в docker
  • В настройках docker-контейнеров
  • В конфигах модных нынче систем вроде kubernetes или openshift во внутренних файлах на каждой ноде и еще там же в конфигах dnsmasq.
  • В конфигах почтовых серверов.
  • В настройках VPN-серверов.

Никакими плейбуками и DHCP-декларациями это все обновить просто нереально. Поэтому было бы очень хорошо, если бы собираемый кластер можно было повесить на 1 уже существующий IP. Тогда для пользователей ничего не изменится, и софт перенастраивать не понадобится.

Поэтому я выбрал решение с keepalived и протоколом VRRP.

Подготовка

Собирая кластер из нескольких серверов, желательно уметь их различать на стороне клиента, чтобы не бегать искать по логам серверов, какой запрос, куда попал. Я для этого в bind9 завел вот такую зону.

/var/named/zones/load.balance.zone

$ORIGIN load.balance. $TTL 1h load.balance. 86400 IN SOA ns.mydomain.ru. dnsmaster.mydoamin.ru. ( 1603065098 3600 1800 604800 30 ) load.balance. IN NS ns.mydomain.ru. health IN TXT =nameserver-1=

На 1-м сервере ресурсная запись TXT для health.load.balance содержит текст =nameserver-1=, на 2-м сервере — =nameserver-2=, и т. д. Таким образом, отправляя запрос в кластер, я по ответу могу определить, какой сервер мне ответил, что очень удобно для отладки.

Если у вас HTTP-сервер, то поместите эту информацию в HTTP-заголовок. Например, для nginx я использую вот такую директиву

add_header serega-trace "$hostname" always;

Убедитесь, что ваши сетевые файерволлы не блокируют IP-трафик протокола 112 по адресу 224.0.0.18. Этот адрес будут использовать ваши сервера, чтобы договариваться между собой о том, кто из них MASTER, а кто BACKUP.

Открыть VRRP в iptables

iptables -t filter -I INPUT -p vrrp -d 224.0.0.18 -j ACCEPT iptables -t filter -I OUTPUT -p vrrp -d 224.0.0.18 -j ACCEPT

При организации DNS нужно выделить мастер-сервер, на который не будут идти клиентские запросы. DNS-мастер используется только для управления. Он реплицирует свои зоны на slave-сервера, которые уже видны пользователям, и именно на них идет нагрузка. Далее речь будет идти о кластеризации именно DNS-slave.

Уровень 1 (Easy)

Если вам просто достаточно резервирования на случай аварии, то рекомендую рассмотреть самый быстрый и простой вариант. 2 одинаковых сервера разделяют между собой общий виртуальный IP (далее буду называть его VIP). У кого в данный момент в сетевом интерфейсе прописан VIP, тот сервер и работает. 2-й сервер следит за мастером (имеется в виду мастер VRRP, а не DNS), и как только обнаруживает, что он перестал вещать, сразу объявляет мастером себя и поднимает VIP на своем сетевом интерфейсе.

Меня приятно удивило то, как быстро удалось поднять кластер по такому варианту. Несмотря на то, что раньше я никогда не имел дело с keepalived, уже через час все работало. Так что если вам нужно решить задачу быстро, то уровень 1 вам подойдет в самый раз.

Сбор информации

Для успешного развертывания вам понадобится собрать следующую информацию. Здесь я привожу значения для примера. У вас эти значения должны быть свои.

Параметр Возможное значение Описание
vip 10.2.1.5 виртуальный IP, на который шлют запросы клиенты
dev0 eth0 1-й сетевой интерфейс на узлах кластера
ip01 10.2.1.2 IP 1-го узла кластера на 1-м сетевом интерфейсе
ip02 10.2.1.3 IP 2-го узла кластера на 1-м сетевом интерфейсе
net0 10.2.1.0/24 подсеть, которой принадлежат ip01 и ip02

Установите keepalived и snmpd. SNMP ставить необязательно, но мне кажется, что, если серверов с виртуальными IP будет много, он будет полезен.

setenforce 0 # если вдруг у вас selinux dnf install -y keepalived nmap-ncat net-snmp net-snmp-utils systemctl enable keepalived systemctl enable snmpd

Netcat нужен для диагностики и healthcheck-ов.

В файл /etc/sysconfig/keepavlied добавьте опцию -x. Она нужна для взаимодействия keepalived с snmpd. Если вы не собираетесь поднимать SNMP, то этот шаг можете пропустить.

Отредактируйте файл /etc/snmp/snmpd.conf следующим образом:

/etc/snmp/snmpd.conf

master agentx rocommunity public

В /etc/keepalived положите вот такой скрипт keepalived-notify.sh:

/etc/keepalived/keepalived-notify.sh

#!/bin/sh umask -S u=rwx,g=rx,o=rx exec echo "[$(date -Iseconds)]" "$0" "$@" >>"/var/run/keepalived.$1.$2.state"

Этот скрипт будет вызываться демоном keepalived при изменении состояния кластера. Он запишет в каталог /var/run статусный файл, который удобно использовать для диагностики.

Отредактируйте основной конфигурационный файл keepalived.conf следующим образом:

global_defs < enable_script_security >vrrp_script myhealth < script "/bin/nc -z -w 2 127.0.0.1 53" interval 10 user nobody >vrrp_instance VI_1 < state BACKUP interface eth0 virtual_router_id 5 priority 100 advert_int 1 nopreempt notify /etc/keepalived/keepalived-notify.sh root authentication < auth_type PASS auth_pass KPSjXfRG >virtual_ipaddress < 10.2.1.5 >track_script < myhealth >>

Блок global_defs содержит единственную необходимую настройку enable_script_security, которая по умолчанию отключена.

Блок vrrp_script описывает скрипт, который демон keepalived будет использовать для определения работоспособности своего сервера. Если этот скрипт вернет ошибку, то демон перейдет в состояние FAIL, и не будет претендовать на роль MASTER. В этом же блоке описывается периодичность выполнения healthchek-ов и указывается пользователь, от имени которого запускается скрипт. В нашем случае используется утилита netcat, которая устанавливает соединение c локальным DNS-сервером по TCP-порту 53. Можно использовать разные проверки, например, прозвонить UDP-порт 53 утилитой dig.

В блоке VRRP_INSTANCE задаются настройки 1 экземпляра сервера с виртуальным IP.

  • state задает начальное состояние сервера BACKUP или MASTER. В режиме nopreempt единственное допустимое значение — BACKUP.
  • interface указывает, на каком сетевом интерфейсе будет поднят VIP
  • virtual_router_id уникальный идентификатор роутера VRRP. Возможные значения от 1 до 255. У всех узлов кластера это значение должно быть одинаковым. Рекомендуется в качестве router_id использовать последний байт VIP, чтобы не запутаться, когда у вас таких виртуальных адресов будет много.
  • priority задает приоритет данного экземпляра при выборе мастера. Мастером назначается сервер, у которого значение параметра priority выше. Если у нескольких серверов priority одинаковый, то мастер будет выбран случайным образом.
  • advert_int определяет, с какой периодичностью мастер должен сообщать остальным о себе. Если по истечению данного периода сервера не получат от мастера широковещательное уведомление, то они инициируют выборы нового мастера.
  • nopreempt означает, что если мастер пропал из сети, и был выбран новый мастер с меньшим приоритетом, то по возвращении старшего мастера, он останется в состоянии BACKUP. Т. е. если вы перезагрузили мастер, то он больше мастером не станет, пока новый мастер не отвалится. Если вы предпочитаете, чтобы мастером был какой-то конкретный сервер, то замените настройку nopreempt на preempt_delay.
  • notify задает хук-скрипт, который будет вызываться при каждом изменении состояния сервера, и имя пользователя, от имени которого данный скрипт будет выполняться.
  • authentication задает пароль, длиной до 8 символов, который будет защищать кластер от случайных коллизий с другими серверами в локальной сети.
  • virtual_ipaddress задает VIP
  • track_script указывает на описание скрипта, осуществляющего healthcheck.

Выполните указанные настройки на обоих серверах кластера и запустите сервисы:

systemctl start snmpd systemctl start keepalived

Проверьте логи и статусные файлы на наличие ошибок.

journalctl -u snmpd journalctl -u keepalived tail /var/run/keepalived.INSTANCE.VI_1.state

Если у вас используется selinux, не забудьте по данным audit.log обновить политики и вернуть enforcing mode командой set enforce 1.

Проверка

Если в логах ошибок нет, можно проверять. Поскольку мы кластеризовали DNS, то будем использовать dig. Для проверки HTTP-сервера подойдет curl.

Запустите на клиенте такой скрипт:

while true; do dig -4 +short +notcp +norecurse +tries=1 +timeout=1 \ -q health.load.balance. -t txt @10.2.1.5; sleep 1; done

Этот скрипт будет раз в секунду выдавать ресурсную запись health.load.balance/IN/TXT, которая содержит идентификатор сервера. В нашей конфигурации это будет тот сервер, который сейчас VRRP-мастер.

Зайдите на этот сервер и убедитесь, что в файле /var/run/keepalived.INSTANCE.VI_1.state в последней строке указано MASTER.

Перезапустите на мастере сервис keepalived. Если у вас все сделано правильно, то мастер поменяется. На 1-м сервере в файле keepalived.INSTANCE.VI_1.state появятся строки STOP и BACKUP, на втором сервере в этом же файле появится строка MASTER, а клиентский скрипт станет выдавать ресурсную запись с идентификатором нового мастера.

[2020-10-13T10:48:00+00:00] /etc/keepalived/keepalived-notify.sh INSTANCE VI_1 BACKUP 100 [2020-10-13T11:26:29+00:00] /etc/keepalived/keepalived-notify.sh INSTANCE VI_1 MASTER 100
"=nameserver-1=" "=nameserver-1=" "=nameserver-1=" "=nameserver-2=" "=nameserver-2 spoiler" role="button" tabindex="0"> /etc/keepalived/keepalived.conf 
global_defs < enable_script_security >vrrp_instance VI_1 < state BACKUP interface eth0 virtual_router_id 5 priority 100 advert_int 1 nopreempt notify /etc/keepalived/keepalived-notify.sh root authentication < auth_type PASS auth_pass KPSjXfRG >virtual_ipaddress < 10.2.1.5 >> virtual_server 10.2.1.5 53 < protocol UDP delay_loop 10 lvs_sched rr lvs_method NAT real_server 10.2.1.2 53 < DNS_CHECK < type txt name health.load.balance >> real_server 10.2.1.3 53 < DNS_CHECK < type txt name health.load.balance >> > virtual_server 10.2.1.5 53 < protocol TCP delay_loop 10 lvs_sched rr lvs_method NAT real_server 10.2.1.2 53 < TCP_CHECK < connect_timeout 3 >> real_server 10.2.1.3 53 < TCP_CHECK < connect_timeout 3 >> >

Начало конфигурации аналогично предыдущему варианту без балансировки, только из блока vrrp_instance исчез track_script, соответственно за ненадобностью был удален блок vrrp_script.

Главное отличие в новой конфигурации заключается в блоках virtual_server. Для DNS требуется 2 виртуальных сервера, для 53-го порта TCP и для 53-го порта UDP. В случае HTTP-сервера аналогично потребуются сервера для 80-го и 443-го портов TCP.

Каждый виртуальный сервер идентифицируется 3 значениями: IP, порт и протокол. IP и порт через пробел указываются в заголовке блока virtual_server, а протокол определяется параметром protocol внутри блока. Допустимые протоколы TCP и UDP. В случае DNS как раз нужны оба.

Параметр delay_loop задает периодичность, с которой балансировщик опрашивает бэкенды для определения их состояния.

Самые важные параметры в виртуальном сервере — это lvs_sched и lvs_method. lvs_sched задает алгоритм, по которому балансировщик определяет, куда отправить очередной IP-пакет. lvs_method задает механизм, который использует балансировщик для направления пакетов в выбранный пункт назначения.

В приведенном примере lvs_sched равен rr, что означает round robin, т. е. балансировка равномерно по очереди. lvs_method используется NAT. Кроме NAT доступны также механизмы DR (direct routing) и TUN (tunneling). На мой взгляд, NAT — единственный рабочий вариант. Остальные методы работают только в очень специфических условиях.

Каждый виртуальный сервер состоит из нескольких реальных серверов, что отражено в соответствующих вложенных блоках real_server. Внутри блока real_server надо описать способ опроса его состояния, т. е. healthcheck.

После такой настройки keepalived работает следующим образом:

  1. Принимает IP-пакет с адресом получателя равным VIP.
  2. Выбирает real_server, куда необходимо направить пакет, анализируя протокол, порт, lvs_sched и результаты healthcheck-ов.
  3. Заменяет в IP-пакете адрес получателя на IP-адрес выбранного реального сервера и отправляет его дальше.

Только для работы этого недостаточно. Выбранный реальный сервер отправит ответный IP-пакет, в котором адрес отправителя будет равен его собственному IP-адресу. Клиент дропнет такой пакет, потому что он отправлял запрос на VIP и ожидает ответы от VIP, а не с IP-адреса реального сервера.

Чтобы решить эту проблему, нужно заставить реальный сервер отправить ответ не на IP клиента, а на IP мастера, чтобы тот выполнил обратную подстановку реального IP на виртуальный.

Для этого понадобится itpables и некоторые настройки ядра.

dnf -y install iptables iptables-services systemctl enable iptables systemctl start iptables
echo "net.ipv4.ip_forward=1" >>/etc/sysctl.d/99-sysctl.conf echo "net.ipv4.vs.conntrack=1" >>/etc/sysctl.d/99-sysctl.conf sysctl -w net.ipv4.ip_forward=1 sysctl -w net.ipv4.vs.conntrack=1

Добавьте в iptables следующее правило:

iptables -t nat -I POSTROUTING 1 -d 10.2.1.0/24 -j SNAT --to-source 10.2.1.5 service iptables save

Действие SNAT означает, что после маршрутизации в IP-пакете IP-адрес источника будет заменен на IP-адрес to-source. Вместо SNAT можно также использовать действие MASQUERADE, которое делает то же самое, только определяет исходящий IP автоматически.

Поскольку были внесены изменения в такие вещи как iptables и параметры ядра, рекомендуется перезагрузить сервер и убедиться, что ничего из этого не потерялось.

Выполните описанные действия на обоих серверах кластера. Проверьте логи и статусные файлы. Если ошибок нет, то выполните проверку работы кластера способом, описанным выше. Теперь должен получиться вот такой вывод:

"=nameserver-1=" "=nameserver-2=" "=nameserver-1=" "=nameserver-2=" "=nameserver-1 plaintext">"=nameserver-1=" "=nameserver-1=" "=nameserver-1=" "=nameserver-1=" "=nameserver-1 scrollable-table"> 
Параметр Возможное значение Описание
vip 10.2.1.5 виртуальный IP, на который шлют запросы клиенты
dev0 eth0 1-й сетевой интерфейс на узлах кластера
dev1 eth1 2-й сетевой интерфейс на узлах кластера
ip01 10.2.1.2 IP 1-го узла кластера на 1-м сетевом интерфейсе
ip02 10.2.1.3 IP 2-го узла кластера на 1-м сетевом интерфейсе
ip11 10.2.1.6 IP 1-го узла кластера на 2-м сетевом интерфейсе
ip12 10.2.1.7 IP 2-го узла кластера на 2-м сетевом интерфейсе
net0 10.2.1.0/24 подсеть, которой принадлежат ip01 и ip02

Скорректируйте конфигурацию keepalived по указанному образцу.


/etc/keepalived/keepalived.conf
global_defs < enable_script_security >vrrp_instance VI_1 < state BACKUP interface eth0 virtual_router_id 5 priority 100 advert_int 1 nopreempt notify /etc/keepalived/keepalived-notify.sh root authentication < auth_type PASS auth_pass KPSjXfRG >virtual_ipaddress < 10.2.1.5 >> virtual_server 10.2.1.5 53 < protocol UDP delay_loop 10 lvs_sched rr lvs_method NAT real_server 10.2.1.6 53 < DNS_CHECK < connect_ip 10.2.1.2 type txt name health.load.balance >> real_server 10.2.1.7 53 < DNS_CHECK < connect_ip 10.2.1.3 type txt name health.load.balance >> > virtual_server 10.2.1.5 53 < protocol TCP delay_loop 10 lvs_sched rr lvs_method NAT real_server 10.2.1.6 53 < TCP_CHECK < connect_ip 10.2.1.2 connect_timeout 3 >> real_server 10.2.1.7 53 < TCP_CHECK < connect_ip 10.2.1.3 connect_timeout 3 >> >

От предыдущей конфигурации новая отличается тем, что для реальных серверов указаны IP с дополнительных сетевых интерфейсов, но healthcheck-и отправляются на IP основных сетевых интерфейсов. Обратите внимание на этот момент. Все сервера кластера опрашивают друг друга, но на дополнительных сетевых интерфейсах будут настроены маршруты на VIP, поэтому узлы, которые сейчас в состоянии BACKUP, не смогут получить ответ от новых IP-адресов.

Теперь необходимо прописать правильные маршруты для дополнительных сетевых интерфейсов.

Добавьте в файл /etc/iproute2/rt_tables 2 новых таблицы маршрутизации. В примере ниже добавлены таблицы table0 и table1.

/etc/iproute2/rt_tables

# # reserved values # 255 local 254 main 253 default 0 unspec # # local # #1 inr.ruhep 20 table0 21 table1

По документации к NetworkManager и CentOS 8 статические маршруты и правила следует помещать в файлы /etc/syconfig/network-scripts/route-eth0 и rule-eth0. На многих моих серверах именно так и сделано. Только почему-то на серверах, поднятых из одного и того же образа, формат этих файлов оказался разным. На большинстве серверов route-eth0 выглядит так:

route-eth0 здорового человека

192.168.1.0/24 via 192.168.1.1 172.10.1.0/24 via 172.10.1.1

но почему-то на моих серверах DNS эти же файлы содержат вот это:

route-eth0 курильщика

ADDRESS0=192.168.1.0 NETMASK0=255.255.255.0 GATEWAY0=192.168.1.1 ADDRESS1=172.10.1.0 NETMASK1=255.255.255.0 GATEWAY1=172.10.1.1

Формат понятен, только совершенно непонятно, как в него поместить имя таблицы маршрутизации. Я не смог разобраться в этом вопросе. Если кто-то знает, в чем дело, поделитесь, пожалуйста, информацией в комментариях.

Поскольку сохранить маршруты в специальных системных файлах не удалось, пришлось сделать костыль.

UPD: в комментах товарищ Bearpuh подсказал, как это лечить.

/etc/keepalived/routes.sh

#!/bin/sh # https://tldp.org/HOWTO/Adv-Routing-HOWTO/lartc.rpdb.multiple-links.html vip="10.2.1.5" dev0="eth0" ip0="10.2.1.2" # "10.2.1.3" dev1="eth1" ip1="10.2.1.6" # "10.2.1.7" ip route add 10.2.1.0/24 dev "$dev0" src "$ip0" table table0 ip route add default via 10.2.1.1 table table0 ip rule add from "$ip0" table table0 ip route add "$vip/32" dev "$dev1" src "$ip1" ip route add default via "$vip" table table1 ip route add "$vip/32" dev "$dev1" src "$ip1" table table1 ip rule add from "$ip1" table table1

В комментарии в скрипте указаны значения, которые надо скорректировать при переносе скрипта на другой сервер.

Данный скрипт я добавил в автозапуск вместе с сервисом keepalived.

systemctl edit keepalived
[Service] ExecStartPre=/etc/keepalived/routes.sh

Не самое элегантное решение, но работает нормально, поэтому можете спокойно использовать, если не знаете, как можно сделать лучше.

Принципы задания правил маршрутизации описаны в Linux Advanced Routing & Traffic Control HOWTO. Идея заключается в том, что создается 2 независимые таблицы маршрутизации, в каждой свой шлюз по умолчанию. В зависимости от того, с какого сетевого интерфейса отправляется пакет, с помощью правил ip rule выбирается либо одна таблица, либо другая.

Удалите из iptables правило SNAT в цепочке POSTROUTING, добавленное при прохождении 2-го уровня. Сохраните состояние iptables.

iptables -t nat -D POSTROUTING -d 10.2.1.0/24 -j SNAT --to-source 10.2.1.5 service iptables save

Проверьте результат. Клиент должен получать ответы от каждого сервера поочередно, в логах на серверах должны писаться реальные IP клиентов.

Теперь имеется отказоустойчивый кластер, в котором все живые узлы принимают нагрузку и видят IP-адреса своих клиентов. Единственный небольшой минус у этой конфигурации заключается в том, что есть 1 скрипт, который на разных серверах должен иметь разные параметры. Небольшое усложнение администрирования, которое с лихвой окупается полученными преимуществами.

Сложность Масштабирование Единые настройки IP клиента
Уровень 1 Easy Нет Да Да
Уровень 2 Normal Да Да Нет
Уровень 3 Expert Да Нет Да

Установка и настройка keepalived

Пакет keepalived это open source программное обеспечение, предназначенное для обеспечения функций высокой надежности (high availabilitty) и балансировки нагрузки (load-balancing). За первую функцию отвечает реализация протокола VRRP, а вторая основывается на модуле ядра Linux Vitrual Server (IPVS). Keepalived не разрабатывается сотрудниками Eltex и не включает доработок, за исключением конфигурации. Keepalived используется для организации резервирования контроллеров SoftWLC, при этом используется только функционал VRRP.

Установка keepalived

Для установки пакета необходимо загрузить его на сервер и выполнить следующую команду (установка должна производиться от имени суперпользователя root):

root@master:/# apt update root@master:/# apt install keepalived

После установки необходимо добавить демона Keepalived в автозагрузку и запустить его:

root@master:/# systemctl enable keepalived root@master:/# systemctl start keepalived

Конфигурация keepalived

Конфигурация keepalived состоит из следующих файлов:

главный файл конфигурации сервиса

Основной файл конфигурации

Листинг основного файла конфигурации по умолчанию

/etc/keepalived/keepalived.conf Развернуть исходный код

! Configuration File for keepalived global_defs < script_user root enable_script_security >vrrp_script check_network < script "/etc/keepalived/check_ping.sh" interval 5 weight 50 fall 3 rise 3 init_fail user root >vrrp_instance VI_SWLC < state BACKUP interface virtual_router_id 1 track_script < check_network >track_interface < weight 50 > priority 150 advert_int 1 nopreempt # Uncomment and comment "nopreempt" if preemption needed #preempt_delay 180 authentication < auth_type PASS auth_pass eltex >virtual_ipaddress < dev eth0 label :1 > notify_master "/etc/keepalived/keep_notify.sh master" notify_backup "/etc/keepalived/keep_notify.sh backup" notify_fault "/etc/keepalived/keep_notify.sh fault" unicast_peer < > >
  • - наименование сетевого интерфейса;
  • - виртуальный ip-адрес (с указанием префикса);
  • - ip-адрес другого сервера;

Тест-скрипт

В текущей реализации в качестве тестового скрипта предлагается использовать следующий:

/etc/keepalived/check_ping.sh Развернуть исходный код

#!/bin/bash # host to ping # there - default gw HOST= # -q quiet # -c nb of pings to perform ping -q -c5 $HOST > /dev/null # $? var keeping result of execution # previous command if [ $? -eq 0 ] then echo `date +"%T %F"` "OK gw reachable" EXIT_CODE=0 else echo `date +"%T %F"` "ERROR gw unreacheble!" EXIT_CODE=1 fi exit $EXIT_CODE

где - шлюз по умолчанию для этого сервера.

Скрипт пингует шлюз по умолчанию и возвращает код результата. Таким образом, при успешном выполнении скрипта гарантируется, что SoftWLC достижим для внешних клиентов.

Конфигурация смены роли

При смене состояния сервера выполняется скрипт keep_notify.sh

/etc/keepalived/keep_notify.sh Развернуть исходный код

#!/bin/bash MYSQL_USER="" MYSQL_PASSWORD="" mongo_set_role() < local role="$1" if [[ "$(which mongo)" ]]; then mongo --quiet --eval "var role=\"$role\"" admin /etc/keepalived/mongo_switch.js # Uncomment if using mongodb auth #mongo -u-p --quiet --eval "var role=\"$role\"" admin /etc/keepalived/mongo_switch.js fi > if ! lockfile-create --use-pid -r 5 /tmp/keep.mode.lock; then echo "Unable to lock" echo "Unable to lock" > /tmp/keep.mode.lock.fail exit 0 fi case "$1" in master) # ems_reload_all echo "MASTER" > /tmp/keep.mode mongo_set_role master service eltex-ems restart service tomcat7 restart service eltex-ngw restart # рестарт слейва MySQL чтобы при восстановлении связи - сразу получить изменения, # а не ждать периодического heartbeat от второго сервера mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e "stop slave" mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e "start slave" ;; backup) echo "BACKUP" > /tmp/keep.mode mongo_set_role slave service mongodb restart service eltex-ems stop service tomcat7 stop service eltex-ngw stop mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e "stop slave" mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e "start slave" ;; fault) echo "FAULT" > /tmp/keep.mode mongo_set_role slave service mongodb restart ;; *) echo "Usage: $0 " exit 1 esac lockfile-remove /tmp/keep.mode.lock; exit 0

где и - логин и пароль от БД MySQL.

Скрипт смены мастера replicaSet MongoDB.

/etc/keepalived/mongo_switch.js Развернуть исходный код
// Предоставляется окружением var role; if (role != 'master' && role != 'slave') < throw "Role must be either master or slave"; >var thisIsMaster = (role == 'master'); var status = rs.isMaster(); var thisHost = status.me; print("Primary: " + status.ismaster + "; applying configuration . "); var cfg = rs.conf(); for (var i = 0; i < cfg.members.length; i++) < var member = cfg.members[i]; var self = (member.host == thisHost); if (self ^ thisIsMaster) < // Конфигурация для slave member.priority = 1; member.votes = 0; print(member.host + ": secondary"); >else < // Конфигурация для master member.priority = 2; member.votes = 1; print(member.host + ": primary"); >> var result = rs.reconfig(cfg, < force: !status.ismaster >); if (result.ok == 1) < print("Reconfiguration done"); >else

Выделение лога в отдельный файл

По умолчанию keepalived записывает лог в файл /var/log/syslog . Для удобства отладки, мониторинга и контроля работы keepalived можно настроить ведение собственного, отдельного лог-файла. Ниже приведен пример настройки rsyslog :

nano -w /etc/rsyslog.d/10-keepalived.conf if $programname contains 'Keepalived' then /var/log/keepalived.log if $programname contains 'Keepalived' then ~

Затем нужно перезапустить rsyslog командой:

root@swlc01-server:/# service rsyslog restart

Теперь сообщения от демона keepalived попадут только в лог-файл /var/log/keepalived.log и не попадут в /var/log/syslog .

Способ запуска/остановки keepalived

Для запуска сервиса воспользуйтесь командой:

service keepalived start

Ответ об успешном запуске будет такой:

keepalived start/running, process 2471
root@master:/# service keepalived stop
keepalived stop/waiting

Проверить состояние сервиса можно командой:

root@master:/# service keepalived status
keepalived start/running, process 2809

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *