Container Orchestration/Kubernetes

MetalLB란?

Somaz 2023. 5. 3. 20:51
728x90
반응형

Overview

오늘은 Bare-Metal에서 많이 사용하는 LoadBalancer인 MetalLB에 대해서 공부해보려고 한다.

https://devops.cisel.ch/deploy-metallb-as-an-on-prem-load-balancer-for-your-kubernetes-services

 

 

 


 

MetalLB란?

Kubernetes 사용 시 AWS, GCP, Azure 와 같은 클라우드 플랫폼에서는 자체적으로 로드 벨런서(Load Balancer)를 제공해 주지만, 온프레미스 클러스터에서는 로드 벨런싱 기능을 제공하는 모듈을 추가적으로 설치해야 한다.

MetalLB는 MetalLB는 BareMetalLoadBalancer 약자로 베어메탈 환경에서 사용할 수 있는 로드 벨런서를 제공하는 오픈소스 프로젝트이다. 클라우드 환경의 서비스(로드밸런서 타입)와는 동작이 조금 다르다.
 
서비스(로드 밸런서)의 External IP 전파를 위해서 표준 프로토콜인 ARP(IPv4)/NDP(IPv6), BGP 를 사용한다
데몬셋으로 speaker 파드를 생성하여 External IP 전파한다.
 

https://mlops-for-all.github.io/docs/appendix/metallb/

 

 

 


 

MetalLB Mode

 


 

 

Layer 2 Mode

출처 : Cloudnet@ 스터디

 
서비스(로드밸런서) 'External IP' 생성 시 speaker 파드 중 1개리더가 되고, 리더 speaker 파드가 존재하는 노드로 서비스 접속 트래픽이 인입되게 된다

  • 데몬셋으로 배포된 speaker 파드는 호스트 네트워크를 사용한다 ⇒ "NetworkMode": "host"

리더는 ARP(GARP, Gratuitous APR)로 해당 'External IP' 에 대해서 자신이 소유라며 동일 네트워크에 전파를 한다
 
만약 리더(노드)가 장애 발생 시 자동으로 나머지 speaker 파드 중 1개가 리더가 된다.

  • 멤버 리스터 및 장애 발견은 hashicorp 의 memberlist 를 사용 - Gossip based membership and failure detection

Layer 2에서 멤버 발견 및 자동 절체에 Keepalived(VRRP)도 있지만 사용하지 않은 이유는 아래 링크에 있다.

  • 링크

 

 


 

BGP Mode

출처 : Cloudnet@ 스터디

 
speaker 파드에 BGP 가 동작하여 서비스 정보(EXTERNAL-IP)를 전파한다

  • 기본은 IP주소(32bit)를 전파하며, 설정으로 축약된 네트워크 정보를 전파할 수 있다 → bgp-advertisements 에 aggregation-length 설정
  • BGP 커뮤니티, localpref 등 BGP 관련 설정을 할 수 있다
  • IP 주소 마지막이 0 과 255 를 처리를 못하는 라우터 장비가 있을 경우 avoid-buggy-ips: true 옵션으로 할당되지 않게 할 수 있다

 
외부 클라이언트에서 SVC(서비스, EXTERNAL-IP)로 접속이 가능하며, 라우터에서 ECMP 라우팅을 통해 부하 분산 접속 할 수 있다

  • 일반적으로 ECMP 는 5-tuple(프로토콜, 출발지IP, 목적지IP, 출발지Port, 목적지Port) 기준으로 동작한다.
  • 물론 라우터 장비에 따라 다양한 라우팅(분산) 처리가 가능하다

 

 


 

MetalLB 설치

 
설치 방법 지원 : Kubernetes manifests, using Kustomize, or using Helm

kubectl edit configmap -n kube-system kube-proxy
...
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
  strictARP: true
  
# or

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

# 재시작
k rollout restart -n kube-system daemonset kube-proxy

 

 

 


 

 

Install With Helm

helm repo add metallb https://metallb.github.io/metallb
helm install metallb metallb/metallb -n metallb-system --create-namespace

# example
helm install -n <네임스페이스> <릴리즈 이름> -f <브랜치별 helm values 파일명>.yaml metallb/metallb

