[쿠버네티스] Minikube + MetalLB 셋팅 자동화하기

humblEgo·2020년 8월 1일
5
post-thumbnail

들어가며

아래 내용은 42seoul 과제 중 Ft_services 의 요구사항인 'MetalLB를 활용하여 kubernetes 외부접근 관리'를, minikube 환경에서 구현하기 위해 학습한 내용을 정리한 것입니다.
부정확한 내용이 있으면 댓글 남겨주시면 감사히 배우겠습니다.

Why MetalLB?

—> bareMetal 환경에서 LoadBalancer type의 서비스를 만들기 위해 씁니다.

그럼 왜 metalLB을 쓰게 되었느냐! 그건 사실 과제에서 클라우드 없이 LoadBalancer type의 서비스를 구현하라고 요구했기 때문(!)인데 아래 과정을 거쳤습니다.

  • Pod는 휘발성을 가지므로 고정된 엔드포인트를 자체적으로 가지기 힘들다.
    Kubernetes의 Pod는 상황에 따라 소멸-재생성을 반복하게 됩니다. 문제는 이 때마다 지정되는 IP가 바뀌어 엔드포인트로 호출이 어렵습니다. 또한 여러 Pod에 같은 애플리케이션을 운용할 때 어느 Pod로 트래픽을 보낼지 결정해주는 로드밸런싱 기능이 필요합니다.

  • Service가 고정된 IP로 Pod에 접근할 수 있게 해준다.
    Kubernetes에서는 Service가 Pod의 한계를 보완해주는 역할을 합니다. Service는 4개의 Type-ClusterIP, NodePort, LoadBalancer, ExternalName-으로 나누어져있습니다. 각 타입별로 네트워크 구성이 달라집니다.
    상용 서비스에서 외부로 IP를 노출시킬 때는 LoadBalancer Type을 주로 쓴다고 합니다. 여기를 참고하시면 이해가 쉽습니다. 더 상세한 설명은 여기를 참고하세용.

  • Service type 중 LoadBalancer type을 쓰려면 External IP를 만들어줘야한다.
    LoadBalancer type을 쓰려면 로드밸런서에 외부에서 접근가능한 External IP(외부 IP)를 만들어줘야합니다. 기존에는 이 LoadBalancer Type의 Kubernetes Service 객체를 만들려면 클라우드 공급자(ex IBM 클라우드, AWS, GCP 등)가 제공해주는 IP를 써야했습니다. 이 IP가 없으면 External IP에 영원히 pending이라고 찍혀있는 것을 봐야했습니다. 영원히.. 그럼 만약 클라우드 서비스를 못쓰는 환경이라면 어떻게 해야할까요?

  • MetalLB를 활용하면 클라우드 공급자에서 실행되지 않는 클러스터에서도 External IP를 할당할 수 있고, 결과적으로 LoadBalancer Type의 Service 객체를 만들 수 있습니다. 이름부터 BareMetal LoadBalancer..!

1) Install MetalLB

공식 홈페이지에 설명되어있는 것을 그대로 따라가면 됩니다. 저는 Manifest를 통해 설치했습니다.

아래 명령어를 입력하시면 됩니다!

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/namespace.yaml
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/metallb.yaml
# On first install only
kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"

명령어를 간략히 설명드리자면 아래와 같습니다.

  • kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/namespace.yaml
    이 명령어는 아래 내용의 yaml 파일을 kubectl에 전달합니다. 전달하고 나면 metallb-system 네임스페이스로 엮인 MetalLB가 클러스터에 배포됩니다.
  apiVersion: v1
  kind: Namespace
  metadata:
    name: metallb-system
    labels:
      app: metallb
  • kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/metallb.yaml

    이 명령어도 마찬가지로 링크된 yaml 파일을 kubectl에 전달합니다. 전달하고 나면 metalLB controller와 metalLB speaker가 생성됩니다.

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

    이 명령어는 memberlist secret을 만들어서 스피커간의 통신을 암호화한다고 합니다.

2) Setting MetalLB

metalLB는 configmap을 전달하기 전까지 유휴상태로 남아있습니다. 주의할 것은, 앞서 설치한 metalLB와 같은 네임스페이스(이 포스팅예제에서는 metallb-system)로 만들어줘야한다는 것입니다. Helm을 이용하시는 분들은 이 네임스페이스를 수동으로 맞춰줘야한다고 하네요.

MetalLB를 셋팅할 때는 사용할 프로토콜에 따라서 종류가 나뉩니다.

  • Layer 2 configuration
  • BGP configuration
  • Advanced configuration

