반응형

 

MetalLB v0.13.x  설치 및 테스트 (2023년 2월 14일)

MetalLB의 버전에 따라 설치 결과가 조금씩 달라서 MetalLB를 설치한 날짜를 밝힌다.

아래 절차를 따라하면 MetalLB 설치, 그리고 예제 앱 테스트 모두 잘 동작한다.

 

 

MetalLB 설치에 관한 공식 문서는 아래 Web Docs를 참고
   https://metallb.universe.tf/installation/

 

 

위 Web Docs는 여러 도구를 이용한 설치 방법을 설명하지만, 나는 Manifest  방식을 이용하여 MetalLB를 설치했다.

위 Web docs를 보면서 따라해보면, 막힘없이 쭉쭉~ 잘 설치되었다.

설치 완료한 이후에 LB 테스트를 해봤는데 잘 동작했다.

내가 설치한 환경은 이렇다.


Kubernetes: v1.25.3
CNI: Calico v3.24.5

 

내가 Web docs를 보면서 수행했던 명령 및 설정 파일 편집한 내역만 추려보면 이렇다.

 

strict ARP mode 활성화하기

아래 예제처럼 kube-proxy  configmap을 수정한다. 

(strictARP 항목을 false 에서 true 로 변경)

## 아래 명령을 수행
$  kubectl edit configmap -n kube-system kube-proxy

... 중간 생략 ...

apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
  strictARP: true  ## 이 부분을 수정한다.  false -> true

... 중간 생략 ...

 

Manifest 이용하여 Metal LB 설치하기

아래 명령을 따라서 수행한다.

$  kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.7/config/manifests/metallb-native.yaml


##
## MetalLB가 잘 설치되었다면,
## 아래와 같이 metallb-controller와 metallb-speaker pod가 Running 상태로 보일 것이다.
##

$  kubectl get -n metallb-system pod
NAME                          READY   STATUS    RESTARTS   AGE
controller-84d6d4db45-g94mh   1/1     Running   0          31s
speaker-6jqzw                 1/1     Running   0          31s
speaker-hlrg7                 1/1     Running   0          31s
speaker-sq94q                 1/1     Running   0          31s


## 참고: speaker가 running 상태가 되려면 대략 25~30초 정도 걸린다.
##      Pod의 상태가 ConfigErr로 보인다고 당황해하지 않아도 된다.
##      30초 후에 Running 상태로 변경될거다.

 

IP Address Pool 설정하기

$  cat >> my-network.yaml <<-EOF

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: first-pool
  namespace: metallb-system
spec:
  addresses:
  - 10.1.4.160/28
  - 10.1.4.176/28
  - 10.1.4.192-10.1.4.200

---

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: second-pool
  namespace: metallb-system
spec:
  addresses:
  - 10.1.4.150-10.1.4.159


---


apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: my-network-l2
  namespace: metallb-system
spec:
  ipAddressPools:
  - first-pool
  - second-pool
  
EOF

$  kubectl apply -n metallb-system -f my-network.yaml

ipaddresspool.metallb.io/first-pool created
ipaddresspool.metallb.io/second-pool created
l2advertisement.metallb.io/my-network-l2 created

$

 

 

주의할 점:
  위와 같이 L2Advertisement, IPAddressPool을 변경하고 적용해도 실제로 Service resource가 생성될 때,
  과거의 IPAddressPool을 이용한다.
  아마 MetalLB  버그 같은데, 과감하게 metallb-system 네임스페이스의 controller pod를 종료시키고 재기동하면 
  새로운 IPAddressPool이 적용된다. (아래 명령을 참고)

 

$ kubectl get -n metallb-system pod -l component=controller

NAME                          READY   STATUS    RESTARTS   AGE
controller-84d6d4db45-vgt9r   1/1     Running   0          6m12s

$ kubectl delete -n metallb-system pod controller-84d6d4db45-vgt9r

## 20초 정도 후에 Pod가 재기동되고, 그 뒤로 새로운 IPAddressPool이 정상적으로 반영된다.

 

 

 

Example App을 이용하여 MetalLB 동작 확인

$  cat >> my-example.yaml <<-EOF
apiVersion: v1
kind: Pod
metadata:
  name: almighty
  labels:
    app: almighty
spec:
  terminationGracePeriodSeconds: 3
  containers:
  - name: almighty
    image: docker.io/andrewloyolajeong/almighty:0.2.4