# helm으로 설치할 때는 memberlist 필요없다. 자동으로 설치됨.
k get secret -n metallb-system
NAME                            TYPE                 DATA   AGE
metallb-memberlist              Opaque               1      2d
metallb-webhook-cert            Opaque               4      2d
sh.helm.release.v1.metallb.v1   helm.sh/release.v1   1      2d

 

 

metallb config 설정한다.

# metallb config 설정
cat <<EOF >> metallb-config.yaml
# 사용 apiversion
apiVersion: metallb.io/v1beta1 
kind: IPAddressPool
metadata:
  name: ip-pool
  namespace: metallb-system
spec:
  addresses:
  # 사용할 ip address pool
  - 143.92.123.123-143.92.123.123
  autoAssign: true
--- 
apiVersion: metallb.io/v1beta1 
# metalib의 l2모드를 사용한다.
kind: L2Advertisement 
metadata:
  name: l2-network
  namespace: metallb-system
spec:
   # 사용할 ipAddressPools
  ipAddressPools:
    - ip-pool
EOF

 

 

기존설정 삭제 후에 ipaddresspool 확인한다.

# 설정 확인
kubectl get validatingwebhookconfigurations

# 기존설정 삭제
kubectl delete validatingwebhookconfigurations  metallb-webhook-configuration

# 삭제 확인 (no resource found가 나와야 한다.)
kubectl get validatingwebhookconfigurations

# 설정 적용
k apply -f metallb-config.yaml -n metallb-system

# 최종 확인
kubectl describe ipaddresspool.metallb.io --namespace metallb-system

# ipaddresspool 확인
Name:         ip-pool
Namespace:    metallb-system
Labels:       <none>
Annotations:  <none>
API Version:  metallb.io/v1beta1
Kind:         IPAddressPool
Metadata:
  Creation Timestamp:  2024-05-29T08:10:22Z
  Generation:          1
  Managed Fields:
    API Version:  metallb.io/v1beta1
    Fields Type:  FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .:
          f:kubectl.kubernetes.io/last-applied-configuration:
      f:spec:
        .:
        f:addresses:
        f:autoAssign:
        f:avoidBuggyIPs:
    Manager:         kubectl-client-side-apply
    Operation:       Update
    Time:            2024-05-29T08:10:22Z
  Resource Version:  742627
  UID:               358e924f-c935-431c-a4a0-46788c4a1392
Spec:
  Addresses:
    ex. 192.168.10.10 - 192.168.10.20
  Auto Assign:       true
  Avoid Buggy I Ps:  false
Events:              <none>

 

 

 


 

 

Install By Manifest

 
Manifest를 통해 설치한다. 
다만 해당 파일의 native에는 모든 resource가 전부 다들어가있는 것 같다.
따라서 MetalLB의 github를 보고 필요한 리소스를 설치하는 것이 좋아보인다.

curl -O https://raw.githubusercontent.com/metallb/metallb/v0.13.9/config/manifests/metallb-native.yaml
kubectl apply -f metallb-native.yaml -n metallb-system

# If you want to deploy MetalLB using the FRR mode, apply the manifests
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.9/config/manifests/metallb-frr.yaml

 
memberlist secret을 만들어서 스피커간의 통신을 암호화한다.

kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)" -o yaml > metallb-secret.yaml

cat metallb-secret.yaml
apiVersion: v1
data:
  secretkey: bmRzd3hQSWZDUX...
kind: Secret
metadata:
  creationTimestamp: null
  name: memberlist
  namespace: metallb-system
  
kubectl apply -f metallb-secret.yaml -n metallb-system

 
memberlist secret이 없으면 아래와 같이 Error가 발생한다.

{"branch":"HEAD","caller":"main.go:138","commit":"v0.10.2","goversion":"gc / go1.16.5 / arm","msg":"MetalLB controller starting version 0.10.2 (commit v0.10.2, branch HEAD)","ts":"2021-06-14T10:07:51.113257418Z","version":"0.10.2"}
{"caller":"main.go:173","error":"Get \"https://10.96.0.1:443/api/v1/namespaces/metallb-system/secrets?fieldSelector=metadata.name%3Dmemberlist\": dial tcp 10.96.0.1:443: i/o timeout","msg":"failed to create memberlist secret","op":"startup","ts":"2021-06-14T10:08:21.120420776Z"}

 

MetalLB 구성

 