이 중 Layer 2 설정은 가장 심플하지만, 노드 하나가 트래픽을 일단 다 받으며 로드밸런싱을 한다음 서비스에 연결된 모든 포드로 트래픽을 분산시키는 방식이라는 특징을 가지고 있습니다. 어차피 minikube를 쓸거라서 노드가 하나라는 점, 어차피 트래픽이 큰 실제 서비스를 돌리는게 아니라 과제제출용이라는 점을 감안해서 Layer 2 configuration을 선택했습니다.

설정은 간단합니다.

  1. 먼저 아래 내용의 configmap 파일을 만듭니다. 저는 metallb-config.yaml 이라는 이름으로 만들었습니다.
   apiVersion: v1
   kind: ConfigMap
   metadata:
     namespace: metallb-system
     name: config
   data:
     config: |
       address-pools:
       - name: default
         protocol: layer2
         addresses:
         - 192.168.99.100-192.168.99.110         #Host IP 대역에 맞추어 작성해야합니다!

이 때 addresses는 metalLB가 제대로 설정해주셔야합니다. 공식홈페이지 예제를 따라하시면 안되고, Host IP 대역에 맞추어서 작성해주셔야합니다.

저처럼 minikube로 노드를 만든 경우에는 minikube IP를 입력하면 Host IP를 확인할 수 있습니다. 192.168.99.100이 나와서 일단 위처럼 설정해보았습니다.

  1. kubectl apply -f metallb-config.yaml 명령어로 configmap을 생성해줍니다.

  2. kubectl get svc 명령어로 아래처럼 서비스별로 External IP가 잘 할당되었는지 확인합니다. External IP와 Port를 주소창에 치면 접근이 가능해야합니다.

    https://user-images.githubusercontent.com/54612343/89098462-d07c3900-d422-11ea-9d22-f5777c4d2234.png

3) 자동화 with shell

이제 위 과정을 shell로 자동화해보려고 했는데, 경우에 따라 External IP로 잘 접근되었다가 말았다가 해서 고민이었습니다. 알고보니 minikube IP가 계속 바뀌어서 metalLB에서 설정한 IP range와 괴리가 생겨서 발생한 이슈인 것 같았습니다.

minikube IP는 minikube VM이 무엇인가에 따라, minikube VM을 쓰지 않는다면 host 컴퓨터의 네트워크 환경에 따라 결정됩니다. 가령 minikube VM을 만들 때 minikube start 명령어만 치면 default로 설정된 docker driver로 minikube VM을 만듭니다. 이 경우엔 [172.17.0.xxx](http://172.17.0.xxx)minikube IP가 설정되곤 합니다. 그리고 저처럼 minikube start --vm-driver=virtualbox 옵션으로 시작시키면 192.168.99.xxxminikube IP가 설정되는 식입니다. host IP가 바뀌었는데 metalLB의 configmap yaml 파일에 addresses 범위가 다른 대역으로 설정되어있다면 External IP가 생성되더라도 제대로 작동하지 않습니다.

이 문제를 해결할 다른 세련된 방법이 분명히 있겠지만..! 저는 아래처럼 해결했습니다.

1) 아래처럼 metallb-config_format.yaml 을 만든 다음

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - MINIKUBE_IP/24

2) minikube ip 명령어로 생성된 minikube IP 를 확인한 뒤 , 이를 환경변수로 만들고
3) 이 환경변수를 addresses 에 삽입한 metallb-config.yaml 파일을 따로 생성한 뒤
4) metallb-config.yaml파일로 configmap을 만들어보았습니다.

결과적으로 아래 내용대로 setup-metalLB.sh 을 작성하여 활용할 수 있었습니다.

# 이미 minikube가 start되어 minikubeIP가 생성되었음을 가정합니다.
# LOG_PATH는 지워버리거나 임의로 설정하시면 됩니다. 예를들어 /dev/null로 설정해서 버려도됨.
echo "Setup metalLB..."

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/namespace.yaml >> $LOG_PATH
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/metallb.yaml >> $LOG_PATH
# On first install only
kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)" >> $LOG_PATH

cd metallb
MINIKUBE_IP=$(minikube ip)
sed "s/MINIKUBE_IP/$MINIKUBE_IP/g" yaml/metallb-config_format.yaml > ./yaml/metallb-config.yaml
kubectl apply -f yaml/metallb-config.yaml >> $LOG_PATH

echo "Finish metalLB setup"

참고1

참고2

참고3

참고4

참고5

참고6

profile
자기전에 뿌듯한 하루를 추구합니다. @42seoul

1개의 댓글

comment-user-thumbnail
2020년 11월 16일

지금 많이 헤매고 있는데 도움이 많이 되었습니다 감사해요!

답글 달기