Kubernetes

Kubernetes - MetalLB

rygus 2025. 10. 12. 19:10
728x90

안녕하세요.

오늘은 MetalLB에 대해 알아보겠습니다. 

 

저희는 앞서 쿠버네티스 서비스에 대해 알아보았는데요.  Kubernetes - 서비스란?

그중 Load Balancer 타입에 대해서 알아보았습니다. 

 

공식 문서에서도 알 수 있듯이 `loadbalancer` 타입은 클라우드 공급자의 로드밸런서를 필요로 합니다. 

Azure, AWS 같은 클라우드 환경에서는 `loadbalancer` 타입의 서비스를 생성하면 클라우드가 자동으로 로드 밸런서 인스턴스(예: aws의 NLB, azure의 LB)를 만들어 트래픽을 분산시켜 줍니다. 

 

하지만 온프레미스 환경에서는 이런 기능은 자동으로 제공되지 않습니다. 

이때 Metal LB를 사용하면, 클라우드 처럼 별도의 로드 밸런서 서버를 만들지 않아도 

외부에서 접근 가능한 로드 밸런서처럼 동작할 수 있습니다.

즉, 온프레미스 환경에서도 `loadbalancer` 타입 서비스를 그대로 사용할 수 있게 해 줍니다. 

 

# Metal LB 란?

Metal LB는 Layer2 모드와 BGP 모드 두 가지를 지원합니다. 

Layer 2 모드

Metal LB를 배포하면 spearker 파드가 데몬셋형태로 각 노드에 배포됩니다. 

 

이렇게 배포된 speaker 파드는 리더를 선출하고 리더 파드는 각 노드에서 "External IP를 내가 가지고 있어!"라고 네트워크에 알리는 역할을 합니다. 

그래서 외부에서 서비스를 접근하면 이 IP를 소유한 노드로 트래픽이 전달됩니다.

(*참고로 리더 파드가 죽으면 다른 파드가 리더로 선출되어 리더 역할을 하게 됩니다.)

 

Layer 2 모드는 말 그대로 OSI 7계층에서 2번째 계층인 Datalink 계층에서 작동하는 모드로 같은 LAN 대역의 호스트만 접근이 가능합니다. 

(* 같은 LAN 대역은 브로드 캐스트가 전달되는 대역을 뜻합니다.)

 

같은 LAN 대역에서는 IP를 통해서 통신하지 않습니다. 

MAC Address를 통해서 통신을 주고받는데요.

즉, 장비의 물리적 주소를 통해서 데이터를 주고받습니다. 

이때 IP를 통해서 MAC Address를 알아내는 프로토콜을 ARP라고 합니다. 

이 방식을 이용한 방법이 Layer 2 모드입니다.

 

앞서 말씀드린 대로 speaker pod의 리더를 선출하고 리더는 자신이 External IP를 가지고 있다고 광고한다고 했습니다. 

이 광고하는 방식이 Layer2냐 BGP 모드냐에 따라 달라지는데요. 

 

Layer2의 경우 리더 speaker 파드는 해당 External IP 주소에 대해 GARP(Gratuitous ARP) 패킷을 네트워크에 브로드캐스트해 자신이 이 IP의 소유자임을 알립니다. 

이것은 같은 브로드캐스트 대역 내 네트워크 장비들이 해당 IP의 MAC 주소를 리더 노드의 MAC으로 인식하도록 하는 동작입니다.

 

이렇게 말하면 이해가 안 될 것이기에 그림으로 설명드리겠습니다. 

요청자가 최초로 쿠버네티스의 `loadbalancer`의 external ip를 호출하였을 때 누가 external ip를 갖고 있는지 알 수가 없기 때문에 ARP Broadcast를 발생시켜 나머지 노드들에게 "external ip를 갖고 있는 게 누구야? 있으면 MAC 주소 좀 알려줘" 라는 통신을 발생시킵니다.

(* ARP는 IP 주소로 MAC 주소를 알아내는 프로토콜입니다.)

여기서 리더 speaker pod 노드를 제외한 나머지 노드들은 해당 요청을 무시하고 리더 speaker pod 노드는 이에 응답을 합니다. 

리더 speaker pod 노드는 "어 그 external ip는 내가 갖고 있어" 라고 unicast를 통해서 응답하게 됩니다. 

그러면 이제 요청자는 external ip의 mac 주소를 알았으니 그 후로는 정상적으로 통신이 가능하게 됩니다. 

 

위 사진은 리더 speaker pod 노드가 ARP 10.0.0.20(external ip) 요청을 받고 자신의 mac 주소를 알려주는 로그입니다. 

 

이제  리더 speaker pod에 도착한 트래픽을 kube-porxy에서 알맞은 서비스에 포워딩함으로써 정상적으로 통신이 가능하게 됩니다. 

위와 같이 Layer 2 모드는 ARP Broadcast 방식을 이용하기 때문에 같은 LAN 대역의 호스트에서 밖에 호출이 되지 않는 것입니다.

이러한 Layer 2 모드의 단점은 모든 호출을 리더 speaker pod 노드에서 처리하기 때문에 비효율적입니다. 

그리고 리더 speaker pod가 죽으면 다음 리더를 선출할 때까지 다운 타임이 발생되게 되어 다운 타임이 길어진다는 단점도 있습니다.