metalLB는 configmap을 전달하기 전까지 유휴상태이다.

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: metallb-ip-range
      protocol: layer2
      addresses:
      - <ip range start> - <ip range End> 
      ex. 192.168.10.10 - 192.168.10.20
      ex. 10.10.100.26 - 10.10.100.26
      - <ip range 대역대> 
      ex. 192.168.10.0/24

 

구성을 완료하면 아래와 같이 MetalLB pod가 정상적으로 Running된다

$ k get po -n metallb-system -o wide
NAME                         READY   STATUS    RESTARTS      AGE    IP             NODE      NOMINATED NODE   READINESS GATES
controller-f54fbc6f9-pxgqv   1/1     Running   2 (97d ago)   365d   10.233.70.84   node5     <none>           <none>
speaker-5xqc9                1/1     Running   2 (98d ago)   365d   10.10.100.24   node4     <none>           <none>
speaker-cxzgx                1/1     Running   2 (97d ago)   365d   10.10.100.25   node5     <none>           <none>
speaker-dn6mg                1/1     Running   1             365d   10.10.100.20   master0   <none>           <none>
speaker-m2psn                1/1     Running   3 (97d ago)   365d   10.10.100.22   node2     <none>           <none>
speaker-nhxms                1/1     Running   2 (97d ago)   365d   10.10.100.23   node3     <none>           <none>
speaker-zt72w                1/1     Running   2 (97d ago)   365d   10.10.100.21   node1     <none>           <none>
  • MetalLB의 Speaker의 IP는 Node의 IP를 가지게 된다.

 


마지막으로 저는 MetalLB Service는 배포하지 않았습니다. 그 이유는 ingress-nginx-controller를 사용할 것이고 MetalLB는 LoadBalancer Type을 위한 설치이다.

 

 

 


 

 

MetalLB 구성 아키텍처 다이어그램

+------------------+        +------------------+
| Kubernetes svc   | -----> | MetalLB Speaker  |  (Layer2/BGP 선택)
+------------------+        +------------------+
                                   |
+------------------+        +------------------+
| Kubernetes Node  |<------>| Physical Network |
+------------------+        +------------------+

 

 

 

MetalLB + Ingress-Nginx 연동 구조도

+------------------+
| Client           |
+------------------+
          |
+------------------+
| MetalLB External IP (L2/BGP) |
+------------------+
          |
+------------------+
| Ingress-Nginx Service (LoadBalancer) |
+------------------+
          |
+------------------+
| Target Pod       |
+------------------+

 

 

 

실전 트러블슈팅 사례

문제 유형 증상  해결 방법
External IP 미할당 서비스 생성해도 `EXTERNAL-IP` 없거나 Pending MetalLB Config 확인, strictARP 누락 확인
트래픽 한쪽으로 쏠림 특정 노드만 트래픽 수신 Layer2 환경에서 ARP Conflict 여부 확인
BGP 세션 불안정 BGP 모드인데 Peer 세션 지속 끊김 라우터 BGP 설정 확인, BGP Timer 튜닝
Service 접근 불가 External IP는 있는데 서비스 응답 없음 인그레스 Controller 정상 기동 여부 확인

 

 

 

 

 


 

마무리

다음시간에는 Ingress-Nginx에 대해 공부해보려고 합니다. 잘 설치가 된다면 아래와 같은 모습이 된다.

k get po,svc -n ingress-nginx
NAME                                            READY   STATUS      RESTARTS      AGE
pod/ingress-nginx-admission-patch-s6zwc         0/1     Completed   2             365d
pod/ingress-nginx-controller-75f58fbf6b-qph5z   1/1     Running     5 (97d ago)   365d

NAME                                         TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)                      AGE
service/ingress-nginx-controller             LoadBalancer   10.233.10.100   10.10.100.26   80:31500/TCP,443:31158/TCP   365d
service/ingress-nginx-controller-admission   ClusterIP      10.233.39.214   <none>         443/TCP                      365d
  • 10.10.100.26 이 MetalLB의 IP입니다. Config 파일에 작성해주는 IP요!

 

 


Reference

MetalLB 공식사이트
 
https://devops.cisel.ch/deploy-metallb-as-an-on-prem-load-balancer-for-your-kubernetes-services
 
https://mlops-for-all.github.io/docs/appendix/metallb/
 
https://mydevjourney.tistory.com/96

728x90
반응형