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

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

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

왜 홈랩인가

클라우드를 쓰면 되는 시대에 굳이 집에 서버를 두는 이유가 뭐냐고 물어볼 수 있다. 사실 나도 처음엔 그렇게 생각했다.

그런데 막상 개인 프로젝트를 이것저것 운영하다 보니 클라우드 비용이 슬금슬금 쌓이기 시작했다. DB 하나, 캐시 하나, 메시지 브로커 하나, 이것저것 붙이다 보면 어느새 매달 적지 않은 비용이 청구된다. 쓰지도 않는 시간에도 꼬박꼬박 나가는 비용이 아깝다는 생각이 들기 시작했다. 거기다 솔직히 말하면, Kubernetes를 업무에서 쓰기는 하지만 직접 처음부터 클러스터를 만들어본 적이 없었다. 누군가 이미 구성해둔 클러스터 위에서 배포만 해왔다는 게 왠지 찜찜했다. “내가 정말 이걸 안다고 할 수 있나?” 하는 물음이 계속 머릿속에 남아있었던 것 같다.

홈랩은 그 두 가지 고민을 한 번에 해결할 수 있는 방법이었다.

하드웨어 선택

서버로 쓸 장비를 고를 때 가장 중요하게 생각한 조건은 세 가지였다. 조용해야 하고(집에서 24시간 켜두려면 팬 소음이 문제다), 전기를 적게 먹어야 하며, 그러면서도 Kubernetes 클러스터를 돌릴 만큼은 강해야 한다는 것이었다.

그렇게 선택한 것이 ASRock DeskMini X600이다. Ryzen 7 8700G(8코어), DDR5 32GB, 1TB NVMe로 구성했다. 성인 주먹 두 개 크기의 미니 PC치고는 꽤 강력한 사양이다. 나중에 워커 노드로 쓸 장비도 추가할 생각이지만, 당장은 이 한 대 위에 VM 3개를 띄워서 Control Plane 1개, Worker 2개로 구성했다.

전체 구성

몇 달에 걸쳐 구축하면서 결국 아래와 같은 스택이 됐다.

레이어도구
가상화Proxmox VE
VM 프로비저닝Terraform
k8s 구성 자동화Ansible
k8s 배포kubeadm
CNIFlannel
로드밸런서MetalLB
Ingressingress-nginx
스토리지Longhorn
GitOpsArgoCD
CIJenkins
이미지 레지스트리Harbor
모니터링Prometheus + Grafana + Loki
시크릿 관리Sealed Secrets
보안 감사Kyverno + kube-bench
외부 접근Tailscale VPN

한눈에 봐도 꽤 많다. 처음부터 이렇게 다 할 생각은 아니었는데, 하나를 붙이면 그 다음에 필요한 것이 생기고, 그걸 붙이면 또 다음 것이 보이는 식으로 하다 보니 이 지경이 됐다. (그래도 배운 것도 그만큼 많았다.)

삽질의 기록

솔직히 말하면, 처음부터 제대로 된 건 거의 없었다.

Terraform Provider SSH 인증 문제

Terraform으로 VM을 프로비저닝할 때 bpg/proxmox provider가 클라우드 이미지를 Proxmox에 임포트하기 위해 SSH로 접속한다. 평소에 1Password SSH 에이전트를 쓰고 있어서 당연히 될 거라 생각했는데, provider 내부의 Go SSH 라이브러리가 에이전트 소켓을 제대로 인식하지 못했다. SSH_AUTH_SOCK 설정, agent_socket 경로 직접 지정 등 여러 방법을 시도해 봤지만 전부 실패였다. 결국 1Password에서 개인키를 파일로 내보내 직접 참조하는 방식으로 해결했다. 터미널에서 ssh root@proxmox는 에이전트로 멀쩡히 잘 되는데 provider만 안 되는, 다소 어처구니없는 상황이었다.

Bitnami 이미지 유료화

MySQL과 Redis를 Bitnami Helm 차트로 설치하려고 했는데 계속 실패했다. 명령어도 틀린 것 같지 않고, 설정도 문제없어 보이는데 ImagePullBackOff가 뜨면서 진행이 안 됐다. 한참을 들여다본 끝에 알게 된 건, Bitnami가 2025년 8월부터 일부 이미지를 유료화했다는 것이었다. MySQL과 Redis는 공식 이미지(mysql:8.4, redis:7)로 직접 StatefulSet을 작성해서 설치했고, Kafka는 Strimzi Operator로 갈아탔다. 덕분에 Operator 패턴이 뭔지, 왜 Strimzi가 적합한지를 자연스럽게 이해하게 됐으니 결과적으로는 나쁘지 않았다.

MongoDB AVX 명령어 오류