---

apiVersion: v1
kind: Service
metadata:
  name: almighty
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local
  selector:
    app: almighty
  ports:
    - name: myweb
      protocol: TCP
      port: 8080
      targetPort: 8080
    - name: yourweb
      protocol: TCP
      port: 80
      targetPort: 80

EOF

$

$  kubectl create ns ns1


$  kubectl apply -n ns1 -f my-example.yaml


$  kubectl get -n ns1 svc

NAME       TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                       AGE
almighty   LoadBalancer   10.104.156.217   10.1.4.150    8080:30859/TCP,80:31917/TCP   116s

$

##
## 위 결과에서 EXTERNAL-IP에 적절한 IP Address가 출력되면, 잘 되는 것이다.
## 그리고 아래와 같이 실제로 MetalLB가 할당해준 10.1.4.150 주소를 통해 Networking이 되는지 확인한다.
##

$  curl 10.1.4.150:8080

 Hello from example application. (written by Andrew)
 
$  curl 10.1.4.150:80

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
...
...
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

$

 

올레~~~ 잘 동작한다 ^^

 

 

 

 


 

 

참고:  ping 명령으로 EXTERNAL-IP 통신 여부를 확인하지 말 것 !!!

MetalLB 설치하고, 많은 사용자들이 실수하는 것이 아래처럼 ping 명령으로 External-IP로 ICMP 패킷이 전달되는지 체크한다.

$ ping 10.10.12.43

MetalLB가 만든 External-IP 주소는 K8S Cluster의 특정 Worker Node의 Netfilter에만 존재하는 Chain Rule일 뿐이다.

즉, OS Kernel이 물린 Network Port의 MAC Address에 Binding한 IP Address가 아니다보니, OS Kernel이 ICMP Echo Request에 대해 반응할리 없다. 단, K8s LoadBalancer 구현체(즉, MetalLB)의 구현에 따라서 MetalLB가 직접 ICMP Echo Response를 만들 수는 있지만, 이것은 구현체의 버전에 따라 다를 수 있으니까 ICMP Echo(즉, Ping)에 대한 테스트를 시도하지 않는 것이 좋다.

아래와 같이 CURL을 이용하여 테스트하는 것이 정확한 테스트 방법이다.

$ curl  https://10.10.12.43:8443

다시 한번 강조한다.  절대 ping 명령으로 MetalLB의 External-IP 동작 유무를 체크하지 말자 !!!

 

 

 

 

참고:  Address 설정은  모든 대역의 주소가 다 가능한다.

아래 설정 예제처럼 특정 addresses 대역을 사용하겠다고 지정하면, MetalLB Speaker가 알아서 동일한 Broadcast Domain에 해당하는 Network Port로 GARP(Gratuitous ARP)를  Broadcasting한다.

 

$  vi metallb/values.yaml
... 중간 생략 ...
configInline:
  address-pools:
   - name: default
     protocol: layer2
     addresses:
     - 10.10.12.40/29
... 중간 생략 ...

따라서 Worker Node에 Network Port가 여러 개 있다면, 위 address-pools에 설정된 ip address 대역 중에서 broadcast domain이 일치하는 Network Port로 GARP 패킷이 흘러나간다.

 

 

 

참고:  특정 Service에 특정 External-IP(Public IP)를 고정해서 사용하기

External-IP는 Kubernetes Cluster 밖에 있는 Client App이 접근하기 위한 주소이기 때문에 고정하는게 운영상 편하다.

그런데 MetalLB는 IP Address Range를 설정하도록 되어 있기 때문에 K8s Service 생성시 어떤 External-IP가 K8s Service에 할당될지 알 수 없다.

이럴 때 아래와 같이 K8s Service에 설정을 추가하면 특정 External-IP(즉, Public IP Address)를 고정해서 사용할 수 있다.

 

$ cat  my-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: mysvc
  
(... 중간 생략 ...)

spec:
  type: LoadBalancer
  ## MetalLB의 IP Address Range가 211.10.3.160 ~ 190 이라고 가정하고
  ## 이 mysvc에 211.10.3.165 주소를 고정해서 사용하고 싶아면 아래와 같이 사용한다.
  loadBalancerIP: 211.10.3.165

(... 중간 생략 ...)

 

 

게시물 작성자: sejong.jeonjo@gmail.com

 

 

+ Recent posts