MetalLB 설치 과정은 단순히
kubectl apply한 줄로 끝나지 않습니다. VMware Fusion DHCP 설정 변경, IPVS strictARP 확인, IP 풀 설정까지 여러 단계가 맞물려 있어 처음에는 어디서 막혔는지 파악하기도 쉽지 않습니다. 나중에 다시 설치할 때 같은 곳에서 헤매지 않으려고 전 과정을 기록해둡니다.
들어가며: 왜 MetalLB가 필요한가?
쿠버네티스에서 LoadBalancer 타입 서비스를 만들면 EXTERNAL-IP가 <pending> 상태로 멈춥니다.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEnginx-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 모드는 다루지 않습니다.
설치하기에 앞서
이 글의 실습 환경은 다음과 같습니다.
| 항목 | 내용 |
|---|---|
| 호스트 OS | macOS Apple Silicon(VMware Fusion) |
| 게스트 OS | Rocky Linux |
| MetalLB 버전 | v0.15.3 |
| 네트워크 | vmnet2 (10.10.10.0/24) |
사전 작업: VMware Fusion DHCP 충돌 방지
MetalLB를 바로 설치하기 전에 VMware Fusion DHCP와의 IP 충돌을 막아야 합니다.
왜 충돌이 생기는가?
두 주체가 같은 IP 대역에 다른 방식으로 접근합니다.
| VMware DHCP | MetalLB | |
|---|---|---|
| 역할 | 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 설정 파일을 직접 수정해야 합니다.
vi "/Library/Preferences/VMware Fusion/vmnet2/dhcpd.conf"10.10.10.0 서브넷을 찾아 range 끝을 239로 변경합니다.
# 변경 전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을 재시작해야 반영됩니다.
sudo "/Applications/VMware Fusion.app/Contents/Library/vmnet-cli" --stopsudo "/Applications/VMware Fusion.app/Contents/Library/vmnet-cli" --startIP 대역 사용 여부 확인
MetalLB에 할당할 IP 대역이 이미 사용 중인지 확인합니다.
# -sn: 포트 스캔 없이 호스트 활성화 여부만 확인 (Ping Scan)nmap -sn 10.10.10.240-250
위와 같이 아무것도 표시되지 않으면 사용가능한 상태입니다.
Starting Nmap 7.92 ( https://nmap.org ) at 2026-04-08 04:35 KSTNmap done: 11 IP addresses (0 hosts up) scanned in 1.56 seconds만약 이미 있다면 사용중인 IP가 표시됩니다.
Starting Nmap 7.92 ( https://nmap.org ) at 2026-04-08 04:34 KSTNmap scan report for 10.10.10.240Host is up.Nmap scan report for 10.10.10.241Host is up.Nmap done: 11 IP addresses (2 hosts up) scanned in 1.58 secondsMetalLB 설치
1. IPVS strictARP 확인
실습 환경은 kube-proxy를 IPVS 모드로 구성했습니다. 이 경우 strictARP를 true로 설정해야 합니다.
IPVS 모드는 서비스 IP들을 가상 인터페이스(
kube-ipvs0)에 등록하는데, Linux 기본 동작은 어느 인터페이스로 ARP가 들어오든 자신이 아는 IP면 다 응답합니다.strictARP=true는 이를 막아서 MetalLB speaker가 LoadBalancer IP의 ARP 응답을 독점할 수 있게 합니다.
kubectl get configmap kube-proxy -n kube-system -o yaml | grep strictARPfalse라면 직접 수정합니다.
kubectl edit configmap -n kube-system kube-proxy# 아래 두 값을 확인/수정strictARP: truemode: "ipvs"2. MetalLB 설치
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.3/config/manifests/metallb-native.yaml3. ipvsadm 설치
모든 클러스터 노드에 ipvsadm을 설치합니다.
dnf -y install ipvsadm4. 설치 확인
MetalLB는 설치 시 metallb-system 네임스페이스를 자동으로 생성하고 모든 구성 요소를 그 안에 배포합니다. 컨트롤러와 스피커 파드가 모두 Running 상태인지 확인합니다.
kubectl get all -o wide -n metallb-systemNAME READY STATUS RESTARTS AGEpod/controller-cd8c9874-nbqfh 1/1 Running 0 31mpod/speaker-cxrl2 1/1 Running 0 29m # node1pod/speaker-k5gl8 1/1 Running 0 31m # controllerpod/speaker-qlcgn 1/1 Running 0 29m # node2speaker는 DaemonSet으로 배포되어 모든 노드에 하나씩 올라갑니다.
MetalLB 배포 설정
MetalLB가 사용할 IP 풀과 L2 광고 설정을 YAML로 정의합니다.
# metallb.yaml
# LoadBalancer가 사용할 IP 주소 대역apiVersion: metallb.io/v1beta1kind: IPAddressPoolmetadata: name: first-pool namespace: metallb-systemspec: addresses: # 이번에 사용할 IP 대역 - 10.10.10.240-10.10.10.250---# IP가 L2(ARP)에서 응답할 수 있도록 설정apiVersion: metallb.io/v1beta1kind: L2Advertisementmetadata: name: default namespace: metallb-systemspec: ipAddressPools: - first-poolkubectl apply -f metallb.yaml적용하면 <pending> 상태였던 서비스에 EXTERNAL-IP가 할당됩니다.
# 변경 전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를 응답 본문에 포함하기 때문에 로드밸런싱 확인에 적합합니다.
# nginx-hello.yaml
apiVersion: apps/v1kind: Deploymentmetadata: name: nginx-hello namespace: default labels: app: nginxspec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginxdemos/hellokubectl apply -f nginx-hello.yamlkubectl get podsNAME READY STATUS RESTARTS AGEnginx-hello-64d8c497c8-ckwkw 1/1 Running 0 23mnginx-hello-64d8c497c8-kztvm 1/1 Running 0 51snginx-hello-64d8c497c8-wvzgk 1/1 Running 0 51sLoadBalancer 타입 서비스를 배포합니다. MetalLB가 이 서비스를 감지하고 IP 풀에서 주소를 할당합니다.
# nginx-loadbalancer.yaml
apiVersion: v1kind: Servicemetadata: name: nginx-loadbalancerspec:# IP 부여 방식을 LoadBalancer로 지정 type: LoadBalancer selector:# Deployment 이름인 nginx와 연동 app: nginx ports:# 포트가 사용하는 프로토콜 - protocol: TCP port: 80 # 내부 포트(서비스 포트 번호가 여러개일 때) targetPort: 80 kubectl apply -f nginx-loadbalancer.yamlLoadBalancer에 할당된 EXTERNAL-IP인 10.10.10.240으로 curl을 여러 번 호출하면 매번 다른 파드로 연결됩니다.
curl 10.10.10.240 | grep ServerServer name은 요청이 전달된 파드의 이름입니다. 호출할 때마다 다른 파드 이름이 나오면 로드밸런싱이 정상 동작하는 것입니다.
# 첫 번째 요청<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 + L2Advertisement | kubectl apply -f metallb.yaml |
| 확인 | 네임스페이스 상태 확인 | kubectl get all -n metallb-system |
VMware Fusion DHCP와의 IP 충돌만 주의하면 MetalLB 설치 자체는 간단합니다. 이제 <pending> 상태로 멈춰있던 EXTERNAL-IP에 실제 IP가 할당되고, LoadBalancer 타입 서비스를 활용한 실습을 본격적으로 진행할 수 있는 환경이 마련되었습니다.