문제 상황: VIP는 넘어갔는데 트래픽은 안 온다
keepalived로 액티브-스탠바이를 구성하면 마스터 장애 시 VIP(가상 IP)가 백업 노드로 넘어간다. 그런데 페일오버 직후 수 초에서 수십 초 동안 서비스가 먹통이 되는 경우를 흔히 만난다. 노드에는 VIP가 정상적으로 붙어 있고 로컬에서 curl도 되는데, 외부 클라이언트만 접속이 안 된다.
원인은 L2에 있다. VIP는 그대로지만 그 IP를 응답하는 MAC 주소가 마스터 노드에서 백업 노드로 바뀌었다. 스위치의 MAC 학습 테이블과 클라이언트/게이트웨이의 ARP 캐시는 여전히 옛 마스터의 MAC을 가리킨다. 즉, 프레임이 죽은 노드로 계속 흘러간다.
왜 ARP 캐시가 문제인가
IP 통신은 최종적으로 MAC 주소로 프레임을 전달한다. 클라이언트나 게이트웨이는 "VIP → MAC" 매핑을 ARP 캐시에 보관하며, 이 항목은 보통 수십 초에서 수 분간 유지된다. keepalived가 VIP를 옮겨도 이 캐시가 스스로 갱신되기 전까지는 트래픽이 옛 MAC으로 향한다.
이를 능동적으로 깨는 수단이 gratuitous ARP(GARP)다. 요청하지 않았는데도 "이 IP는 이제 내 MAC이다"라고 브로드캐스트로 알리는 ARP 패킷이다. keepalived는 백업이 마스터로 승격되는 순간 이 GARP를 자동 전송해 스위치와 이웃 장비의 매핑을 강제로 갱신한다.
keepalived 기본 설정과 GARP 옵션
아래는 VRRP 인스턴스의 최소 구성이다. keepalived는 마스터 전환 시 기본적으로 GARP를 보내므로, 핵심은 재전송 횟수와 간격을 튜닝하는 것이다.
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 100
advert_int 1
# GARP 튜닝: 전환 직후 5개 즉시 전송
garp_master_repeat 5
garp_master_delay 1
# 지연 재전송: 스위치가 첫 패킷을 놓쳤을 때 대비
garp_master_refresh 10
garp_master_refresh_repeat 2
authentication {
auth_type PASS
auth_pass ch4ngeMe
}
virtual_ipaddress {
192.168.10.100/24 dev eth0
}
}
garp_master_repeat는 승격 직후 보내는 GARP 개수, garp_master_refresh는 이후 주기적 재전송 간격(초)이다. 패킷 유실이 잦은 환경에서는 재전송이 안전망이 된다.
GARP가 제대로 나가는지 검증
설정만 믿지 말고 실제 패킷을 확인해야 한다. 백업 노드를 마스터로 만든 뒤(마스터 keepalived 중지 또는 VRRP 차단) 스위치 미러 포트나 해당 노드에서 캡처한다.
# 페일오버 순간 GARP 캡처
tcpdump -i eth0 -n arp and 'ether[6:2] = 0xffff' -vv
# 옛 마스터 노드의 ARP 캐시 즉시 무효화(테스트용)
ip neigh flush all
ip neigh show 192.168.10.100
# 게이트웨이/클라이언트 캐시가 새 MAC으로 바뀌었는지 확인
arping -c 3 -I eth0 192.168.10.100
캡처에서 "who-has"가 아닌 ARP Reply(또는 announce)가 새 노드 MAC으로 브로드캐스트되면 정상이다. 매핑이 바뀌지 않으면 스위치 설정이나 네트워크 격리를 의심한다.
흔한 실패 원인
| 증상 | 원인 | 대응 |
|---|---|---|
| GARP는 보냈는데 트래픽 미복구 | 스위치 포트 보안/DAI가 GARP 드롭 | Dynamic ARP Inspection 예외 등록 |
| 클라우드(AWS/GCP)에서 무반응 | L2 브로드캐스트 미지원, GARP 무의미 | API로 VIP(보조 IP) 재할당 스크립트 사용 |
| 가끔만 복구됨 | GARP 패킷 유실 | repeat/refresh 증가 |
| 양쪽 다 마스터(스플릿브레인) | VRRP advert 차단, 방화벽 | 멀티캐스트 224.0.0.18 허용 |
특히 퍼블릭 클라우드는 물리 스위치와 달리 GARP 브로드캐스트가 라우팅되지 않는다. 이 경우 keepalived의 notify_master 훅에서 클라우드 API로 IP를 재바인딩해야 한다.
클라우드 환경 보완: notify 훅 활용
L2 GARP가 통하지 않는 환경에서는 승격 이벤트를 스크립트로 받아 제어 플레인에 직접 알린다.
vrrp_instance VI_1 {
# ... 생략 ...
notify_master "/etc/keepalived/on_master.sh"
}
#!/usr/bin/env bash
# on_master.sh — 승격 시 보조 IP 재할당(AWS 예시)
set -euo pipefail
ENI_ID="eni-0abc123"
VIP="192.168.10.100"
aws ec2 assign-private-ip-addresses \
--network-interface-id "$ENI_ID" \
--private-ip-addresses "$VIP" \
--allow-reassignment
logger -t keepalived "VIP $VIP reassigned to $ENI_ID"
주의점 정리
- 페일오버 검증은 반드시 외부 클라이언트 기준으로 한다. 노드 로컬 curl은 L2 문제를 못 잡는다.
garp_master_repeat를 과도하게 키우면 브로드캐스트 폭증으로 스위치에 부담을 준다. 5~10 수준이 무난하다.- DAI, 포트 보안, 방화벽이 ARP/VRRP를 막는지 먼저 확인한다. 설정보다 네트워크 정책이 원인인 경우가 많다.
- 클라우드에서는 GARP를 신뢰하지 말고 API 재할당을 기본으로 삼되, 훅 실패 시 알람을 남긴다.
핵심은 "VIP가 붙었다 ≠ 트래픽이 온다"는 점이다. 페일오버 설계에서 L3(IP)뿐 아니라 L2(MAC 학습·ARP 캐시)까지 갱신 경로를 함께 검증해야 실제 무중단에 가까워진다.