2014년산 Mac Mini (솔로몬) 의 내장 WiFi 가 무작위로 끊겨서 K3s 노드가 NotReady 되는 일이 반복됐습니다. WiFi 동글 2 개 추가 (AX900 / A3000UA) + 자체 bash watchdog 로 192.168.219.108 floating VIP 페일오버 구현. keepalived 가 단일 호스트 다중 NIC 시나리오에 맞지 않아서 직접 만든 기록입니다.

이 글에서 다루는 것

  • 왜 keepalived 가 안 맞는가
  • bash watchdog + systemd 30 줄로 충분한 이유
  • 실제 페일오버 동작 검증 (disconnect/reconnect)
  • K3s 의 한계 — node-IP 는 여전히 single point
  • 진짜로 막은 것 vs 못 막은 것

1. 문제 — WiFi 무작위 단절

$ kubectl get nodes
solomon   NotReady   <none>   2d

조사:

  • 솔로몬: 2014 Mac Mini, 내장 WiFi 만 (유선 포트 없음)
  • 평균 RTT: 110ms (정상), 가끔 끊김
  • 단절 시 etcd VXLAN endpoint 잃음 → flannel 페일

2. 하드웨어 보강 — WiFi 동글 2 종

인터페이스 드라이버 칩셋 제품
wlp3s0b1 내장 Broadcom 2014 Mac Mini
wlxb0386cf8d710 rtw89_8851bu RTL8851BU ipTime AX900 Mini (WiFi 6)
wlxb0386cf4af80 rtw88_8822bu RTL8822BU ipTime A3000UA (WiFi 5)

USB 동글 2 개 다 꽂아도 둘 다 state DOWN — NetworkManager 연결 안 함. 직접 연결:

sudo nmcli device wifi connect "lms" password "xxx" \
  ifname wlxb0386cf8d710 name lms-ax900
sudo nmcli device wifi connect "sky" password "xxx" \
  ifname wlxb0386cf4af80 name sky-a3000ua

다른 SSID 로 분산 (lms 2.4G, sky 5G) → 한 AP 장애 시 다른 쪽 살아남음.

NetworkManager 강성 설정:

sudo nmcli connection modify lms \
  connection.autoconnect yes \
  connection.autoconnect-retries 0 \
  802-11-wireless.powersave 2     # disable

3. K3s 의 진짜 문제 — 3-NIC 이 도움 안 됨

3 IP 가 있어도:

트래픽 종류 영향
아웃바운드 (솔로몬 → 외부) ✅ 페일오버
인바운드 control-plane ❌ K3s 는 한 노드 IP 만 알아봄
flannel VXLAN endpoint ❌ 다른 노드 cache 에 .108 만 등록

192.168.219.108 이라는 IP 가 죽으면 NIC 가 살아도 K3s 는 죽음.

해결: floating VIP. .108 이 어떤 NIC 에 있든 무관하게 살아있어야 함.

4. 왜 keepalived 안 쓰나

VRRP 의 일반적 시나리오:

host1 (master, .108)  ←→  host2 (backup)
   eth0                       eth0

내 시나리오:

host1 (solomon)
├─ wlp3s0b1   .108?
├─ wlxb...    .108?  ← 이게 되어야 함
└─ wlxb...    .108?

단일 호스트의 다중 NIC 사이 IP 페일오버는 VRRP 가 의도한 게 아님. track_interface + notify_script 로 우회 가능하지만 의외로 복잡. bash 30 줄이 깔끔.

5. 자체 watchdog — 30 줄

#!/bin/bash
# /usr/local/sbin/vip-failover.sh
set -u
VIP="192.168.219.108"
NETMASK="24"
PRIORITY_NICS=("wlp3s0b1" "wlxb0386cf8d710" "wlxb0386cf4af80")

pick_active() {
  for nic in "${PRIORITY_NICS[@]}"; do
    [ -d "/sys/class/net/$nic" ] || continue
    [ "$(cat /sys/class/net/$nic/operstate)" = "up" ] || continue
    [ "$(cat /sys/class/net/$nic/carrier)" = "1" ] || continue
    echo "$nic"; return 0
  done
  return 1
}