그래서 실제 서비스 환경에서는 BGP 모드를 사용하는 것을 권장하고 있습니다.

 

BGP 모드

Layer2 모드가 같은 LAN에서만 사용가능했다면 BGP 모드는 다른 LAN 대역에서도 사용이 가능합니다. 

BGP 모드 말 그대로 BGP를 이용하는 것인데요. 

 

MetalLB의 BGP 모드는 쿠버네티스 클러스터 외부의 라우터와 BGP(Border Gateway Protocol) 세션을 맺어, External IP 주소 대역을 라우팅 테이블에 직접 광고하는 방식입니다.

따로 리더는 선출하지 않고 모든 노드를 라우터에 등록하는 것입니다.

 

위 그림과 같이 라우터의 테이블에는 External IP에는 모든 노드가 등록되어 있습니다. 

 

이제 외부에서 요청자가 해당 external ip를 요청해도 라우터는 해당 external ip의 위치를 알고 있기 때문에 정상적으로 통신이 가능하게 됩니다.

여기서 라우터는 ECMP를 이용하여 균등하게 분배를 하게 됩니다. 

(* ECMP (Equal-Cost Multi-Path)는 네트워크에서 동일한 비용(메트릭)을 가진 여러 경로를 통해 패킷을 분산 전송하는 라우팅 기술)

그래서 Layer 2 모드와는 다르게 균등한 분배가 가능하게 됩니다. 

그렇기 때문에 BGP 모드에서는 따로 리더 파드를 선출하지 않습니다.

그리고 만약 특정 스피커 파드가 죽는다고 해도 라우터는 해당 노드로 트래픽을 안보내면 되기 때문에 다운타임도 굉장히 짧다는 장점이 있습니다. 

 

# 실습

실습은 Layer 2 모드로 진행하겠습니다. 

 

본격적으로 metal lb를 구성하기 전 strictARP 모드를 사용해야 합니다. 

strictARP 모드를 사용하면 노드의 네트워크 인터페이스는 자신에게 할당된 IP 주소에 대해서만 ARP 응답을 보내도록 제한되게 합니다.

현재는 false이므로 이를 true로 바꿔줘야 합니다.

 

# true로 변경
kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e "s/strictARP: false/strictARP: true/" | kubectl apply -f - -n kube-system

# 확인
kubectl get configmap kube-proxy -n kube-system -o yaml | grep strictARP

 

이제 Helm을 통해 metallb를 설치해어야 하는데요. 

그전에 Helm을 먼저 설치하겠습니다.

# Helm 스크립트 설치
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3

# 스크립트에 실행 권한 부여
chmod 700 get_helm.sh

# Helm 설치
./get_helm.sh

# Helm 버전 확인
helm version

 

이제 metallb를 설치하겠습니다. 

 

# repository 추가
helm repo add metallb https://metallb.github.io/metallb

# repolisitory 업데이트
helm repo update

# metallb 설치
helm pull metallb/metallb

설치가 완료되었으면 현재 디렉터리에 압축 파일 하나가 다운로드되어 있습니다. 

압축을 해제하겠습니다. 

tar xvfz metallb-0.15.2.tgz

 

이제 metallb라는 디렉터리가 하나 생성되었을 텐데요.

해당 디렉터리로 이동하겠습니다. 

 

# 네임스페이스 생성
kubectl create namespace mymetallb

# 생성된 네임스페이스 확인
kubectl get namespace

 

이제 해당 네임스페이스에 metallb를 배포하겠습니다. 

# 설치
helm install --namespace mymetallb --generate-name metallb/metallb -f values.yaml

# 설치 확인
kubectl get all -n mymetallb

 

 

앞서 설명드린 대로 스피커 파드들과 데몬셋이 설정되어 있는 것을 확인 가능합니다. 

 

---
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: my-metallb-config
  namespace: mymetallb
spec:
  addresses:
  - 10.0.0.20-10.0.0.40
  autoAssign: true
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: my-metallb-config
  namespace: mymetallb
spec:
  ipAddressPools:
    - my-metallb-config

이제 위 yaml 파일 하나를 생성합니다. 

Layer 2 mode를 설정하는 configmap입니다. 

참고로 해당 addresses 대역을 넣으실 때 반드시 쿠버네티스 노드들과 같은 네트워크 대역으로 넣어주셔야 합니다. 

 

이제 Metal LB의 준비는 모두 끝났습니다. 

`loadbalancer` 타입의 서비스와 간단한 nginx 파드를 하나 생성하겠습니다. 

 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-loadbalancer
spec:
  type: LoadBalancer
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

 

`loadbalancer` 서비스의 external ip가 정상적으로 생성되어 있는 것을 확인 가능합니다. 

 

정상적으로 연결이 가능합니다. 

 

호스트 pc의 파워쉘에서 `arp -a` 명령어를 통해 arp 테이블을 확인하면 `loadbalancer`의  external ip의 mac 주소도 등록되어 있는 것을 확인 가능하고 해당 MAC 주소가 워커 노드 2의 MAC 주소와 같은 것을 확인 가능합니다. 

이로써 리더 speaker pod가 워커 노드 2에 올라가 있다는 것을 유추할 수 있습니다. 

 

참고로 제가 제 호스트 PC의 크롬에서 해당 ip로 접근이 가능한 것은 VMware 환경에서 테스트 중이기 때문에 가능한 것입니다. 

 

감사합니다.