쿠버네티스 클러스터 내 Pod로 외부에서 접속하기 위해서는 요청을 수신하기 위한 expose 설정을 해야하는데 방법 중 하나가 LoadBalancer 타입을 지정하는 것
기본적으로 쿠버네티스는 로드밸런서 컴포턴트를 직접적으로 제공하지 않음
public cloud를 사용하는 경우에는 CSP에서 제공하는 자체 로드밸런서를 사용
온프레미스에서는 주로 MetalLB를 사용함 (MetalLB는 소프트웨어로 동작함)
일반적으로 다수의 워커 노드로 트래픽을 분산하기 위해서 앞단에 로드밸런서를 두고, 로드밸런서가 수신한 요청을 대상 노드에 전달하면 수신받은 노드는 기존의 ClusterIP 타입의 동작과 동일하게 iptables rule을 통해 대상 Pod로 트래픽을 전달함
이 때는 노드의 포트로 수신한 트래픽을 대상 서비스의 iptables rule로 찾기 위해 iptables chain을 하나 더 거치게됨
참고로 AWS의 NLB 또는 ALB를 사용하면 해당 VPC CNI에 의해 로드밸런서에서 대상 Pod로 직접적인 연결이 가능하기 때문에 iptables rule을 거치지 않고 직접 통신하는 구조가 됨
MetalLB란?
BareMetalLodbalancer의 약자
온프레미스 환경에서 표준 프로토콜(ARP, BGP)을 사용해 LoadBalancer 유형의 서비스를 구현
Layer 2 모드(ARP)와 BGP 모드를 지원함
Public Cloud 환경에서는 ARP 사용 시 요청을 차단하기 때문에 BGP 모드를 사용해야함
MetalLB로 BGP 모드를 사용하는 것보다는 LoxiLB를 사용하는 것을 권장(기능이 더 많음)
DaemonSet으로 Speaker Pod를 생성해서 External IP를 전파함
다수의 노드의 IP 대신 엔드포인트를 제공함으로써 노드 IP가 유출되지 않아 보안성을 향상 시킬 수 있고, 클라이언트 영향 없이 노드가 유연하게 확장/축소 될 수 있도록 함
Layer2(ARP) 모드
ARP를 통해서 External IP를 전파
참고 : 네트워크 내부에서 통신을 하기 위해 상대방 장비의 MAC 주소를 알아야하는데 이 때 ARP 프로토콜을 통해서 상대방 IP 주소에 해당하는 MAC 주소를 요청하고 응답을 통해 자동으로 알아오게됨
speaker pod는 DaemonSet으로 실행되기 때문에 각 노드에 배포가 되는데 이 중 투표를 통해 특정 노드의 speaker pod가 리더 노드로 선정됨. 이 후 클라이언트의 요청은 해당 speaker pod가 속한 노드의 IP로 접속하게 됨. 결국 수신 받은 요청은 iptables rule에 의해 대상 Pod로 트래픽을 전달함
어떤 노드의 speaker Pod를 리더로 선정할지 결정하기 위해 ARP를 사용함. 장애 시에도 다른 speaker pod를 리더로 선정하기 위해 ARP를 사용
speaker Pod는 호스트의 네트워크 네임스페이스를 공유해서 사용함
각 노드에 speaker Pod를 배포하는 이유는 서비스 하나만 사용할 것이 아니고, 다수의 서비스를 사용할 때 트래픽의 부담을 분담하기 위함
그럼에도 특정 서비스에 트래픽이 집중 된다면 해당 노드만 부하를 받을 수 있는 Risk가 있음
리더 노드로 트래픽이 집중되는 부분은 ECMP를 사용하여 부하 분산을 할 수는 있지만 리더 노드의 장애 시 ARP를 통해 다시 리더를 선출하고 MetalLB가 동작하게 되기 까지 1분정도 소요될 수 있기 때문에 ARP 모드 보다는 BGP 모드를 사용할 것을 권장
ExternalIP로 사용할 IP 범위를 지정 한 후 LoadBalancer 유형으로 Service를 생성해보면 아래와 같이 External-IP를 할당 받은 것을 확인할 수 있음
아래와 같이 서비스의 이벤트 항목을 보면 리더로 선정된 노드의 IP가 기록된 것을 확인할 수 있음
이벤트 기록과 같이 IP가 Assigned되었다고 layer2로 다른 노드들에 announcing 하는 노드가 각각 다른 것을 볼 수 있음
이제 대상 서비스의 External IP로 curl 명령을 실행하여 접속하면 아래와 같이 리더 노드를 통해 정상적으로 응답을 수신하는 것을 확인할 수 있음
BGP 모드
클러스터 규모가 커지면 ARP를 사용할 경우 브로드캐스트에 대한 패킷량으로 인해 부하가 커질 수 있음
BGP는 브로드캐스트하지 않고 BGP 프로토콜을 사용하여 대상 노드로 ExternalIP 전파가 가능하기 때문에 효율적임
BGP 모드로 설정하면 회사의 내부 네트워크에 서비스의 External-IP가 등록됨
별도의 등록 없이 해당 IP로 통신할 수 있기 때문에 편리함
MetalLB는 규모가 큰 클러스터에 사용은 권장하지 않음
Cilium의 경우 자체적으로 MetalLB와 비슷한 소프트웨어 로드밸런서를 제공하고 있음
온프레미스에서 대규모 클러스터를 운영할 경우에는 하드웨어 로드밸런서 장비를 사용할 것을 권장
failover의 경우에도 BGP는 1초 이내로 즉시 수행됨
BGP 모드에서 Service의 ExternalTrafficPolicy 설정을 Local로 하게 되면 Pod가 존재하는 노드의 IP만 등록되고, SNAT 없이 통신이 가능하기 때문에 클라이언트의 IP를 보존할 수 있음
IPVS
iptables이 랜덤 부하분산이었다면, IPVS는 부하분산 알고리즘을 선택해서 사용할 수 있음
IPVS를 활성화하면 모든 노드에 kube-ipvs라는 네트워크 인터페이스가 생성됨
위 그림에서는 kube-ipvs0 인터페이스에 두개의 IP가 할당되어 있는데 이 IP들이 현재 실행 중인 Service의 ClusterIP
ipvsadm 명령을 사용해서 부하분산에 대한 내용을 확인할 수 있음. 아래 그림에서 rr은 기본값인 라운드로빈 방식을 의미하고 설정된 알고리즘으로 그 하위에 있는 IP들로 부하 분산을 수행함
ipvsadm -Ln
IPVS도 넷필터를 사용하긴 하지만 기존에 부하 분산을 위해 iptables rule을 사용하는 것과 달리 IPVS 내에서 부하 분산을 관리하기 때문에 iptables rule이 확연히 줄어듦
선택할 수 있는 알고리즘들 중 주요 4가지는 아래와 같음
라운드로빈 : 목적지 Pod로 돌아가면서 순차적으로 전달
최소 연결 : 목적지 Pod의 connection 갯수가 가장 적은 곳을 우선해서 전달
목적지 해싱 : 목적지 IP 주소로 해시값을 계산하여 목적지 Pod에 전달
출발지 해싱 : 출발지 IP 주소로 해시값을 계산하여 목적지 Pod에 전달
Service를 생성하면 모든 노드에 kube-proxy에 의해 kube-ipvs0 네트워크 인터페이스에 서비스의 IP가 추가되고, 부하 분산에 대한 설정이 동일하게 적용됨
iptables에는 부하분산의 대상이 되는 IP들이 각각 rule로 작성되는 것이 아니라 ipset을 사용해서 규칙이 줄어듦
iptables -t nat -S ❘ grep KUBE-CLUSTER-IPipset list KUBE-CLUSTER-IP
댓글