VRRP (Virtual Redundant Router Protocol), несмотря на неясную ситуацию с патентами Cisco, остается стандартным протоколом для горячего резервирования маршрутизаторов. Популярный в системах семейства BSD протокол CARP свободен от патентных ограничений, но статус стандарта и поддержка со стороны многих поставщиков имеют свои преимущества — существует по крайней мере теоретическая возможность сменить поставщика незаметно для пользователей сети.
В сегодняшней статье я расскажу, как настроить отказоустойчивый маршрутизатор на основе Linux и создать отказоустойчивую сеть. В качестве реализации VRRP мы будем использовать keepalived.
Протокол VRRP
VRRP — это аббревиатура Virtual Redundant Router Protocol. Группа физических маршрутизаторов объединяется в один виртуальный. Каждый участник группы может находиться в 3 состояниях:
- неопределенном (initialize)
- основном (master)
- резервном (backup)
У всех участников группы в настройках присутствует 1 или несколько виртуальных адресов. У основного эти адреса присвоены сетевой карте, а у других — просто ждут своего часа.
Прежде всего надо сказать, что VRRP работает поверх IP, а не напрямую поверх канального уровня. Если быть точным, он использует групповой (multicast) адрес 224.0.0.18. Поскольку multicast по умолчанию не маршрутизируется, взаимодействие возможно только в пределах одной физической сети.
Это значит, что, помимо общего виртуального адреса, каждому маршрутизатору на каждом сетевом интерфейсе, где вы настраиваете VRRP, должен быть присвоен основной, с которого он будет отправлять соседям служебные пакеты.
Надо сразу сказать, что основной (служебный) адрес совсем не должен быть из одной сети с виртуальными. Если у вас недостаточно публичных адресов для тех сетевых карт, которые смотрят в интернет, вы вполне можете использовать частные адреса из RFC 1918 в качестве служебных. Ну, если настройки вашего провайдера этого не запрещают.
У каждой группы маршрутизаторов есть VRID — Virtual Router Identifier. Это просто число в диапазоне от 1 до 255. С каждой такой группой может быть ассоциирован 1 или несколько виртуальных адресов. На уровне протокола список адресов передается, но только для отладочных целей. Процесс VRRP их никак не использует, тем более что передаются они без маски подсети, так что за идентичностью настроек виртуальных адресов надо следить самому.
Группы с разным VRID друг с другом не взаимодействуют, поэтому в одной физической сети может быть любое количество независимых групп резервирования, главное — настроить.
При загрузке или первичной настройке VRRP участники группы оказываются в неопределенном состоянии (initialize) и выбирают, кому быть основным, а кому резервным. В настройках VRRP можно указать приоритет (priority) — маршрутизатор с наибольшим приоритетом выигрывает выборы.
Если приоритет у нескольких маршрутизаторов одинаковый, выигрывает тот, у кого самый большой адрес IP. Я сам стараюсь не полагаться на случай и всегда указываю приоритет явно.
Маршрутизатор, который выбрали основным, присваивает своей сетевой карте виртуальные адреса и начинает посылать остальным пакеты VRRP advertisement. Таким образом он сообщает, что еще функционирует и работоспособен.
Пока эти пакеты приходят, резервные маршрутизаторы ничего не делают. Когда основной упадет и резервные заметят, что пакеты перестали приходить, они инициируют выборы заново и выберут новый основной из оставшихся, по тем же правилам.
Что будет, если бывший основной маршрутизатор вернется к жизни? Все зависит от опции preempt в настройках. Если она включена, то он повторно инициирует выборы и вернет себе былую славу. Если нет, так и останется резервным.
Включать или не включать preempt — вам решать. С одной стороны, с этой настройкой легко предсказать, какой маршрутизатор в данный момент основной, а с другой — переключений состояния, а значит, и потерянных пакетов будет больше. Я как правило включаю, но свое мнение никому не навязываю.
Настраиваем keepalived
Перейдем от теории к практике. В первую очередь нам потребуется пакет keepalived. Его функциональность шире, но в этой статье для настройки отказоустойчивой сети мы сосредоточимся именно на VRRP. Этот пакет есть в репозиториях у всех популярных дистрибутивов, так что с его установкой сложностей быть не должно.
Сценарий будет такой: два маршрутизатора, rtr-master со служебным адресом 192.0.2.1 и rtr-backup с адресом 192.0.2.2. В качестве виртуального адреса возьмем 192.0.2.254, а VRID установим в 10. Будем считать, что служебные адреса настроены на сетевом интерфейсе eth0.
Файл настроек лежит в /etc/keepalived/keepalived.conf. Начнем с резервного маршрутизатора, чтобы было легче увидеть, как его роль возьмет на себя основной. Присвоим ему приоритет, равный 100.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
rtr-backup$ cat /etc/keepalived/keepalive.conf vrrp_instance my-group { state BACKUP interface eth0 virtual_router_id 10 priority 100 advert_int 1 preempt_delay 0 virtual_ipaddress { 192.0.2.254/24 } } |
Запустим сервис с помощью systemctl start keepalived.service или эквивалента для систем без systemd. В выводе ip address show мы сможем увидеть, что он присвоил eth0 адрес 192.0.2.254.
Теперь создадим идентичный конфиг на rtr-master, но с опцией priority 200. Для наглядности запустим на rtr-master дамп трафика, например sudo tcpdump -vvv -ni eth0 vrrp. Когда мы запустим на нем keepalived, мы получим там такую картину:
1 2 3 4 5 6 7 8 9 10 11 12 |
192.0.2.2 > 224.0.0.18: vrrp 192.0.2.2 > 224.0.0.18: VRRPv2, Advertisement, vrid 10, prio 100, authtype none, intvl 1s, length 20, addrs: 192.0.2.254 06:27:47.495833 IP (tos 0xc0, ttl 255, id 410, offset 0, flags [none], proto VRRP (112), length 40) 192.0.2.2 > 224.0.0.18: vrrp 192.0.2.2 > 224.0.0.18: VRRPv2, Advertisement, vrid 10, prio 100, authtype none, intvl 1s, length 20, addrs: 192.0.2.254 06:27:48.133070 IP (tos 0xc0, ttl 255, id 1, offset 0, flags [none], proto VRRP (112), length 40) 192.0.2.1 > 224.0.0.18: vrrp 192.0.2.1 > 224.0.0.18: VRRPv2, Advertisement, vrid 10, prio 200, authtype none, intvl 1s, length 20, addrs: 192.0.2.254 06:27:49.133266 IP (tos 0xc0, ttl 255, id 2, offset 0, flags [none], proto VRRP (112), length 40) 192.0.2.1 > 224.0.0.18: vrrp 192.0.2.1 > 224.0.0.18: VRRPv2, Advertisement, vrid 10, prio 200, authtype none, intvl 1s, length 20, addrs: 192.0.2.254 06:27:50.133343 IP (tos 0xc0, ttl 255, id 3, offset 0, flags [none], proto VRRP (112), length 40) |
Как видим, rtr-backup отправлял пакеты VRRP, пока не получил пакет от rtr-master с большим приоритетом. В этот момент он перестал отправлять пакеты и перешел в состояние backup. Соответственно, rtr-master присвоил себе адрес 192.0.2.254.
Как можно узнать состояние VRRP не по косвенным признакам? Эта возможность присутствует в keepalived, но, к сожалению, в дистрибутивах она часто не включена при сборке пакета.
- kill -SIGUSR1 $(cat /var/run/keepalived.pid) для дампа данных о состоянии;
- kill -SIGUSR2 для дампа статистики;
- kill -36 для дампа данных в формате JSON.
Файлы сохраняются в /tmp/keepalived.*. Если быть точным, то дамп в JSON инициирует сигнал SIGRTMIN+2, в Linux это значение равно тридцати шести.
Совместимость с RFC
По RFC 3768, кроме виртуальных адресов IP, должны использоваться еще и виртуальные MAC-адреса, из диапазона 00-00-5E-00-01-XX.
Но при наших настройках, если посмотреть еще глубже в дамп трафика, можно увидеть, что пакеты отправляются с физического адреса самого eth0. В keepalived режим совместимости с RFC по умолчанию отключен. Когда-то давно — потому, что нужной функциональности в стабильных версиях ядра Linux не было. Теперь причины в основном исторические, но есть и практическая. Поскольку у каждой сетевой карты может быть один и только один MAC-адрес, достичь совместимости с RFC можно, только создав виртуальный интерфейс. Именно это keepalived и делает, но в этом случае правила netfilter и прочие настройки, в которых явно упомянуты имена сетевых интерфейсов (вроде iptables -I OUTPUT -o eth0 -j ACCEPT), перестанут применяться к интерфейсу с виртуальными адресами — имена интерфейсов не могут быть одинаковыми.
Поэтому перед тем, как включать этот режим, просмотри все настройки и убедись, что они не зависят от имен интерфейсов, или продублируй их для виртуального интерфейса.
Включить его можно опцией use_vmac <имя интерфейса>. Например, если добавить следующие строки, виртуальные адреса будут присвоены виртуальному интерфейсу eth0v10.
1 2 3 4 |
vrrp_instance my-group { use_vmac eth0v10 } |
На практике нестандартный режим по умолчанию обычно не вызывает никаких проблем, разве что с системами, которые принципиально не воспринимают gratuitous ARP (просьбу забыть связь IP- и MAC-адресов), но такие встречаются редко.
Дополнительные возможности
VRRP без multicast
Иногда можно нарваться на сети, где multicast не работает, но организовать резервирование как-то надо. Такое чаще всего бывает на интерфейсах, подключенных к коммутатору провайдера.
Выручит тебя столь же противоречащая RFC, но вполне работоспособная опция unicast-peer. В нашем случае можно добавить в vrrp_instance опцию unicast_peer { 192.0.2.2 } на rtr-master и, соответственно, unicast_peer { 192.0.2.1 } на rtr-backup.
Синхронизация групп
Как ты помнишь, VRRP настраивается отдельно для каждой физической сети. Очевидно, работоспособность одной сетевой карты никак не гарантирует работоспособность всего маршрутизатора.
Пусть у тебя есть маршрутизатор с двумя интерфейсами, один в локальную сеть, другой к провайдеру. Если соединение с провайдером упадет, то виртуальный внешний адрес перейдет к резервному маршрутизатору, но виртуальный внутренний так и останется, где был, и пакеты из локальной сети не пройдут дальше маршрутизатора.
Чтобы избежать подобного, можно использовать sync groups. Они работают так: если интерфейс из одной группы переходит в состояние backup, вместе с ним перейдут и все остальные.
Если у тебя настроены vrrp_instance с названиями LAN и WAN, связать их в одну группу синхронизации можно вот так:
1 2 3 |
vrrp_sync_group my-sync-group { group { LAN WAN } } |
Внешние скрипты
Иногда встроенной функциональности оказывается недостаточно. В этом случае можно расширить ее с помощью внешних скриптов.
Например, для тебя критически важна доступность сайта xakep.ru. Тогда можно создать скрипт /usr/local/bin/xakep_test.sh с ping -c1 xakep.ru и добавить в keepalived.conf следующее (не внутрь vrrp_instance):
1 2 3 4 5 6 |
vrrp_script xakep_test { script "/config/scripts/test.sh" interval 60 # Выполнять раз в минуту fall 3 # Три неудачных выполнения считать отказом rise 1 # Одно удачное считать успехом } |
А потом добавить внутрь vrrp_instance вот такую опцию: track_script { xakep_test }.
Можно также выполнять скрипты при изменении состояния VRRP, опциями
notify_master "/path/to/script",
notify_backup "/path/to/script" и
notify_fault "/path/to/script". В стандарте это не указано, но keepalived позволяет различать нормальный переход в состояние backup (например, из-за preempt) и аварийный. В первом случае выполняется скрипт из
notify_backup, а во втором — из
notify_fault.
Это бывает полезно для отправки уведомлений админу или для применения настроек, которые должны быть только на основном маршрутизаторе.
Отключаем preempt
По умолчанию keepalived использует preempt, то есть маршрутизатор с большим приоритетом всегда вернет себе статус master после возвращения из аварийного состояния. Если ты хочешь избежать лишних переключений, просто добавь nopreempt внутрь настроек vrrp_instance.
Заключение
Надеюсь, эта статья поможет тебе строить отказоустойчивые сети. Даже если ты используешь VRRP и keepalived только в составе специализированных сетевых дистрибутивов, а не напрямую, всегда полезно понимать, как он работает.