MetalLB 설치 과정은 단순히 kubectl apply 한 줄로 끝나지 않습니다. VMware Fusion DHCP 설정 변경, IPVS strictARP 확인, IP 풀 설정까지 여러 단계가 맞물려 있어 처음에는 어디서 막혔는지 파악하기도 쉽지 않습니다. 나중에 다시 설치할 때 같은 곳에서 헤매지 않으려고 전 과정을 기록해둡니다.

들어가며: 왜 MetalLB가 필요한가?

쿠버네티스에서 LoadBalancer 타입 서비스를 만들면 EXTERNAL-IP<pending> 상태로 멈춥니다.

Plain Text
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-loadbalancer LoadBalancer 10.101.16.141 <pending> 80:32534/TCP 5m

클라우드 환경(AWS, GCP 등)에서는 클라우드 프로바이더가 자동으로 IP를 할당해주지만, Mac의 VMware Fusion 위에 구성한 실습 환경에서는 IP를 할당해줄 주체가 없기 때문입니다.

MetalLB 는 이 역할을 대신합니다. 베어메탈 쿠버네티스 클러스터에서 LoadBalancer 타입 서비스를 사용할 수 있도록 표준 라우팅 프로토콜(ARP/BGP)을 이용해 외부 IP를 광고해주는 로드밸런서 구현체입니다. 지정한 IP 풀에서 IP를 선택해 서비스에 할당하고, 해당 IP에 대한 ARP 응답을 직접 수행합니다.

이 글에서는 Layer 2(ARP) 모드로 설치합니다. BGP 모드는 다루지 않습니다.


설치하기에 앞서

이 글의 실습 환경은 다음과 같습니다.

항목내용
호스트 OSmacOS Apple Silicon(VMware Fusion)
게스트 OSRocky Linux
MetalLB 버전v0.15.3
네트워크vmnet2 (10.10.10.0/24)

사전 작업: VMware Fusion DHCP 충돌 방지

MetalLB를 바로 설치하기 전에 VMware Fusion DHCP와의 IP 충돌을 막아야 합니다.

왜 충돌이 생기는가?

두 주체가 같은 IP 대역에 다른 방식으로 접근합니다.

VMware DHCPMetalLB
역할VM 부팅 시 IP 자동 할당서비스에 IP 선점 후 광고(announce)
동작 방식L3 (IP 계층)Layer 2 (ARP) 또는 BGP
IP 관리중앙 DHCP 서버가 동적 분배미리 정의된 IP Pool에서 선택

MetalLB가 10.10.10.240을 선점하고 ARP 응답을 시작했는데, VMware Fusion DHCP가 같은 IP를 다른 VM에 할당하면 충돌이 발생합니다.

DHCP 범위 줄이기

실습 환경에서 VMware의 vmnet2 서브넷을 10.10.10.0/24로 구성했습니다. MetalLB에는 이 대역 중 240-250 구간을 IP 풀로 할당할 예정이므로, VMware DHCP가 해당 구간에 IP를 나눠주지 않도록 범위를 먼저 줄입니다.

Windows의 VMware Workstation은 GUI 메뉴(Virtual Network Editor)에서 DHCP 범위를 직접 수정할 수 있지만, Mac의 VMware Fusion은 이 메뉴가 없습니다. 대신 dhcpd.conf 설정 파일을 직접 수정해야 합니다.

Terminal
vi "/Library/Preferences/VMware Fusion/vmnet2/dhcpd.conf"

10.10.10.0 서브넷을 찾아 range 끝을 239로 변경합니다.

Config
# 변경 전
subnet 10.10.10.0 netmask 255.255.255.0 {
range 10.10.10.128 10.10.10.254;
option routers 10.10.10.2;
}
# 변경 후
subnet 10.10.10.0 netmask 255.255.255.0 {
range 10.10.10.128 10.10.10.239;
option routers 10.10.10.2;
}

변경 후 vmnet을 재시작해야 반영됩니다.

Terminal
sudo "/Applications/VMware Fusion.app/Contents/Library/vmnet-cli" --stop
sudo "/Applications/VMware Fusion.app/Contents/Library/vmnet-cli" --start

IP 대역 사용 여부 확인

MetalLB에 할당할 IP 대역이 이미 사용 중인지 확인합니다.

Terminal
# -sn: 포트 스캔 없이 호스트 활성화 여부만 확인 (Ping Scan)
nmap -sn 10.10.10.240-250

위와 같이 아무것도 표시되지 않으면 사용가능한 상태입니다.

