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

VRRP — протокол резервирования виртуальных маршрутизаторов, предназначен для повышения отказоустойчивости сервисов по сети или организации балансировки нагрузки между узлами. Отказоустойчивость достигается объединением нескольки узлов один виртуальным адресом, который переназначется следующему узлу, при отказе основного узла. В среде Linux для реализации VRRP используется демон Keepalived.

В данной статье будет рассмотрена только организация отказоустайчивости, без балансировки. Настройка будет производиться на серверах Debian 11 с адресами 10.25.128.50 — node1, 10.25.128.51 — node2, в качестве виртуального ip-адреса возьмем — 10.25.128.55

Настройка node1

Установим keepalived

apt-get install keepalived

Конфигурационный файл keepalived

cat /etc/keepalived/keepalived.conf
########################
## VRRP configuration ##
########################

# Указываем VRRP istance (экземпляр). Например даем ему имя failover_test
vrrp_instance failover_test {

#Статус сервера в VRRP instance. Может быть MASTER или BACKUP

state MASTER

# Укапзываем интерфейс к которому будет привязан VRRP instance

interface eth0

# Указываем произвольно значение в интервале от 1 до 255,
#для того чтобы одназначно определить instance среди других,
#которые могут быть запущены на хосте.
#Должен быть одинаков на всех хостах в instance.

virtual_router_id 10

# Приоритет хоста. Тот хост, который имеет больший приоритет,
# будет являться MASTER. По-умолчанию значение равно 100.

priority 110

# Указываем время в секундах между VRRP запросами между хостами в instance.
# По-умолчанию 1 секунда.

advert_int 4

# Authentication method: AH indicates ipsec Authentication Header.
# It offers more security than PASS, which transmits the
# authentication password in plaintext. Some implementations
# have complained of problems with AH, so it may be necessary
# to use PASS to get keepalived"s VRRP working.
#
# The auth_pass will only use the first 8 characters entered.

#Метод аутентификации. AH - ipsec Authentication Header
#   PASS - пароль в открытом виде.
# AH более безопасен и рекомендуется использовать его,
#но в некоторых реализациях keepalived AH метод может не работать,
#тогда необходимо использовать PASS.

authentication {
auth_type AH
auth_pass 1111
}

# VRRP запросы обычно являются мультикастовыми. Если вы хотите ограничить
#устройства, которые будут видить эти запросы, можно использовать директиву
#unicast_peer, где указываются IPv4 или IPv6 адреса хостов в instance.

unicast_peer {
10.25.128.51
}

# Указваем общий виртуальный ip-адрес для членов VRRP instance.
# Можем указать какому интерфейсу он будет назначен, а так же с
# помощью директивы "label" указать для него описание.

 virtual_ipaddress {
 10.25.128.55 dev eth0 label eth0:vip
}

}

Запустим демон keepalived

systemctl start keepalived
systemctl enable keepalived

Переходим к настройки второго хоста.

Настройка node2

Установим keepalived

apt-get install keepalived

Конфигурационный файл keepalived

cat /etc/keepalived/keepalived.conf
########################
## VRRP configuration ##
########################

# Указываем VRRP istance (экземпляр). Например даем ему имя failover_test
vrrp_instance failover_test {

# Статус сервера в VRRP instance. Может быть MASTER или BACKUP
# Устанавливаем статус BACKUP

state BACKUP

# Укапзываем интерфейс к которому будет привязан VRRP instance

interface eth0

# Указываем произвольно значение в интервале от 1 до 255,
#для того чтобы одназначно определить instance среди других,
#которые могут быть запущены на хосте.
#Должен быть одинаков на всех хостах в instance.

virtual_router_id 10

# Приоритет хоста. Тот хост, который имеет больший приоритет,
# будет являться MASTER. По-умолчанию значение равно 100.
# Устанавливаем приоритет меньше, чем на хосте MASTER

priority 100

# Указываем время в секундах между VRRP запросами между хостами в instance.
# По-умолчанию 1 секунда.

advert_int 4

# Authentication method: AH indicates ipsec Authentication Header.
# It offers more security than PASS, which transmits the
# authentication password in plaintext. Some implementations
# have complained of problems with AH, so it may be necessary
# to use PASS to get keepalived"s VRRP working.
#
# The auth_pass will only use the first 8 characters entered.

#Метод аутентификации. AH - ipsec Authentication Header
#   PASS - пароль в открытом виде.
# AH более безопасен и рекомендуется использовать его,
#но в некоторых реализациях keepalived AH метод может не работать,
#тогда необходимо использовать PASS.

authentication {
auth_type AH
auth_pass 1111
}

# VRRP запросы обычно являются мультикастовыми. Если вы хотите ограничить
#устройства, которые будут видить эти запросы, можно использовать директиву
#unicast_peer, где указываются IPv4 или IPv6 адреса хостов в instance.

unicast_peer {
10.25.128.50
}

# Указваем общий виртуальный ip-адрес для членов VRRP instance.
# Можем указать какому интерфейсу он будет назначен, а так же с
# помощью директивы "label" указать для него описание.

 virtual_ipaddress {
 10.25.128.55 dev eth0 label eth0:vip
}

}

