왜 컨트롤플레인 VIP가 필요한가

온프레미스나 베어메탈에 kubeadm으로 클러스터를 올리면 API 서버 엔드포인트가 문제가 된다. 컨트롤플레인이 3대라도 kubeconfig와 kubelet은 하나의 주소만 바라봐야 한다. 특정 노드 IP를 직접 쓰면 그 노드가 죽는 순간 클러스터 전체가 API 접근 불능이 된다. 클라우드라면 로드밸런서를 붙이면 되지만, LB가 없는 환경에서는 별도의 가상 IP(VIP)와 그 VIP를 살아있는 노드로 옮겨줄 장치가 필요하다.

전통적으로는 keepalived(VRRP) + HAProxy 조합을 썼다. 하지만 데몬 두 개를 별도 패키지로 관리하고, 설정 파일을 노드마다 동기화해야 하는 부담이 있다. kube-vip는 이 역할을 스태틱 파드 하나로 대체한다.

kube-vip의 동작 방식

kube-vip는 컨트롤플레인 노드에서 스태틱 파드로 실행되며 두 가지 모드를 제공한다. VIP를 어느 노드가 소유할지 정하는 리더 선출은 ARP 모드(레이어2, 리더가 gratuitous ARP로 VIP 소유권 광고)와 BGP 모드(업스트림 라우터에 경로 광고) 중 선택한다. 소규모 온프레미스는 ARP가 단순해서 무난하고, 여러 서브넷·ToR 스위치 환경은 BGP가 적합하다.

항목ARP 모드BGP 모드
네트워크 요건동일 L2 세그먼트BGP 피어(라우터) 필요
장애 전환gratuitous ARP 재광고경로 재수렴
멀티서브넷불가가능
설정 난이도낮음중간

매니페스트 생성

kube-vip 컨테이너 자체로 스태틱 파드 매니페스트를 뽑아낸다. 첫 컨트롤플레인 노드에서 kubeadm init 전에 실행해 /etc/kubernetes/manifests에 배치한다.

export VIP=192.168.10.100
export INTERFACE=eth0
export KVVERSION=v0.8.0

# 컨트롤플레인 VIP용 스태틱 파드 매니페스트 생성 (ARP 모드)
ctr image pull ghcr.io/kube-vip/kube-vip:$KVVERSION

ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip \
  /kube-vip manifest pod \
  --interface $INTERFACE \
  --address $VIP \
  --controlplane \
  --arp \
  --leaderElection > /etc/kubernetes/manifests/kube-vip.yaml

kubeadm과 연동하기

핵심은 controlPlaneEndpoint를 실제 노드 IP가 아니라 VIP로 지정하는 것이다. 이렇게 해야 이후 조인하는 노드와 kubeconfig가 모두 VIP를 바라본다.

apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.30.0
controlPlaneEndpoint: "192.168.10.100:6443"
apiServer:
  certSANs:
    - "192.168.10.100"   # VIP를 인증서 SAN에 반드시 포함
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 192.168.10.11   # 이 노드의 실제 IP
  bindPort: 6443

이 파일로 kubeadm init --config kubeadm.yaml --upload-certs를 실행한 뒤, 나머지 컨트롤플레인은 출력된 join 명령에 --control-plane을 붙여 합류시킨다. 조인 노드에도 같은 방식으로 kube-vip 매니페스트를 넣어준다.

동작 확인

리더 노드에 VIP가 붙었는지, 장애 시 다른 노드로 넘어가는지 확인한다.

# 현재 VIP를 소유한 노드에서만 주소가 보인다
ip addr show eth0 | grep 192.168.10.100

# 리더 선출 로그 확인
kubectl -n kube-system logs -l name=kube-vip-ds --tail=20

# 리더 노드를 재부팅한 뒤, 다른 노드에서 VIP 인계 확인
watch -n1 'kubectl get nodes'

실무에서 자주 겪는 함정

몇 가지 주의점을 정리한다.

  • certSAN 누락: VIP를 SAN에 넣지 않으면 VIP로 접속할 때 TLS 인증서 오류가 난다. 이미 init한 뒤라면 인증서를 재발급해야 해서 번거롭다.
  • 인터페이스 이름: 노드마다 NIC 이름이 다르면 매니페스트를 노드별로 맞춰야 한다. predictable name(ens192 등)을 확인하자.
  • ARP와 클라우드 네트워크: gratuitous ARP를 차단하거나 MAC 학습을 제한하는 스위치·클라우드 환경에서는 ARP 모드가 동작하지 않는다. 이때는 BGP 모드나 별도 LB를 검토한다.
  • 워커 노드 접근: kube-vip는 컨트롤플레인 VIP만 담당한다. 서비스용 LoadBalancer가 필요하면 kube-vip의 서비스 모드나 MetalLB를 별도로 구성한다.

keepalived처럼 별도 데몬을 관리하지 않고 클러스터 생명주기 안에서 VIP를 다룰 수 있다는 점이 kube-vip의 실질적 이점이다. 다만 VIP는 L2/L3 네트워크의 제약을 그대로 받으므로, 도입 전 스위치와 서브넷 구성을 먼저 확인하는 것이 안전하다.