MetalLB 개요
MetalLB는 BareMetal LoadBalancer의 약자로, 온프레미스 환경에서도 클라우드 로드 밸런서처럼 사용할 수 있는 서비스(로드밸런서 타입)입니다.
퍼블릭 클라우드 환경 AWS의 경우, LoadBalancer
타입의 서비스를 사용할 때, 클라우드 제공자의 로드밸런서(ALB)가 자동으로 할당되지만, 온프레미스 환경에서는 이러한 로드밸런서가 기본적으로 제공되지 않기 때문에 MetalLB를 사용하여 클러스터 외부로 서비스를 노출할 수 있습니다.
MetalLB는 AWS, GCP 등 대부분의 퍼블릭 클라우드 환경을 지원하지는 않습니다.
MetalLB 특징
- 데몬셋으로 speaker 파드를 생성하여 External IP를 전파합니다.
- speaker 파드는 호스트 네트워크 사용(
NetworkMode: host
)
- speaker 파드는 호스트 네트워크 사용(
- 서비스(LoadBalancer)의 External IP 전파를 위해 표준 프로토콜 ARP(IPv4), NDP(IPv6), BGP를 사용합니다.
- MetalLB는 두 가지 모두를 지원하며, 환경에 맞게 구성하여 사용할 수 있습니다.
- L2 mode
ARP
: 같은 서브넷 내에서 ARP/NDP를 통해 IP를 광고 - BGP mode : BGP를 사용하여 외부 네트워크 라우터와 경로 정보를 동적으로 공유
- L2 mode
사전지식
GARP(Gratutious ARP)
일반적인 ARP 요청과 달리, 아래와 같은 목적으로 특정 IP를 요청하는 것이 아닌 자신의 IP를 광고하는 패킷입니다.
GARP의 목적
- IP 주소 충돌 감지 및 방지
- 네트워크에 새로운 장치가 연결되었을 때, 자신의 IP가 네트워크 내에서 중복되는지 확인
- ARP 캐시 업데이트
- 네트워크 장치가 IP 주소가 변경되었을 때, GARP를 사용하여 스위치, 라우터, 다른 호스트의 ARP 캐시를 업데이트
- 로드밸런서 및 VRRP 환경에서의 사용
- 로드벨런서, VRRP(Virtual Router Redundancy Protocol) 또는 MetalLB 같은 네트워크 시스템에서, 마스터 노드 전환 시 GARP를 사용하여 새로운 마스터 노드의 IP-MAC 정보를 네트워크에 알림
strickARP
응답을 더 엄격하게 제어하는 네트워크 설정입니다. 이 설정을 활성화하면, 시스템은 자신에게 실제로 할당된 IP 주소에 대해서만 ARP 요청에 응답합니다.
1. MetalLB에서의 Strict ARP
MetalLB를 Layer 2 모드로 사용할 때 Strict ARP 설정이 특히 중요합니다
- MetalLB는 LoadBalancer 서비스에 대해 가상 IP(VIP)를 할당합니다.
- Strict ARP가 비활성화된 경우, 잘못된 노드가 이 VIP에 대한 ARP 요청에 응답할 수 있습니다.
- 이로 인해 네트워크 트래픽이 잘못된 노드로 전달될 수 있습니다.
2. IPVS모드에서의 Strict ARP
Kubernetes의 kube-proxy가 IPVS 모드에서 작동할 때, Strict ARP 설정이 중요해집니다. 이 설정은 다음과 같은 효과를 가집니다:
- 노드는 자신에게 실제로 할당된 IP 주소에 대해서만 ARP 응답을 보냅니다.
- 이는 IPVS로 로드밸런싱할 때 ARP 패킷이 잘못된 인터페이스로 전달되는 문제를 방지합니다.
Layer 2 Mode
Layer 2 모드는 MetalLB가 같은 서브넷 내에 있는 장치들에 IP 주소를 광고하는 방식입니다.
ARP(Address Resolution Protocol) 또는 NDP(Neighbor Discovery Protocol)를 사용하여 클러스터 외부 장치들에게 해당 IP 주소가 특정 호스트(노드)에 연결되어 있음을 알립니다. 이를 통해서 같은 서브넷에 있는 클라이언트들이 Kubernetes 서비스에 접근할 수 있습니다.
Layer 2 Mode의 장단점
- 장점:
- 설정이 간단하고, 추가적인 라우터 설정이 필요 없습니다.
- 같은 서브넷 내에 있는 장치들과 빠르게 통신할 수 있습니다.
- 복잡한 네트워크 장치 없이도 서비스 노출이 가능합니다.
- 단점:
- 같은 서브넷 내에서만 동작하므로, 클러스터와 클라이언트가 같은 서브넷에 있어야 합니다.
- 서브넷을 넘어가는 트래픽에 대해서는 설정이 어려울 수 있습니다.
- 대규모 네트워크 환경에서 여러 서브넷이나 라우터 간 경로 설정이 필요한 경우에는 비효율적입니다.
실습 환경 구성(MetalLB 설치)
- Kind(쿠버네티스 클러스터)
- control-plane-node(172.17.0.5)
- worker1(172.17.0.2)
- worker2(172.17.0.2)
- worker3(172.17.0.3)
(*실습 환경에 따라서, 리더 스피커 파드의 배치된 노드가 다르거나, 할당된 IP가 다를 수 있습니다.)
webpod 파드 배포
worker node1,2에만 webpod
를 배포합니다.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: webpod1
labels:
app: webpod
spec:
nodeName: myk8s-worker
containers:
- name: container
image: traefik/whoami
terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Pod
metadata:
name: webpod2
labels:
app: webpod
spec:
nodeName: myk8s-worker2
containers:
- name: container
image: traefik/whoami
terminationGracePeriodSeconds: 0
EOF
MetalLB 설치
설치는 다양한 방식(helm 등)이 있지만, 간단한 설치를 위해 manifest 방식으로 설치합니다.
metallb-native-prometheus.yaml
: metallb 프로메테우스 익스포터를 제공하는 버전
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/refs/heads/main/config/manifests/metallb-native-prometheus.yaml
kube-rabc-proxy 컨테이너가 프로메테우스 익스포터 역할을 제공합니다.
MetalLB 리소스 확인
- metalLB
- controller
- speaker
- CRD
kubectl get all -n metallb-system
NAME READY STATUS RESTARTS AGE
pod/controller-679855f7d7-5snvd 2/2 Running 4 (25m ago) 46h
pod/speaker-q6srk 2/2 Running 3 (26m ago) 46h
pod/speaker-sjf55 2/2 Running 6 (25m ago) 46h
pod/speaker-t57cz 2/2 Running 3 (25m ago) 46h
pod/speaker-z9srl 2/2 Running 2 (26m ago) 175m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/controller-monitor-service ClusterIP None <none> 9120/TCP 46h
service/metallb-webhook-service ClusterIP 10.200.1.42 <none> 443/TCP 46h
service/speaker-monitor-service ClusterIP None <none> 9120/TCP 46h
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/speaker 4 4 4 4 4 kubernetes.io/os=linux 46h
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/controller 1/1 1 1 46h
NAME DESIRED CURRENT READY AGE
replicaset.apps/controller-679855f7d7 1 1 1 46h
생성된 CRD는 다음과 같습니다.
모드 및 서비스 대역 지정
MetalLB는 설치가 되었지만, 기능을 사용하기 위해서는 추가적으로 MetalLB 리소스를 구성해야 합니다.
1.IPAddressPool 생성
spec.addresses
: LoadBalancer Externel IP로 사용할 IP대역을 설정합니다.
kubectl explain ipaddresspools.metallb.io
cat <<EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: my-ippool
namespace: metallb-system
spec:
addresses:
- 172.17.255.200-172.17.255.250
EOF
2.l2advertisements 생성
spec.ipAddressPools
: 설정한 IPpool을 기반으로 Layer2 모드로 LoadBalancer IP 사용 허용합니다.
# 생성
cat <<EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: my-l2-advertise
namespace: metallb-system
spec:
ipAddressPools:
- my-ippool
EOF
# 확인
kubectl get l2advertisements -n metallb-system
NAME IPADDRESSPOOLS IPADDRESSPOOL SELECTORS INTERFACES
my-l2-advertise ["my-ippool"]
3.서비스 (LoadBalancer 타입) 생성
webpod로 label 지정하여, LoadBalancer
타입의 서비스 3개를 생성합니다.
# 서비스 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: svc1
spec:
ports:
- name: svc1-webport
port: 80
targetPort: 80
selector:
app: webpod
type: LoadBalancer # 서비스 타입이 LoadBalancer
---
apiVersion: v1
kind: Service
metadata:
name: svc2
spec:
ports:
- name: svc2-webport
port: 80
targetPort: 80
selector:
app: webpod
type: LoadBalancer
---
apiVersion: v1
kind: Service
metadata:
name: svc3
spec:
ports:
- name: svc3-webport
port: 80
targetPort: 80
selector:
app: webpod
type: LoadBalancer
EOF
생성된 LoadBalancer 타입 서비스를 확인해 보면 EXTERNAL-IP
가 할당된 것을 확인할 수 있습니다. EXTERNAL-IP
는 기본적으로 위에서 설정한 IPAddressPool
대역으로 랜덤 하게 할당됩니다.
metallb CRD인 servicel2status
로 상태를 확인할 수 있습니다.
만약, MetalLB가 설치되지 않았다면, 아래와 같이 LoadBalancer
타입의 경우 EXTERNAL-IP는 pending 상태일 것입니다.
fixed IP 설정EXTERNAL-IP
를 고정된 IP로 설정하고 싶다면 아래 필드를 추가하면 됩니다. 주의할 점은 IPAddressPool
에서 지정한 IP대역의 IP로 설정해야 합니다.
노드포트 비활성화(allocateLoadBalancerNodePorts)
LoadBalancer를 사용하면 노드의 IP를 노출하지 않고도 외부와 서비스를 통신할 수 있는 장점이 있습니다. 하지만, LoadBalancer Type
의 서비스는 기본적으로 노드포트를 할당합니다.
allocateLoadBalancerNodePorts: false 필드를 추가하면 노드포트를 할당하지 않을 수 있습니다.
MetalLB 동작흐름 분석
로드벨런서 타입의 서비스를 생성하고 이벤트를 확인해 보면 metallb-controller
가 External 노드에 배포된 특정 speaker 파드가 리더 역할을 하는 것을 알 수 있습니다.
자세히 MetalLB의 동작 예시를 살펴보겠습니다.
- 서비스 생성:
LoadBalancer
타입의 서비스가 생성되면, MetalLB의metallb-controller
가 이를 감지하고IPAddressPool
에서 사용 가능한 IP를 할당합니다.
- IP 할당 이벤트:
metallb-controller
가IPAllocated
이벤트를 생성하고, 할당된 IP(172.18.255.201
)를 서비스에 매핑합니다.
- 노드에서 IP 광고:
metallb-speaker
가 해당 IP를 가진 노드(myk8s-worker
)에서 IP를 광고하고,nodeAssigned
이벤트를 생성하여, 해당 노드가 이 IP에 대한 요청을 받을 준비가 되었음을 알립니다.
- 외부 트래픽 수신:
- 외부 클라이언트가172.18.255.201
으로 트래픽을 전송하면,myk8s-worker
노드가 이를 수신하여 Kubernetes 서비스로 전달합니다.
Assigned IP ["172.18.255.201"]
: MetalLB가 LoadBalancer
타입의 서비스에 할당한 외부 IP로, 외부에서 접근할 때 사용하는 External IP입니다.metallb-speaker
가 해당 IP를 myk8s-worker
노드에서 광고하고, 외부 클라이언트의 트래픽을 이 노드로 전달하도록 설정합니다.
이를 통해 MetalLB가 IP 할당과 광고를 통해 외부에서 Kubernetes 서비스에 접근할 수 있도록 하는 과정을 이해할 수 있습니다. 😊
서비스 접속 테스트(External IP)
쿠버네티스 노드가 아닌 mypc
외부 클라이언트에서 쿠버네티스 서비스 external-ip로 통신이 잘 동작하는지 확인합니다.
# 클라이언트 컨테이너 생성(external-ip와 같은 네트워크 대역)
docker run -d --rm --name mypc --network kind --ip 172.17.0.100 nicolaka/netshoot sleep infinity # IP 지정 실행 시
# 현재 SVC EXTERNAL-IP를 변수에 지정
SVC1EXIP=$(kubectl get svc svc1 -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
SVC2EXIP=$(kubectl get svc svc2 -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
SVC3EXIP=$(kubectl get svc svc3 -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $SVC1EXIP $SVC2EXIP $SVC3EXIP
for i in $SVC1EXIP $SVC2EXIP $SVC3EXIP; do echo ">> Access Service External-IP : $i <<" ; docker exec -it mypc curl -s $i | grep Hostname ; echo ; done
>> Access Service External-IP : 172.17.255.200 <<
Hostname: webpod2
>> Access Service External-IP : 172.17.255.201 <<
Hostname: webpod1
>> Access Service External-IP : 172.17.255.202 <<
Hostname: webpod2
이제, k8s 클러스터 외부에서 노드의 IP를 감추고 VIP:Port를 통해 클러스터 내부의 애플리케이션과 통신할 수 있습니다.
# mypc/mypc2 에서 현재 SVC EXTERNAL-IP를 담당하는 리더 Speaker 파드 찾는법 : arping 툴 사용
## Unicast reply from 172.18.255.200: 해당 IP 주소에서 응답을 받았음을 의미합니다.
## Sent 1 probes (1 broadcast(s)): 하나의 ARP 요청을 보냈고, 브로드캐스트 방식으로 요청을 전송했음을 나타냅니다.
## Received 1 response(s): 하나의 응답을 수신했음을 나타냅니다.
docker exec -it mypc arping -I eth0 -f -c 1 $SVC1EXIP
docker exec -it mypc arping -I eth0 -f -c 1 $SVC2EXIP
docker exec -it mypc arping -I eth0 -f -c 1 $SVC3EXIP
for i in $SVC1EXIP $SVC2EXIP $SVC3EXIP; do docker exec -it mypc arping -I eth0 -f -c 1 $i; done
docker exec -it mypc ip -c neigh
ARP 테이블 정보
Failover 테스트
쿠버네티스 worker 1번 노드를 장애를 발생시켜, 정상적으로 통신이 복구되는지 확인합니다.
# 반복 접속
SVC1EXIP=$(kubectl get svc svc1 -o jsonpath='{.status.loadBalancer.ingress[0].ip}') docker exec -it mypc zsh -c "while true; do curl -s --connect-timeout 1 $SVC1EXIP | egrep 'Hostname|RemoteAddr'; date '+%Y-%m-%d %H:%M:%S' ; echo ; sleep 1; done"
## 상태 모니터링
watch -d kubectl get pod,svc,ep
## 실시간 로그 확인
kubectl logs -n metallb-system -l app=metallb -f
혹은
kubectl stern -n metallb-system -l app=metallb
# 장애 재연
## 리더 Speaker 파드가 존재하는 노드(실제는 컨테이너)를 중지
docker stop <svc1 번 리더 Speaker 파드가 존재하는 노드(실제는 컨테이너)> --signal 9
docker stop myk8s-worker -- signal 9
워커노드 1에 장애가 발생하면 남아있는 스피커들이 장애를 인지하고 Leader 파드를 다시 선출하고 GARP를 통해 전파를 합니다. 하지만 이 과정에서 10~20초라는 장애 시간이 발생하게 됩니다.
장애 노드가 복구가 되면 다시 Leader가 변경되고 5초정도 장애시간이 발생합니다.
따라서, MetalLB Layer2 모드 사용 시에는 , 장애 지속 시간이 운영하고 있는 애플리케이션이 동작에 문제가 없는지, 사전에 테스트가 필요하며, 최적화 및 장애 대응 방안이 필요합니다.
Layer 2 Mode 정리
- 서비스(로드벨런서) External IP 생성 시, speaker 파드 중 1개가 리더가 됩니다.
- 리더 speaker 파드가 존재하는 노드로 서비스 접속 트래픽이 인입되고, 해당 노드에서 iptables 분산되어 파드로 접속합니다.
- 리더는 ARP(GARP, Gratutious ARP)로 해당 External IP에 대해서 IP 충돌을 방지하기 위해, 자신의 소유라며 동일 네트워크에 전파합니다.
- 만약, 리더(노드)가 장애 발생 시, 자동으로 나머지 speaker 파드 중 1개가 리더가 됩니다.
BGP Mode
BGP 모드 사용을 위해서는 외부 라우터가 필요하기 때문에, 실습 환경을 구성의 어려움으로, 간단한 이론에 대해서만 다루도록 하겠습니다.
MetalLB에서 BGP 모드 설정 시, speaker 파드는 BGP 프로토콜을 통해 서비스 정보(External-IP)를 전파합니다.
외부 라우터와 연동을 통해 LoadBalancer 서비스의 External IP가 자동으로 라우터 장비의 라우팅 테이블에 업데이트됩니다.
쿠버네티스의 서비스와 외부 라우터를 연동해서 사용하기 때문에, 편리하고 성능이 우수할 수도 있지만, 그만큼 라우터 설정과 관리가 정말 중요하기 때문에 네트워크팀과의 협조가 필요합니다.
'Kubernetes > Network' 카테고리의 다른 글
Ingress와 Kubernetes Gateway Api - KANS 6주차 (0) | 2024.10.13 |
---|---|
kube-proxy IPVS 모드의 동작 원리 이해 - KANS 5주차 2 (1) | 2024.10.06 |
Calico CNI 기본 네트워크 이해 & 네트워크 모드 - KANS 3주차 (4) | 2024.09.22 |
Pause 컨테이너 & Flannel CNI - KANS 2주차 (2) | 2024.09.08 |
컨테이너 격리 & 네트워크 및 보안 - KANS 1주차 (0) | 2024.08.27 |