Запустим демон keepalived

systemctl start keepalived
systemctl enable keepalived

Проверим работу нашего VRRP instance

На node1 проверим наличие общего виртуального ip-адреса

ifconfig
eth0: flags=4163  mtu 1500
   inet 10.25.128.50  netmask 255.255.255.0  broadcast 10.25.128.255
        inet6 fe80::216:3eff:fe81:f9b8  prefixlen 64  scopeid 0x20
        ether 00:16:3e:81:f9:b8  txqueuelen 1000  (Ethernet)
        RX packets 10658  bytes 20163348 (19.2 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 8434  bytes 603317 (589.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0:vip: flags=4163  mtu 1500
        inet 10.25.128.55  netmask 255.255.255.255  broadcast 0.0.0.0
        ether 00:16:3e:81:f9:b8  txqueuelen 1000  (Ethernet)

Теперь отключим интерфейс eth0 и посмотрим получит ли node2 виртуальный ip-адрес

ifconfig down

Подождем пока VRRP запросы пройдут

ifconfig
eth0: flags=4163  mtu 1500
   inet 10.25.128.51  netmask 255.255.255.0  broadcast 10.25.128.255
        inet6 fe80::216:3eff:fecb:ec1b  prefixlen 64  scopeid 0x20
        ether 00:16:3e:cb:ec:1b  txqueuelen 1000  (Ethernet)
        RX packets 13380  bytes 20350376 (19.4 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 7617  bytes 522763 (510.5 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0:vip: flags=4163  mtu 1500
        inet 10.25.128.55  netmask 255.255.255.255  broadcast 0.0.0.0
        ether 00:16:3e:cb:ec:1b  txqueuelen 1000  (Ethernet)

node2 получил виртуальный ip-адрес

Как только node1 станет вновь доступной, то виртуальный ip-адрес перейдет снова на нее так как она указана с более высоким приоритетом.

Посмотрим как это работает с помощью tcpdump

......
14:42:22.947698 fe:3a:55:a9:e2:19 (oui Unknown) > 00:16:3e:81:f9:b8 (oui Unknown),
ethertype IPv4 (0x0800), length 98: 10.25.128.1 > 10.25.128.55: ICMP echo request,
id 26070, seq 1, length 64

14:42:23.946686 fe:3a:55:a9:e2:19 (oui Unknown) > 00:16:3e:81:f9:b8 (oui Unknown),
ethertype IPv4 (0x0800), length 98: 10.25.128.1 > 10.25.128.55: ICMP echo request,
id 26070, seq 2, length 64
.....

14:42:51.944068 fe:3a:55:a9:e2:19 (oui Unknown) > 00:16:3e:cb:ec:1b (oui Unknown),
ethertype IPv4 (0x0800), length 98: 10.25.128.1 > 10.25.128.55: ICMP echo request,
id 26070, seq 30, length 64

.....

14:42:55.944108 00:16:3e:cb:ec:1b (oui Unknown) > 00:16:3e:81:f9:b8 (oui Unknown),
ethertype IPv4 (0x0800), length 98: 10.25.128.1 > 10.25.128.55: ICMP echo request,
id 26070, seq 34, length 64
.....

......
14:43:03.944110 fe:3a:55:a9:e2:19 (oui Unknown) > 00:16:3e:81:f9:b8 (oui Unknown),
ethertype IPv4 (0x0800), length 98: 10.25.128.1 > 10.25.128.55: ICMP echo request,
id 26070, seq 42, length 64

14:43:04.944144 fe:3a:55:a9:e2:19 (oui Unknown) > 00:16:3e:81:f9:b8 (oui Unknown),
ethertype IPv4 (0x0800), length 98: 10.25.128.1 > 10.25.128.55: ICMP echo request,
id 26070, seq 43, length 64

14:43:05.944093 fe:3a:55:a9:e2:19 (oui Unknown) > 00:16:3e:81:f9:b8 (oui Unknown),
ethertype IPv4 (0x0800), length 98: 10.25.128.1 > 10.25.128.55: ICMP echo request,
id 26070, seq 44, length 64

Видим что ICMP пакеты сначала отправляются на MAC-адрес MASTER хоста, потом после отключения на нем интервейса eth0, запросы начинают идти на MAC-адрес BACKUP, а после восстановления работы интерфейса, через какое то время снова идут на MASTER сервер.