MetalLB, ingress-nginx, Longhorn으로 네트워크와 스토리지 구성하기 (홈랩 k8s 구축기 3편)

munilive
munilive
MetalLB, ingress-nginx, Longhorn으로 네트워크와 스토리지 구성하기 (홈랩 k8s 구축기 3편)

지난 편에서 Ansible로 Kubernetes 클러스터를 구성했다. 클러스터는 올라왔지만, 이 상태로는 아무것도 할 수 없다. 외부에서 트래픽을 받는 방법도 없고, 데이터를 저장할 스토리지도 없다. 이번 편에서는 그 두 가지, 네트워크와 스토리지를 채우는 과정을 이야기 하겠다.

베어메탈 환경의 LoadBalancer

클라우드 환경에서는 LoadBalancer 타입 Service를 만들면 클라우드 공급자가 알아서 IP를 붙여준다. 하지만 베어메탈 환경에서는 그런 역할을 해주는 것이 없어서 LoadBalancer 타입 Service는 영원히 <pending> 상태에 머문다.

이 문제를 해결해주는 것이 MetalLB다. 홈 네트워크의 IP 대역에서 일부를 MetalLB에 넘겨두면, LoadBalancer Service가 생성될 때 그 풀에서 IP를 할당해준다. L2 모드로 설정했는데, ARP를 통해 해당 IP에 대한 요청을 특정 노드로 보내주는 방식이다.

IP 풀은 192.168.50.200~250으로 잡았다. 공유기의 DHCP 범위와 겹치지 않도록 미리 확인하고 설정했다.

helm install metallb metallb/metallb \
  -n metallb-system --create-namespace \
  -f kubernetes/system/metallb/values.yaml \
  --wait
kubectl apply -f kubernetes/system/metallb/resources/

ingress-nginx

ingress-nginx는 Ingress 리소스를 처리하는 컨트롤러다. 도메인에 따라 내부 Service로 요청을 라우팅해주는 역할을 한다. LoadBalancer 타입으로 배포하면 MetalLB가 IP를 할당해주고, 그 IP 하나로 여러 도메인의 트래픽을 받을 수 있다.

설치 후 ingress-nginx가 192.168.50.200을 External IP로 받아오는 것을 확인했다.

NAME                       TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)
ingress-nginx-controller   LoadBalancer   10.110.67.105   192.168.50.200   80:30909/TCP,443:32165/TCP

이 IP 하나를 공유기 DNS나 로컬 /etc/hosts에 원하는 도메인으로 등록해두면, 내부 서비스들에 도메인으로 접근할 수 있게 된다. Grafana, ArgoCD, Jenkins 같은 것들을 나중에 각자의 도메인으로 접근할 수 있는 것도 이 구성 덕분이다.

cert-manager

TLS 인증서를 자동으로 발급하고 갱신해주는 컴포넌트다. 지금 당장은 내부 전용으로만 쓰고 있어서 자체 서명 인증서를 사용하고 있는데, 나중에 Cloudflare Tunnel로 외부 서비스를 노출할 때 Let’s Encrypt 인증서를 자동 발급하도록 ClusterIssuer를 추가할 예정이다.

Longhorn

Kubernetes에서 퍼시스턴트 볼륨을 관리하는 것은 생각보다 손이 많이 가는 일이다. 클라우드 환경에서는 EBS나 Persistent Disk 같은 것이 있지만, 베어메탈에서는 직접 해결해야 한다.

Longhorn은 각 노드의 디스크를 묶어서 분산 블록 스토리지를 만들어주는 도구다. PVC를 생성하면 Longhorn이 노드 디스크에 볼륨을 만들고, 복제본을 여러 노드에 나눠 저장해서 한 노드가 죽어도 데이터가 남아있게 해준다. replica를 2로 설정했는데, 워커 노드가 2개니 각 볼륨이 두 노드에 복제된다.

설치는 Helm으로 진행했다.

helm install longhorn longhorn/longhorn \
  -n longhorn-system --create-namespace \
  -f kubernetes/system/longhorn/values.yaml \
  --wait --timeout 10m

Longhorn은 설치 전에 각 노드에 open-iscsinfs-common이 설치되어 있어야 한다. Ansible common role에 포함해두어서 클러스터 구성 시 자동으로 설치된다.

시크릿 관리 — Sealed Secrets

클러스터를 운영하다 보면 DB 비밀번호, API 키 같은 시크릿을 어딘가에 관리해야 한다. Kubernetes Secret을 그대로 Git에 올리면 Base64로 인코딩되어 있을 뿐 사실상 평문이나 다름없다.

Sealed Secrets는 이 문제를 해결해준다. kubeseal CLI로 시크릿을 암호화하면 SealedSecret이라는 리소스가 만들어지는데, 이건 해당 클러스터의 키로만 복호화할 수 있다. Git에 올려도 안전하고, ArgoCD로 자동 배포도 가능해진다.

helm install sealed-secrets sealed-secrets/sealed-secrets \
  -n kube-system \
  -f kubernetes/system/sealed-secrets/values.yaml

시크릿을 만들 때는 이런 방식으로 사용한다.

kubectl create secret generic my-secret \
  --from-literal=password=mysecretpassword \
  --dry-run=client -o yaml \
| kubeseal --controller-namespace kube-system \
           --controller-name sealed-secrets \
           --format yaml \
> my-sealed-secret.yaml

여기까지 오면

MetalLB, ingress-nginx, Longhorn, Sealed Secrets까지 올라오면 클러스터 위에 실제 서비스를 올릴 기반이 거의 갖춰진다. 로드밸런서가 있고, 트래픽을 도메인으로 라우팅할 수 있고, 데이터를 저장할 수 있고, 시크릿을 안전하게 관리할 수 있다.

다음 편에서는 CI/CD 파이프라인을 구성하는 과정을 이야기 하겠다.

munilive

munilive

Backend Application Developer

Share

Comments

Related Posts

Ansible로 Kubernetes 클러스터를 코드 한 줄로 (홈랩 k8s 구축기 2편)

Ansible로 Kubernetes 클러스터를 코드 한 줄로 (홈랩 k8s 구축기 2편)

지난 편에서 Terraform으로 VM 3개를 만들었다. 이번에는 그 VM들 위에 Kubernetes 클러스터를 올리는 과정이다. kubeadm으로 클러스터를 직접 구성하고, 그…

munilive munilive ·
집에 Kubernetes 클러스터를 구축해 봤습니다

집에 Kubernetes 클러스터를 구축해 봤습니다

퇴근하고 집에 돌아와 미니 PC 한 대를 책상 위에 올려두고는 여기다가 Kubernetes 클러스터를 직접 구축해 보겠다고 마음먹은 게 몇 달 전이었다. 그리고 지금, 그 미니 P…

munilive munilive ·
Proxmox 설치부터 Terraform으로 VM 찍어내기까지 (홈랩 k8s 구축기 1편)

Proxmox 설치부터 Terraform으로 VM 찍어내기까지 (홈랩 k8s 구축기 1편)

집에 Kubernetes 클러스터를 구축해 봤습니다에서 전체 구성과 삽질의 개요를 간략하게 정리했다. 이번 편부터는 각 단계를 좀 더 구체적으로 풀어볼 생각이다. 1편의 주제는 P…

munilive munilive ·