왜 컨트롤플레인 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 네트워크의 제약을 그대로 받으므로, 도입 전 스위치와 서브넷 구성을 먼저 확인하는 것이 안전하다.