K8s Network
MetalLB는 Cloud가 아닌 환경에서 Loadbalancer를 사용할 수 있는 솔루션입니다.
L2 및 BGP 모드를 지원하고 있으며, 무료로 사용 가능합니다.
MetalLB는 왜 등장했을까요?
이유는 Service의 Loadbalancer 타입에 있습니다.
해당 타입을 사용하기 위해서는 반드시 CSP의 LB가 필요합니다.
클러스터의 외부와 통신하기 위해서는 LB가 없이도 Nodeport 타입을 설정하면 통신이 가능합니다.
그러나, Nodeport 타입을 사용하면 <Node IP>:<Nodeport>와 같이 IP에 Port를 붙혀야 정상적으로 시스템이 인식합니다.
동작 원리
MetalLB의 L2모드는 모드 명 처럼, 2계층 통신을 사용합니다. 클러스터에 구성 시, speaker라는 daemonset이 생성되며, 노드마다 배포된 파드는 LB의 외부IP(ExternalIP)를 2가지 방법을 통해 제어합니다.
GARP 프로토콜을 사용하여, 리더 speaker 파드를 실행하는 노드로 ExternalIP 패킷이 전송되도록 설정
==> 리더로 선출된 speaker 파드는 LB의 External IP를 관리하게 됩니다.

MetalLB에서 GARP 프로토콜 역할 흐름
어떻게 리더 speaker 파드를 실행하는 노드로 ExternalIP 패킷이 전송되도록 할 수 있는 것일까요?
해답은 GARP 프로토콜에 있습니다.
먼저, GARP 프로토콜은 자신의 IP가 네트워크 망에서 자기 IP에 해당하는 MAC 주소를 알리는 ARP Reply(ARP 프로토콜 방식)없이 브로드캐스트를 하는 것입니다.
<흐름 순서 정리>
1. 리더 speaker 파드가 External IP를 가짐
MetalLB & iptabels
MetalLB 또한 iptables를 활용합니다.
리더 speaker 파드가 실행되는 노드의 External IP로 패킷이 접근하면, 해당 노드의 iptables 규칙에 의해 각 노드의 파드로 분산되어 패킷이 전달됩니다.

L2 모드 단점
가장 큰 첫 번째 단점은 리더 speaker 파드를 가진 노드에 대한 부하도가 증가하는 것입니다.
GARP를 통해 모든 External IP로 접근하는 패킷을 리더 speaker 파드로 전달하기에, 당연한 수순입니다.
두 번째 단점은 가용성 부족입니다. 리더 speaker에 대한 장애 발생 시, 네트워크 순단이 생길 수 밖에 없는 구조이고, 새로운 리더가 선출되기 전까지 통신되지 않습니다.
실습을 위한 전제 조건이 있는데, VM을 클러스터링 맺은 경우 같은 서브넷 대역에 존재해야합니다.
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.12/config/manifests/metallb-native.yaml
# metallb-config.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: my-pool
namespace: metallb-system
spec:
addresses:
- 192.168.0.240-192.168.0.250 # 이 IP 대역은 클러스터 외부와 충돌 없어야 함
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: l2
namespace: metallb-system
spec: {}
# nginx-lb.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-lb
spec:
type: NodePort
selector:
app: nginx
ports:
- port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
kubectl get svc nginx-lb