has_vip() { ip -4 addr show "$1" 2>/dev/null | grep -q "inet ${VIP}/"; }

while true; do
  active=$(pick_active) || { sleep 2; continue; }

  if has_vip "$active"; then
    # 중복 제거
    for nic in "${PRIORITY_NICS[@]}"; do
      [ "$nic" != "$active" ] && has_vip "$nic" && \
        ip addr del "${VIP}/${NETMASK}" dev "$nic" 2>/dev/null
    done
  else
    # 모든 NIC 에서 떼고 active 에 붙임
    for nic in "${PRIORITY_NICS[@]}"; do
      ip addr del "${VIP}/${NETMASK}" dev "$nic" 2>/dev/null || true
    done
    ip addr add "${VIP}/${NETMASK}" dev "$active"
    arping -c 3 -I "$active" -U "${VIP}"   # gratuitous ARP
  fi
  sleep 2
done

systemd:

[Service]
Type=simple
ExecStart=/usr/local/sbin/vip-failover.sh
Restart=always
RestartSec=5s

6. 실제 페일오버 테스트

# 정상 상태
$ ip -4 -br addr | grep wl
wlp3s0b1        UP    192.168.219.108/24    ← VIP
wlxb0386cf8d710 UP    192.168.219.112/24
wlxb0386cf4af80 UP    192.168.219.113/24

# 의도적 단절
$ sudo nmcli device disconnect wlp3s0b1
Device 'wlp3s0b1' successfully disconnected.

# 5 초 후 (watchdog 자동 동작)
$ ip -4 -br addr | grep wl
wlxb0386cf8d710 UP    192.168.219.112/24 192.168.219.108/24   ★ VIP 이동
wlxb0386cf4af80 UP    192.168.219.113/24

$ kubectl get node solomon
solomon   Ready   <none>   2d    ← NotReady 안 됨

# 재연결
$ sudo nmcli connection up lms
# 5 초 후
$ ip -4 -br addr | grep wl
wlp3s0b1        UP    192.168.219.108/24 192.168.219.114/24  ★ 복귀
wlxb0386cf8d710 UP    192.168.219.112/24
wlxb0386cf4af80 UP    192.168.219.113/24

복귀 시 DHCP 가 새 IP (.114) 도 줘서 듀얼 IP 가 되는데 기능엔 무관. K3s 는 .108 만 보면 되고, .108 이 살아있음.

7. 진짜로 막은 것

  • ✅ WiFi 카드 1 개 죽어도 노드는 Ready
  • ✅ 페일오버 동안 K3s control-plane 통신 끊김 없음 (gratuitous ARP 로 스위치 ARP table 즉시 갱신)
  • ✅ etcd 멤버 (이 노드가 마스터일 때) 도 무중단
  • ✅ 외부 도메인 200 OK 유지

8. 못 막은 것 (한계)

  • ❌ 라우터(공유기) 가 죽으면 셋 다 끊김 (당연)
  • ❌ 솔로몬 OS 자체가 죽으면 (kernel panic, 디스크 fail) 어떤 NIC 도 무의미
  • ❌ 솔로몬 host 의 SSD 가 죽으면 PVC 다 손실 (백업 별건)

이건 결국 노드 단일점. control-plane 3-master HA + PVC 다른 노드 분산이 진짜 답.

9. 부가 효과 — 솔로몬을 etcd 멤버로 승격 가능

floating VIP 가 있으니 솔로몬도 안정적인 IP 를 가짐 → K3s 3-master 의 멤버로 합류 가능.

$ kubectl get nodes
solomon   Ready   control-plane,etcd   2d3h   ★ 마스터 승격

다음 글 K3s 3-Master HA 마이그레이션 에서 이어집니다.


10. 정리 — over-engineering 안 한 것의 가치

시도한 것 결과
keepalived 단일 호스트 다중 NIC 시도 30 분 헛소동, 적합하지 않음
bash watchdog 30 줄 검증 통과, 1 시간
systemd autoConnect + powersave off 보조 안정성

툴이 시나리오에 맞는지 먼저 확인. 표준 솔루션이 항상 답은 아닙니다.