Контекст
Представим ситуацию, когда в инфраструктуре отказоустойчивая балансировка сервисов построена на базе пар балансировщиков нагрузки под управлением Keepalived и HAProxy. Чтобы утилизировать ресурсы обеих нод одновременно, используется схема Active/Active: на каждом узле сконфигурированы две независимые VRRP-группы (vrrp_grp_alpha и vrrp_grp_bravo). В штатном режиме Нода-01 держит пул адресов группы Alpha, а Нода-02 — группы Bravo.
Распределение трафика между площадками и дата-центрами регулируется GSLB (Global Server Load Balancing), который непрерывно опрашивает сервисные VIP-адреса через Health Check пробы.
Схема скрипта валидации (cluster_notify.sh):
#!/usr/bin/env bash
# Keepalived notify hook: INSTANCE <group_name> <state> [priority]
set -u
PATH=/usr/sbin:/usr/bin:/sbin:/bin
IFACE="eth0"
GATEWAY="192.0.2.1"
LOGTAG="vrrp-vip-audit"
log() { logger -t "$LOGTAG" -- "$*"; printf '%s\n' "$*"; }
if [[ $# -lt 3 || $1 != INSTANCE ]]; then
log "ERROR: expected INSTANCE <group> <state> [priority]"
exit 2
fi
GROUP=$2
STATE=$3
case "$GROUP" in
vrrp_grp_alpha)
VIPS=(192.0.2.10 192.0.2.11 192.0.2.12 192.0.2.13 192.0.2.14)
;;
vrrp_grp_bravo)
VIPS=(192.0.2.20 192.0.2.21 192.0.2.22 192.0.2.23 192.0.2.24)
;;
*)
log "ERROR: unknown VRRP group: $GROUP"; exit 2
;;
esac
case "$STATE" in
MASTER|BACKUP|FAULT|STOP) ;;
*) log "ERROR: unknown state: $STATE"; exit 2 ;;
esac
# Ожидание применения адресов ядром
sleep 2
mapfile -t LOCAL_IPS < <(ip -o -4 addr show dev "$IFACE" | awk '{split($4,a,"/");print a[1]}')
has_ip() {
local candidate=$1 ip
for ip in "${LOCAL_IPS[@]}"; do
[[ "$ip" == "$candidate" ]] && return 0
done
return 1
}
log "START host=$(hostname -s) group=$GROUP state=$STATE iface=$IFACE gateway=$GATEWAY"
errors=0
for vip in "${VIPS[@]}"; do
if [[ "$STATE" == MASTER ]]; then
# 1. Проверяем локальное наличие IP
if ! has_ip "$vip"; then
log "ERROR group=$GROUP vip=$vip: missing on $IFACE in MASTER"
((errors+=1))
continue
fi
# 2. Форсируем обновление ARP через исходящий ping к шлюзу
if ping -n -I "$vip" -c 3 -W 2 "$GATEWAY" >/dev/null 2>&1; then
log "OK group=$GROUP vip=$vip: gateway $GATEWAY reachable"
else
log "ERROR group=$GROUP vip=$vip: gateway $GATEWAY unreachable"
((errors+=1))
fi
else
# В BACKUP/FAULT адрес должен быть гарантированно снят
if has_ip "$vip"; then
log "ERROR group=$GROUP vip=$vip: unexpectedly present in $STATE"
((errors+=1))
else
log "OK group=$GROUP vip=$vip: absent in $STATE"
fi
fi
done
log "DONE host=$(hostname -s) group=$GROUP state=$STATE errors=$errors"
((errors == 0))
Опыт применения 0
Попробовали решение в своей задаче? Расскажите, что получилось.
Станьте первым, кто прокомментирует эту запись
Комментировать