MetalLB IP 대역 선정
먼저 클러스터 노드들이 사용하는 IP 대역을 확인한다.
kubectl get nodes -o wide

노드들이 같은 IP 대역을 사용하고 있는지 확인한다. 노드들은 10.0.2.xx 대역을 사용하고 있다. 10.0.2.60~10.0.2.69 대역을 로드밸런서 대역으로 지정한다.
할당할 로드밸런서 대역을 ping을 통해 사용 여부를 검증한다.
for i in {0..9}; do ping -c 1 10.0.2.6$i; done

- Destination Host Unreachable가 출력 중이므로 해당 IP들을 사용 중이지 않고 있다는 의미이다.
- 위 과정을 통해 MetalLB가 사용할 IP 풀을 안전하게 확보할 수 있다.
Helm을 이용한 MetalLB 설치 준비
먼저, MetalLB 공식 Helm 저장소를 추가한다.
helm repo add metallb https://metallb.github.io/metallb
cf. Helm은 쿠버네티스 애플리케이션 패키지 매니저이며, 리눅스의 apt, yum과 유사한 역할을 한다.
이어서 MetalLB Chart를 다운로드한다.
helm pull metallb/metallb
tar xvfz metallb-0.12.1.tgz
mv metallb metallb-0.15.3
MetalLB 설정 파일(my-values.yaml, my-config.yaml) 생성 및 수정
원본 values.yaml을 보존하기 위해, 복사본을 만들어 사용한다.
cp values.yaml my-values.yaml
my-values.yaml 파일을 통해 헬름으로 MetalLB를 설치한다. 별도의 MetalLB 전용 네임스페이스를 생성해서 설치한다.
kubectl create ns metallb
kubectl ns metallb # 네임스페이스 전환
helm install metallb -f my-values.yaml .

위와 같이 성공적으로 생성된 것을 확인할 수 있다.
또한 IP 설정과 Layer2 방식을 설정하기 위해 아래와 같은 config 파일을 생성해준다.
vi my-config.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default
namespace: metallb
spec:
addresses:
- 10.0.2.60-10.0.2.69
autoAssign: true
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default
namespace: metallb
spec:
ipAddressPools:
- default
IPAddressPool은 LoadBalancer 서비스에 사용할 수 있는 IP 범위를 정의하고, L2Advertisement는 그 IP를 Layer2(ARP) 방식으로 네트워크에 광고하여 외부에서 해당 IP를 인식하고 접근할 수 있게 한다.
상세 옵션의 내용은 다음과 같다.
- IPAddressPool
- MetalLB가 정의한 확장 리소스이다.
- “외부 서비스용 IP 자원 풀”을 의미한다.
- metadata.name
- 이 IP 풀의 식별자이다.
- 이후 다른 리소스에서 이 이름을 참조한다.
- namespace
- MetalLB가 설치된 네임스페이스와 반드시 동일해야 한다.
- 다르면 speaker/controller가 이 설정을 인식하지 못한다.
- addresses
- MetalLB가 사용할 수 있는 외부 IP 범위이다.
- 이 IP들은 다음 조건을 만족해야 한다.
- autoAssign
- 기본값은 true이다.
- LoadBalancer 서비스가 생성되면 MetalLB가 이 풀에서 IP 하나를 자동으로 선택해서 할당한다.
- 만약 false라면, loadBalancerIP: 10.0.2.61 이런식으로 직접 지정해야 한다.
- L2Advertisement
- “이 IP를 네트워크에 어떻게 알릴 것인가”를 정의한다.
- 여기서는 Layer2(ARP) 방식으로 설정했다.
- spec.ipAddressPools.default
- IPAddressPool을 어떤 정책으로 처리할 것인지 지정한다.
- default라는 IP 풀에 속한 IP들은 Layer2 방식으로 광고한다.
다음 명령어를 통해 my-config.yaml 파일을 적용한다.
kubectl apply -f my-config.yaml

위와 같이 성공적으로 생성되는 것을 확인할 수 있다.
적용 후 상태가 정상인지 확인해준다. IP 풀 범위도 정확히 적용되었는지 확인해준다.
kubectl get ipaddresspool.metallb.io/default
kubectl describe ipaddresspool.metallb.io/default

위와 같이 모든 설정들이 정상적으로 적용되어 있는 것을 확인할 수 있다.
다음 명령어를 통해 metallb 리소스들이 정상적으로 올라와 있는지도 확인한다.
kubectl get all

이상 없음을 알 수 있다.
Voting App 어플리케이션 배포
테스트 용도로 voting-app을 배포해본다. 해당 어플리케이션은 사용자가 선호하는 후보를 선택하고 그 결과를 출력하는 어플리케이션이다. 다음 명령어를 통해 소스 코드를 먼저 클론한다.
git clone https://github.com/dockersamples/example-voting-app.git
cd example-voting-app
vote 네임스페이스를 생성하고, 어플리케이션의 매니페스트 구조를 확인한다.
kubectl create ns vote
kubectl ns vote
ls k8s-specifications/

apply -f로 디렉토리를 지정하여 디렉토리 전체의 YAML 파일을 설치한다.
kubectl apply -f k8s-specifications/

정상적으로 모두 올라온 것을 확인할 수 있다.
이제 MetalLB를 테스트하기 위해 vote 서비스 타입을 LoadBalancer로 변경해준다. k8s-specifications/vote-service.yaml 파일을 수정해준다.
cd k8s-specifications/
vi vote-service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: vote
name: vote
spec:
type: LoadBalancer
ports:
- name: "vote-service"
port: 80
targetPort: 80
#nodePort: 31000
selector:
app: vote
kubectl apply -f vote-service.yaml
정상적으로 서비스 타입이 변경되었는지 다음과 같이 확인한다.

위와 같이 정상적으로 서비스 타입이 변경되었고, EXTERNAL-IP 값도 할당된 것을 볼 수 있다. 해당 IP를 통해 클러스터 외부에서 접속할 수 있다.
Voting App 접속 테스트
아래와 같이 포트포워딩을 Virtual Box에서 설정해준다.

이제 다음 링크를 통해 접속을 해보면 아래와 같이 정상적으로 접속되는 것을 확인할 수 있다.
http://127.0.0.1:80

기존의 물리 L4 스위치에서 L4의 가상 IP로 외부에서 접속하는 것과 동일하다. 이제 LB를 통해 파드에 정상적으로 부하 분산이 되는지 확인해본다.
부하분산 테스트
vote 파드 수를 다음과 같이 증가시킨다.
kubectl scale deployment vote --replicas 3

위와 같이 파드의 수가 3개로 증가한 것을 확인할 수 있다.
다음 명령어를 통해 파드 3개에 대해 부하 분산이 이뤄지는지 확인한다.
for i in {1..10}; do curl -s 172.17.29.71 | grep ID; done | sort | uniq -c | sort -nr

위와 같이 각 파드에 4번, 3번, 3번으로 균등하게 접속한 것을 확인할 수 있다.
Reference
- https://kubernetes.io/ko/docs/home/
- 이정훈, ⌜24단계 실습으로 정복하는 쿠버네티스⌟, 위키북스, 2022, 492쪽