CloudNet@ 가시다님이 진행하는 쿠버네티스 네트워크 스터디 KANS 3기 내용을 정리한 글입니다.
LoadBalancer 란
NodePort는 각 노드의 특정 포트를 통해 외부 트래픽을 전달합니다. 이 방식의 장점은 클러스터 외부에서 접근이 가능하다는 점이지만, 고정된 IP가 없고 포트 범위에 제약이 있어 대규모 서비스나 고가용성이 필요한 경우 한계가 있습니다.
반면, LoadBalancer는 클라우드 환경에서 자동으로 로드밸런서를 생성해 고정된 외부 IP를 제공합니다. 이를 통해 여러 파드에 트래픽을 효율적으로 분산할 수 있습니다. 그러나 이 방식을 사용하려면 클라우드 프로바이더와의 연동이 필요합니다. 클라우드 환경에서는 이 연동이 자동화되어 매우 편리하지만, 온프레미스 환경이나 특정 네트워크 구성에서는 직접 로드밸런서를 설정해야 합니다. 이를 통해 외부에서 고정된 IP를 이용해 안정적으로 서비스에 접근할 수 있으며, 로드밸런서는 파드 간 트래픽을 분산시켜 가용성과 확장성을 보장합니다.
현재 회사에서는 Citrix 장비와 Citrix Ingress Controller를 사용하여 LoadBalancer 타입의 서비스를 생성하고 있습니다. 이때, externalTrafficPolicy가 Cluster로 설정된 경우, 모든 노드에서 트래픽을 수신하게 되어 NodePort와 유사하게 동작합니다. 반면, Local로 설정하면 파드가 실행 중인 노드로만 트래픽이 전달됩니다. L7 스위치와 같은 장비를 통해 로드밸런서를 구현할 때는 DNAT이 발생할 수 있는데, 유저의 IP를 보존하고 싶다면 L7 로드밸런서에서는 XFF 헤더를, L4 로드밸런서에서는 Proxy Protocol을 사용하여 유저 IP를 보존해야 합니다.
citrix ingress controller.. 이 친구가 버그가 많아.. 운영하면서 어려움이 있긴 했지만.. 직접 코드를 수정해가면서 .. 운영해야했던.. 유사 네임스페이스의 서비스를 삭제하기만 해도 휴..
그렇지만, 모든 환경에서 L7 장비를 사용하는 것은 비용 면에서 현실적이지 않습니다. 예를 들면 테스트 환경이라던지 그런 용도로 이런 비싼 L7장비를 구매할 수도 없고 하지만 로드밸런서를 넣어 테스트 환경을 만들어보고 싶다면 어떻게 해야할까요? 이럴 때는 OpenELB나 PureLB와 같은 오픈소스 도구를 사용할 수 있습니다. 오늘은 스터디에서 소개받은 MetalLB를 사용해 테스트 환경에서 LoadBalancer 서비스를 구성해 보려 합니다.
이제 MetalLB를 설치한 후, LoadBalancer 모드를 생성하고 그 동작 방식을 자세히 살펴보겠습니다.
Metal LB
MetalLB(BareMetaLoadBalancer)는 onPrem환경에서도 사용할 수 있는 로드밸런서로, 개인적인 쿠버네티스 테스트 환경이나 운영 환경이 아닌 경우에 유용합니다. 스터디에서도 아무도 운영 환경에서 MetalLB를 사용하지 않는다는 점을 보면, 주로 테스트용으로 많이 사용되는 것으로 보입니다. 다른 네트워크 CNI(Calico 제외)와도 잘 호환된다는 점에서 유연성이 높습니다.
MetalLB :: MetalLB, bare metal load-balancer for Kubernetes
MetalLB is a load-balancer implementation for bare metal Kubernetes clusters, using standard routing protocols. Note Despite the beta status of the project / API, MetalLB is known to be stable and reliable. The project maturity page explains what that impl
metallb.universe.tf
Layer2 모드
MetalLB는 외부 IP로 들어오는 트래픽을 클러스터 내 여러 노드에 분산시키는 로드밸런서 역할을 합니다. MetalLB를 설치하면 각 노드에 '스피커' 파드가 실행되어 로드밸런싱을 수행합니다.
Layer2 모드에서는 스피커 파드가 외부 네트워크 장치가 ARP(또는 NDP) 요청을 보낼 때, 해당 IP 주소를 어느 노드에서 응답할지를 결정합니다. 그리고 그 응답을 하는 스피커 파드가 리더로 선정됩니다. 이렇게 여러 스피커 파드 중 리더가 역할을 맡아 트래픽을 받고 iptables룰을 통해 다른 노드로 전달하는 방식으로 로드밸런싱이 이루어집니다.
BGP 모드
BGP 모드에서는 각 노드에 뜬 스피커 파드가 FRR을 사용해 외부 라우터에 IP를 광고합니다.
실제 테스트 해보기
Layer2 모드 설치하기
MetalLB 설치
Layer2 모드의 MetalLB를 설치해보도록 하겠습니다. 설치는 간단하게 manifests로 설치해보도록 하겠습니다.
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/refs/heads/main/config/manifests/metallb-native.yaml
설치를 완료하면 다음과 같은 crd들이 설치가 된것을 확인할 수 있습니다.
기본 구성으로 설치했을 경우에 각 노드에는 speacker 파드가 뜨고 controller 파드가 1개가 뜨는데 speaker 파드들은 모두 노드와 동일한 아이피를 갖고 생성 됩니다. 실제 파드에 설정된 것을 확인했을 때 hostNetwork가 true로 설정되어있는 것을 확인할 수 있습니다.
떠있는 파드의 열려있는 포트를 확인해보니 다음과 같이 열려있는것을 확인해볼 수 있습니다.
IPAM Pool 생성하기
LoadBalancer 타입의 경우 노드 아이피를 사용하는 것이 아닌 다른 아이피를 서비스의 vip로 사용하는 것이기 때문에 라우팅을 위한 별도의 아이피들이 필요합니다. 이러한 아이피들이 있다면 이 metalLB에선 이 아이피들을 관리해서 자동으로 LoadBalancer 타입으로 서비스로 만들어줍니다. kind에서는 가상의 대역을 사용해서 도커 컨테이너를 노드로 만들어 사용하기 때문에 이 아이피 대역을 사용해서 IPAM Pool로 만들어 테스트 할 수 있습니다.
먼저 현재 생성되어있는 도커 네트워크들을 조회해보겠습니다.
docker network ls
별도의 설정을 하지 않았다면 kind를 사용하여 노드들이 생성되게 됩니다. 다른 네트워크 대역으로 노드를 생성해보고 싶다면 아래의 링크의 내용대로 설정할 수 있습니다.
2024.10.05 - [K8S/ecosystem] - kind: 다른 네트워크 대역의 클러스터 2개 만들기
다시 돌아와서 kind의 네트워크 대역을 확인해보겠습니다.
docker network inspect kind | jq '.[].IPAM'
kind가 사용하는 대역이 172.17.0.0/16대역이고 노드에서는 다음의 아이피들을 사용하고 있습니다.
정리해보면 172.17.0.1을 gateway에서 사용하고 있고 172.17.0.2-4를 노드에서 사용하고 있기 때문에 172.17.0.5-172.17.255.255 까지를 IPAM으로 설정할 수 있습니다. 하지만 이번 테스트에서는 간단하게 172.17.0.100-172.17.0.110 을 설정해보도록 하겠습니다.
이 내용을 배포해보도록 하겠습니다.
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: my-ippool
namespace: metallb-system
spec:
addresses:
- 172.17.0.100-172.17.0.110
이제 이 설정을 기반으로 L2 광고를 해야합니다.
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: my-l2-advertise
namespace: metallb-system
spec:
ipAddressPools:
- my-ippool
로드밸런서 생성하기
아이피를 주지 않고 서비스를 생성해보겠습니다.
apiVersion: v1
kind: Service
metadata:
labels:
run: blue
name: blue
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
run: blue
type: LoadBalancer
처음에 정의한 IP Pool의 대역에서 하나가 할당되어 생성된 것을 확인해볼 수 있습니다.
생성되어있는 파드가 없어서 광고는 되지 않고 있는 것을 확인할 수 있습니다.
kubectl describe svc blue
이제 파드를 생성해보겠습니다. 파드가 뜨고나니 광고가 되는 것을 확인해볼 수 있습니다.
arp scan 로그를 보았을 때에도 파드가 생성되고 나서 광고가 된것을 확인해 볼 수 있습니다.
docker exec -it myk8s-control-plane arp-scan --interfac=eth0 --localnet
02:42:ac:11:00:02 이 맥 어드레스는 blue 파드가 뜬 worker2의 eth0 인터페이스의 맥 어드레스 인것도 확인해볼 수 있습니다.
캐싱 된 ARP 테이블 정보 확인하기
같은 대역에 노드 생성하기
docker run -d --rm --name mypc --network kind nicolaka/netshoot sleep infinity
arn 명령어 사용해서 확인하기
# arp 명령어 실행을 위한 설치
apt-get install net-tools
# arp 테이블 확인
arp -n
ip 명령어 사용해서 확인하기
ip -c neigh
생성한 도커 컨테이너에서 arping을 날려보겠습니다.
docker exec -it mypc arping -I eth0 -f -c 1 172.17.0.100
1개의 응답을 02:42:AC:11:00:02 맥 어드레스로 받은것을 확인할 수 있습니다.
BGP 모드 설치하기
이제 BGP 모드로 변경하여 설치해보겠습니다. v0.12 릴리스까지는 MetalLB의 ConfigMap을 통해 BGP 모드를 설정했지만, 이제는 CR을 생성하여 설정할 수 있습니다. 버전에 주의하여 테스트하시기 바랍니다.
AvoidBuggyIPs 구형 네트워크 장비 중 일부는 잘못된 Smurf 공격 보호 기능 때문에 .0 또는 .255로 끝나는 IP 주소를 차단할 수 있습니다. 이런 문제가 발생하면 IPAddressPool CR에서 AvoidBuggyIPs 플래그를 설정하여 .0과 .255로 끝나는 IP 주소를 피할 수 있습니다.
# BGP Peer 정의
apiVersion: metallb.io/v1beta2
kind: BGPPeer
metadata:
name: default
namespace: metallb-system
spec:
myASN: 64512
peerASN: 64513
peerAddress: 192.168.10.254
holdTime: 1m30s
keepaliveTime: 0s
---
# IP Address Pool 정의
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default
namespace: metallb-system
spec:
addresses:
- 172.17.0.200-172.17.0.210
autoAssign: true
avoidBuggyIPs: true
---
# BGP Advertisement 정의
apiVersion: metallb.io/v1beta1
kind: BGPAdvertisement
metadata:
name: default
namespace: metallb-system
spec:
aggregationLength: 32
communities: []
ipAddressPools:
- default
이 설정을 적용하면 MetalLB는 외부 라우터(192.168.10.254)와 BGP 피어링을 설정하고, 172.20.1.0/24 범위의 IP 주소를 개별적으로(/32) 라우터에 광고하게 됩니다. 여기서 peerASN은 외부 라우터에 할당된 자율 시스템 번호(ASN)로, 라우터가 속한 네트워크 그룹을 식별합니다. MetalLB는 이 peerASN(64513)을 사용하여 라우터와 BGP 세션을 설정하며, 이를 통해 라우터는 해당 IP 주소로 들어오는 트래픽을 클러스터로 라우팅할 수 있습니다. MetalLB는 이러한 IP 주소를 서비스에 자동으로 할당하여 외부에서 클러스터 내부의 서비스에 접근할 수 있는 경로를 제공합니다.
서비스 생성해서 테스트해보기
테스트를 위해 다음과 같이 서비스 객체를 생성합니다.
apiVersion: v1
kind: Service
metadata:
labels:
run: green
name: green
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
run: green
type: LoadBalancer
신규 대역의 IP가 할당된 것을 확인할 수 있습니다. 그리고 LoadBalancer 타입이지만 NodePort가 할당된 것을 볼 수 있습니다. 이는 allocateLoadBalancerNodePorts 설정이 true로 되어 있기 때문이며, NodePort가 필요 없는 로드밸런서를 달고 있는 경우 false로 변경할 수 있습니다.
명령어 ss -tunp | egrep 'Netid|speaker'는 현재 네트워크 소켓 중 'speaker' 프로세스와 관련된 TCP 연결 상태를 필터링하여 보여줍니다. 첫 번째 항목은 로컬 주소 172.17.0.5에서 원격 주소 192.168.10.254로 연결을 시도 중이며, 아직 연결이 완료되지 않은 SYN-SENT 상태입니다. 두 번째 항목은 로컬 주소 172.17.0.5에서 원격 주소 10.200.1.1로의 TCP 연결이 성공적으로 확립된 ESTAB 상태임을 나타냅니다.
노드 내부에서는 iptables이 생성되어서 트래픽이 전달 됩니다. 하지만 외부라우터와 연결이 되지 않기 때문에 테스트가 어렵습니다.
이후에 소프트웨어 라우터를 구성해서 연결해서 테스트해볼 수 있으면 이후에 추가해보면 좋을 것 같습니다.
고급 BGP 라우팅
MetalLB에서 BGP를 사용해 클러스터 외부와 통신할 때, 기본적으로 각 서비스 IP는 /32로 광고됩니다. 하지만 트랜짓 제공자(인터넷 서비스 제공자)는 /24보다 더 세부적인 경로를 거부하는 경우가 있습니다. 이를 해결하기 위해, /24 경로를 광고하여 트랜짓 제공자가 이를 수락하게 하고, 클러스터 내부에서는 각 IP에 대한 /32 경로를 사용해 세부적인 라우팅을 할 수 있도록 설정했습니다. 이를 통해 외부와의 원활한 통신을 유지하면서도 내부적으로 효율적인 라우팅이 가능해졌습니다.
apiVersion: metallb.io/v1beta1
kind: BGPAdvertisement
metadata:
name: local
namespace: metallb-system
spec:
ipAddressPools:
- bgp-pool
aggregationLength: 32 # 여러 개의 /32 IP를 큰 범위로 묶어서 광고할 수 있도록 하는 옵션
# 예를 들어 /32 IP를 묶어 /24 같은 큰 범위로 광고할 수 있습니다
localPref: 100 # BGP에서 경로 우선순위를 나타내며, 값이 클수록 우선순위가 높습니다
communities:
- 65535:65282
---
apiVersion: metallb.io/v1beta1
kind: BGPAdvertisement
metadata:
name: external
namespace: metallb-system
spec:
ipAddressPools:
- bgp-pool
aggregationLength: 24
'K8S > 🔥 network study🔥' 카테고리의 다른 글
[네떡스터디🔥kans] 쿠버네티스 서비스 이해하기 - kube-proxy IPVS 모드 (0) | 2024.09.30 |
---|---|
[네떡스터디🔥kans] 쿠버네티스 서비스 이해하기 - External IP (0) | 2024.09.22 |
[네떡스터디🔥kans] 쿠버네티스 서비스 이해하기 - NodePort (0) | 2024.09.22 |
[네떡스터디🔥kans] 쿠버네티스 서비스 이해하기 - ClusterIP (0) | 2024.09.22 |
[네떡스터디🔥kans] Calico CNI 알아보기 - BGP (1) | 2024.09.17 |