MongoDB Pod이 계속 Illegal instruction (core dumped) 오류를 내며 죽었다. 한참을 들여다봤는데, MongoDB 5.0부터 AVX 명령어가 필수인데 Terraform에서 VM CPU 타입을 x86-64-v2-AES로 설정했더니 AVX가 VM에 노출되지 않았던 것이 원인이었다. 해결은 간단했다. VM CPU 타입을 host로 변경해서 Proxmox 호스트의 CPU를 그대로 노출하면 됐다. Ryzen 7 8700G는 당연히 AVX를 지원하니까. 단일 노드 홈랩이라 VM 마이그레이션 제약이 없어서 이 방법을 쓸 수 있었다.

Prometheus가 메트릭을 수집하지 못하는 문제

모니터링 스택을 올리고 Prometheus targets 페이지를 열었더니 kube-controller-manager, kube-scheduler, etcd, kube-proxy가 전부 DOWN으로 표시됐다. 처음에는 설치 문제인가 싶었는데, 알고 보니 kubeadm의 기본 설정 문제였다. kubeadm으로 클러스터를 구성하면 이 컴포넌트들이 127.0.0.1에만 바인딩된다. Prometheus는 Pod IP로 접근하는데, 로컬호스트에만 열려있으니 당연히 접근이 안 됐던 것이다. 각 컴포넌트별로 bind-address=0.0.0.0으로 변경하고, 이후 재구성 시에도 동일한 문제가 생기지 않도록 kubeadm config 파일에 반영해뒀다.

Longhorn 대시보드 패널이 비어있던 문제

Grafana에 Longhorn 대시보드를 가져왔는데 패널이 전부 텅 비어있었다. Prometheus가 Longhorn 메트릭을 수집하고 있지 않았던 것인데, 원인은 kube-prometheus-stack이 release: kube-prometheus-stack 라벨이 붙은 ServiceMonitor만 수집하도록 설정되어 있기 때문이었다. Longhorn이 만든 ServiceMonitor에 그 라벨이 없었던 것이고, Longhorn Helm values에 additionalLabels로 해당 라벨을 추가하고서야 해결됐다. Grafana 대시보드 자체를 Import할 때도 Grafana Pod에서 외부 인터넷 접근이 안 되어서 로컬 PC에서 JSON을 받아 직접 업로드해야 했다.

IaC로 모든 것을 코드로 관리한다는 것

이번 작업에서 IaC를 고집한 이유는 하나였다. 언제든지 다시 만들 수 있어야 한다는 것. 새로운 머신을 구입하거나, 워커 노드를 추가할 때 처음부터 하나하나 손으로 설정하는 상황을 만들고 싶지 않았다. 그래서 웹 UI에서 클릭 몇 번이면 끝날 설정도 굳이 Terraform이나 Ansible, k8s 매니페스트로 남겼다. 처음엔 번거로웠다. 특히 삽질 중에는 “그냥 직접 고치면 되는데 왜 이렇게 돌아가야 하나” 싶을 때도 여러 번 있었다. 그런데 클러스터를 한 번 날리고 다시 구성해야 하는 상황이 생겼을 때, Ansible 플레이북 하나로 k8s 클러스터가 뚝딱 올라오는 걸 보고 나서는 생각이 달라졌다. 그 번거로움은 처음부터 목적이 있는 선택이었고, 나중의 나를 위한 투자인 것이다.

마무리

몇 달에 걸쳐 홈랩 클러스터를 구성하면서 업무에서 늘 쓰던 것들을 처음부터 직접 만들어보니, 알고 있다고 생각했지만 사실은 몰랐던 것들이 꽤 많다는 걸 알게 됐다. 직접 부딪혀보기 전까지는 잘 보이지 않는 것들이 있다.

지금 상태는 인프라 기반이 완성된 것이고, 이제 실제 서비스 앱을 올려서 운영해 보는 단계가 남아있다. 그 과정도 차근차근 기록으로 남길 생각이다.

이 기록이 비슷한 고민을 하고 있는 누군가에게 조금이라도 도움이 되었으면 좋겠고, 나중에 다시 보았을 때 나의 추억이 되었으면 좋겠다.

munilive

munilive

Backend Application Developer

Share

Comments

Related Posts

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

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

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

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

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

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

munilive munilive ·
Jenkins, ArgoCD, Harbor로 CI/CD 파이프라인 구성하기 (홈랩 k8s 구축기 4편)

Jenkins, ArgoCD, Harbor로 CI/CD 파이프라인 구성하기 (홈랩 k8s 구축기 4편)

지난 편에서 네트워크와 스토리지를 구성했다. 이번에는 코드를 빌드하고 클러스터에 배포하는 파이프라인을 만드는 차례다. CI/CD를 왜 직접 구성하는가 GitHub Actions를…

munilive munilive ·