Plain Text
Starting Nmap 7.92 ( https://nmap.org ) at 2026-04-08 04:35 KST
Nmap done: 11 IP addresses (0 hosts up) scanned in 1.56 seconds

만약 이미 있다면 사용중인 IP가 표시됩니다.

Plain Text
Starting Nmap 7.92 ( https://nmap.org ) at 2026-04-08 04:34 KST
Nmap scan report for 10.10.10.240
Host is up.
Nmap scan report for 10.10.10.241
Host is up.
Nmap done: 11 IP addresses (2 hosts up) scanned in 1.58 seconds

MetalLB 설치

1. IPVS strictARP 확인

실습 환경은 kube-proxy를 IPVS 모드로 구성했습니다. 이 경우 strictARPtrue로 설정해야 합니다.

IPVS 모드는 서비스 IP들을 가상 인터페이스(kube-ipvs0)에 등록하는데, Linux 기본 동작은 어느 인터페이스로 ARP가 들어오든 자신이 아는 IP면 다 응답합니다. strictARP=true는 이를 막아서 MetalLB speaker가 LoadBalancer IP의 ARP 응답을 독점할 수 있게 합니다.

Terminal
kubectl get configmap kube-proxy -n kube-system -o yaml | grep strictARP

false라면 직접 수정합니다.

Terminal
kubectl edit configmap -n kube-system kube-proxy
YAML
# 아래 두 값을 확인/수정
strictARP: true
mode: "ipvs"

2. MetalLB 설치

Terminal
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.3/config/manifests/metallb-native.yaml

3. ipvsadm 설치

모든 클러스터 노드에 ipvsadm을 설치합니다.

Terminal
dnf -y install ipvsadm

4. 설치 확인

MetalLB는 설치 시 metallb-system 네임스페이스를 자동으로 생성하고 모든 구성 요소를 그 안에 배포합니다. 컨트롤러와 스피커 파드가 모두 Running 상태인지 확인합니다.

Terminal
kubectl get all -o wide -n metallb-system
Plain Text
NAME READY STATUS RESTARTS AGE
pod/controller-cd8c9874-nbqfh 1/1 Running 0 31m
pod/speaker-cxrl2 1/1 Running 0 29m # node1
pod/speaker-k5gl8 1/1 Running 0 31m # controller
pod/speaker-qlcgn 1/1 Running 0 29m # node2

speaker는 DaemonSet으로 배포되어 모든 노드에 하나씩 올라갑니다.


MetalLB 배포 설정

MetalLB가 사용할 IP 풀과 L2 광고 설정을 YAML로 정의합니다.

YAML
# metallb.yaml
# LoadBalancer가 사용할 IP 주소 대역
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
# 이번에 사용할 IP 대역
- 10.10.10.240-10.10.10.250
---
# IP가 L2(ARP)에서 응답할 수 있도록 설정
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default
namespace: metallb-system
spec:
ipAddressPools:
- first-pool
Terminal
kubectl apply -f metallb.yaml

적용하면 <pending> 상태였던 서비스에 EXTERNAL-IP가 할당됩니다.

Plain Text
# 변경 전
nginx-loadbalancer LoadBalancer 10.101.16.141 <pending> 80:32534/TCP 19m
# 변경 후
nginx-loadbalancer LoadBalancer 10.101.16.141 10.10.10.240 80:32534/TCP 21m

동작 확인

로드밸런싱 테스트

테스트용 nginx deployment를 배포합니다. nginxdemos/hello 이미지는 요청을 받은 파드의 이름과 IP를 응답 본문에 포함하기 때문에 로드밸런싱 확인에 적합합니다.

YAML
# nginx-hello.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-hello
namespace: default
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginxdemos/hello
Terminal
kubectl apply -f nginx-hello.yaml
kubectl get pods
Plain Text
NAME READY STATUS RESTARTS AGE
nginx-hello-64d8c497c8-ckwkw 1/1 Running 0 23m
nginx-hello-64d8c497c8-kztvm 1/1 Running 0 51s
nginx-hello-64d8c497c8-wvzgk 1/1 Running 0 51s

LoadBalancer 타입 서비스를 배포합니다. MetalLB가 이 서비스를 감지하고 IP 풀에서 주소를 할당합니다.

YAML
# nginx-loadbalancer.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-loadbalancer
spec:
# IP 부여 방식을 LoadBalancer로 지정
type: LoadBalancer
selector:
# Deployment 이름인 nginx와 연동
app: nginx
ports:
# 포트가 사용하는 프로토콜
- protocol: TCP
port: 80
# 내부 포트(서비스 포트 번호가 여러개일 때)
targetPort: 80
Terminal
kubectl apply -f nginx-loadbalancer.yaml

LoadBalancer에 할당된 EXTERNAL-IP인 10.10.10.240으로 curl을 여러 번 호출하면 매번 다른 파드로 연결됩니다.

Terminal
curl 10.10.10.240 | grep Server

Server name은 요청이 전달된 파드의 이름입니다. 호출할 때마다 다른 파드 이름이 나오면 로드밸런싱이 정상 동작하는 것입니다.

Plain Text
# 첫 번째 요청
<p><span>Server name:</span> <span>nginx-hello-64d8c497c8-wvzgk</span></p>
# 두 번째 요청
<p><span>Server name:</span> <span>nginx-hello-64d8c497c8-ckwkw</span></p>

정리

단계작업명령어/파일
사전VMware DHCP 범위 축소dhcpd.conf range 수정 → vmnet 재시작
사전대역 사용 여부 확인nmap -sn 10.10.10.240-250
사전IPVS strictARP 설정kubectl edit configmap kube-proxy -n kube-system
설치MetalLB 설치kubectl apply -f metallb-native.yaml
설정IP Pool + L2Advertisementkubectl apply -f metallb.yaml
확인네임스페이스 상태 확인kubectl get all -n metallb-system

VMware Fusion DHCP와의 IP 충돌만 주의하면 MetalLB 설치 자체는 간단합니다. 이제 <pending> 상태로 멈춰있던 EXTERNAL-IP에 실제 IP가 할당되고, LoadBalancer 타입 서비스를 활용한 실습을 본격적으로 진행할 수 있는 환경이 마련되었습니다.