🚀 나만의 쿠버네티스 홈 클러스터 구축하기: 문제 해결 중심 가이드
안녕하세요, 쿠버네티스 애호가 여러분! 오늘은 가정에서 나만의 쿠버네티스 클러스터를 구축하면서 겪었던 다양한 문제들과 해결책을 공유하려고 해요. 이전 포스트에서는 k3s로 간단한 클러스터를 구축했지만, 이번에는 표준 쿠버네티스(kubeadm)를 설치하고 Vagrant와 Ansible로 자동화하는 방법을 알아볼게요. 시작해볼까요? 😄
🌐 전체 네트워크 구성도
먼저 전체 시스템 구성을 살펴보면 이렇게 되어 있어요:
moolmeow.com 도메인
├── 프론트엔드: Vercel에 정적 사이트 배포
└── 백엔드 API: api.moolmeow.com → 집 공인 IP → 홈 클러스터
자세한 네트워크 흐름:
- 사용자 → 도메인: 사용자가 api.moolmeow.com에 접속
- 도메인 → 공인 IP: DDNS 서비스가 도메인을 현재 집 공인 IP로 연결
- 공인 IP → 미크로틱 라우터: 포트 80/443 포워딩
- 라우터 → 맥미니 → VM: 호스트 전용 네트워크 통신
- VM → 쿠버네티스: 인그레스와 MetalLB가 트래픽 라우팅
이렇게 구성하면 외부에서 접속 가능한 홈 쿠버네티스 클러스터를 운영할 수 있어요!
🛠️ Vagrant로 VM 구축하기: 문제와 해결책
이전에 k3s로 구축할 때와 비교하여, 표준 쿠버네티스 설치 시 몇 가지 문제점이 있었어요.
문제 1: VirtualBox Guest Additions 설치 실패
증상: VM이 생성되었지만 공유 폴더가 마운트되지 않는 문제
해결책:
# VM에 접속하여 직접 설치
sudo apt-get install -y dkms build-essential linux-headers-$(uname -r)
sudo /opt/VBoxGuestAdditions*/init/vboxadd setup
이를 Ansible 플레이북에 반영하여 자동화했어요:
- 필요한 패키지 설치
- Guest Additions 설정 스크립트 실행
- 설정 적용을 위한 재부팅
문제 2: Ansible SSH 연결 문제
증상:
ansible-playbook -i inventory.yml main.yml
SSH Error: Permission denied
원인 분석: 인벤토리 파일에서 SSH 설정이 잘못되었음을 확인했어요. Vagrant는 포트 포워딩을 통해 SSH를 설정하는데, 직접 VM IP로 접속하려고 했던 것이 문제였어요.
해결책:
# inventory.yml 파일 수정
k8s-master:
ansible_host: 127.0.0.1 # localhost 사용
ansible_port: 2222 # Vagrant의 포워딩된 포트
ansible_user: vagrant
ansible_ssh_private_key_file: ./.vagrant/machines/k8s-master/virtualbox/private_key
이렇게 localhost와 포워딩된 포트를 사용하니 SSH 연결 문제가 해결되었어요!
문제 3: 환경별 스토리지 경로 설정
문제: 고정된 경로를 사용하면 이식성이 떨어진다는 문제
해결책: Vagrant 설정에서 환경 변수와 홈 디렉토리를 참조하도록 수정했어요:
home_dir = ENV['HOME']
mount_base_path = "#{home_dir}/Desktop/moolmeow"
이렇게 하면 어떤 사용자의 시스템에서든 올바른 경로를 참조할 수 있어요!
🤖 Ansible 자동화의 핵심 포인트
Ansible 자동화를 구성할 때 겪은 문제들과 해결책입니다:
문제: 플레이북 구조화와 의존성 관리
초기에는 단일 플레이북으로 시작했지만, 복잡성이 증가하면서 문제가 발생했어요.
해결책: 플레이북을 기능별로 분리했어요:
common.yml
: 모든 노드의 기본 설정 (패키지 설치, 커널 설정 등)master.yml
: 마스터 노드 구성 (클러스터 초기화, 네트워크 플러그인 등)worker.yml
: 워커 노드 조인storage-volumes.yml
: 환경별 스토리지 볼륨 구성
각 플레이북이 특정 역할을 담당하게 하고, main.yml
에서 순서대로 임포트하는 방식으로 해결했어요.
문제: YAML 문법 오류
YAML의 들여쓰기 관련 구문 오류가 자주 발생했어요.
오류 예시:
ERROR! Syntax Error while loading YAML.
found character that cannot start any token
해결책: 들여쓰기를 주의 깊게 확인하고, YAML 유효성 검사 도구 사용:
yamllint common.yml
문제: 반복 실행 시 충돌
플레이북을 여러 번 실행할 때 “이미 존재함” 오류가 발생했어요.
해결책: 조건부 실행과 오류 처리 로직 추가:
failed_when:
- result.rc != 0
- "'already exists' not in result.stderr"
이렇게 하면 이미 리소스가 존재하는 경우에도 플레이북이 중단되지 않아요!
💾 스토리지 구성의 핵심 포인트
개발, 스테이징, 프로덕션 환경에 맞게 스토리지를 구성하면서 배운 것들입니다:
환경별 스토리지 용량 차별화
개발과 스테이징은 5GB, 프로덕션은 200GB로 설정하여 실제 운영 환경의 요구사항을 반영했어요.
문제: 단순히 크기만 다르게 하면 실제 사용량을 제한하지 못해요.
해결책: 쿠버네티스의 ResourceQuota와 LimitRange를 추가로 설정하여 네임스페이스별 리소스 제한을 구현했어요.
호스트 경로 마운트 관련 문제
문제: VirtualBox 공유 폴더 설정이 때때로 실패하는 문제
해결책:
- Guest Additions 제대로 설치 확인
- 마운트 포인트 소유권 설정
- 필요시 수동 마운트 명령 실행:
sudo mount -t vboxsf host-images-dev /mnt/host-images-dev
🌟 MetalLB 설정의 중요성
온프레미스 쿠버네티스 환경에서 외부 IP 할당을 위해 MetalLB를 사용했어요.
학습 포인트:
- MetalLB가 로컬 환경에서 LoadBalancer 서비스에 실제 IP를 할당
- Layer 2 모드와 BGP 모드의 차이점 이해
- IP 대역을 로컬 네트워크와 충돌하지 않게 설정하는 것이 중요
MetalLB 설정 후 인그레스 컨트롤러에 고정 IP를 할당하여 외부에서 일관되게 접근할 수 있도록 했어요.
🚢 클러스터 구축 흐름: 실패와 성공의 여정
처음부터 모든 것이 순조롭지는 않았어요. 여러 시행착오를 겪었죠:
- 첫 시도: k3s로 간단하게 시작 → 네트워크 플러그인 문제 발생
- 두 번째 시도: kubeadm으로 전환 → Guest Additions 문제
- 세 번째 시도: Ansible 자동화 도입 → SSH 연결 문제
- 최종 성공: 모든 문제 해결 후 안정적인 클러스터 구축!
가장 큰 교훈은 “한 번에 하나의 문제만 해결하자”였어요. 너무 많은 변경을 한꺼번에 시도하면 문제 원인을 파악하기 어려워요.
🔍 DDNS 설정으로 동적 IP 문제 해결
집에서 서버를 운영할 때 가장 큰 고민은 동적 IP 문제예요. 미크로틱 라우터에서 DDNS 클라이언트를 설정하여 이 문제를 해결했어요.
설정 과정:
- 미크로틱 라우터에서 스크립트 생성
- DDNS 제공업체(DuckDNS, Namecheap 등)에 맞게 스크립트 작성
- 스케줄러로 주기적 실행 설정 (5분마다)
이렇게 하면 집의 공인 IP가 변경되어도 도메인이 항상 최신 IP를 가리키게 돼요!
🌟 마무리 및 다음 단계
지금까지 Vagrant와 Ansible을 활용한 쿠버네티스 클러스터 구축 과정과 문제 해결 방법을 살펴봤어요. 이 과정을 통해 배운 내용:
- 자동화의 중요성: 반복 작업을 자동화하면 시간 절약과 실수 방지
- 모듈화된 접근 방식: 큰 문제를 작은 단위로 분해
- 테스트와 검증: 각 단계마다 제대로 작동하는지 확인
다음 단계로 고려할 만한 것들:
- Let’s Encrypt로 SSL 인증서 자동화
- 모니터링 시스템 구축 (Prometheus + Grafana)
- CI/CD 파이프라인 연동
홈랩에서 쿠버네티스를 실행하는 것은 좋은 학습 경험이에요. 실패를 두려워하지 말고 문제 해결 과정을 즐기세요! 🚀
질문이나 피드백이 있으시면 댓글로 남겨주세요. 다음 글에서는 애플리케이션 배포와 관리에 대해 더 자세히 살펴보겠습니다. 😊
🚀 Building a Kubernetes Home Cluster: A Problem-Solving Guide
Hello, Kubernetes enthusiasts! Today I’m sharing the challenges I faced while building a Kubernetes cluster at home and the solutions I discovered along the way. In my previous post, we set up a simple cluster using k3s, but this time we’ll install standard Kubernetes (kubeadm) and automate everything with Vagrant and Ansible. Ready to dive in? 😄
🌐 Overall Network Architecture
First, let’s look at the big picture of our system:
moolmeow.com domain
├── Frontend: Static site deployed on Vercel
└── Backend API: api.moolmeow.com → Home public IP → Home cluster
Detailed Network Flow:
- User → Domain: User accesses api.moolmeow.com
- Domain → Public IP: DDNS service connects domain to current home public IP
- Public IP → Mikrotik Router: Ports 80/443 forwarding
- Router → Mac Mini → VM: Host-only network communication
- VM → Kubernetes: Ingress and MetalLB route traffic
With this setup, you can run a home Kubernetes cluster that’s accessible from the internet!
🛠️ VM Setup with Vagrant: Problems and Solutions
Compared to our previous k3s setup, I encountered several issues when installing standard Kubernetes.
Problem 1: VirtualBox Guest Additions Installation Failure
Symptom: VMs were created but shared folders weren’t mounting
Solution:
# Connect to VM and install manually
sudo apt-get install -y dkms build-essential linux-headers-$(uname -r)
sudo /opt/VBoxGuestAdditions*/init/vboxadd setup
I automated this in the Ansible playbook by:
- Installing required packages
- Running the Guest Additions setup script
- Rebooting to apply changes
Problem 2: Ansible SSH Connection Issues
Symptom:
ansible-playbook -i inventory.yml main.yml
SSH Error: Permission denied
Root Cause Analysis: The inventory file had incorrect SSH settings. Vagrant uses port forwarding for SSH, but I was trying to connect directly to the VM’s IP.
Solution:
# Modify inventory.yml
k8s-master:
ansible_host: 127.0.0.1 # Use localhost
ansible_port: 2222 # Vagrant's forwarded port
ansible_user: vagrant
ansible_ssh_private_key_file: ./.vagrant/machines/k8s-master/virtualbox/private_key
Using localhost with the forwarded port resolved the SSH connection issues!
Problem 3: Environment-specific Storage Path Configuration
Issue: Using hardcoded paths reduces portability
Solution: Modified Vagrant configuration to reference environment variables and home directory:
home_dir = ENV['HOME']
mount_base_path = "#{home_dir}/Desktop/moolmeow"
This way, the correct paths are referenced regardless of which user’s system it runs on!
🤖 Key Points in Ansible Automation
Here are the problems I encountered with Ansible automation and their solutions:
Problem: Playbook Structure and Dependency Management
Initially started with a single playbook but ran into issues as complexity grew.
Solution: Split playbooks by functionality:
common.yml
: Basic setup for all nodes (packages, kernel settings, etc.)master.yml
: Master node configuration (cluster init, network plugins, etc.)worker.yml
: Worker node joiningstorage-volumes.yml
: Environment-specific storage volume setup
Each playbook handles a specific role, imported in sequence by main.yml
.
Problem: YAML Syntax Errors
Frequent syntax errors related to YAML indentation.
Error Example:
ERROR! Syntax Error while loading YAML.
found character that cannot start any token
Solution: Carefully check indentation and use YAML validation tools:
yamllint common.yml
Problem: Conflicts on Repeated Execution
Errors like “already exists” when running playbooks multiple times.
Solution: Add conditional execution and error handling logic:
failed_when:
- result.rc != 0
- "'already exists' not in result.stderr"
This prevents the playbook from failing when resources already exist!
💾 Key Points in Storage Configuration
Lessons learned while configuring storage for development, staging, and production environments:
Differentiating Storage Capacity by Environment
Set development and staging to 5GB, production to 200GB to reflect real-world requirements.
Issue: Simply setting different sizes doesn’t limit actual usage.
Solution: Implemented ResourceQuota and LimitRange to enforce namespace-specific resource limits.
Host Path Mounting Issues
Problem: VirtualBox shared folder setup occasionally failing
Solution:
- Verify Guest Additions is properly installed
- Set mount point ownership
- Run mount commands manually if needed:
sudo mount -t vboxsf host-images-dev /mnt/host-images-dev
🌟 The Importance of MetalLB
Used MetalLB to assign external IPs in an on-premises Kubernetes environment.
Learning Points:
- MetalLB assigns real IPs to LoadBalancer services in local environments
- Understanding differences between Layer 2 and BGP modes
- Importance of configuring IP ranges that don’t conflict with local network
After setting up MetalLB, I assigned a fixed IP to the ingress controller for consistent external access.
🚢 Cluster Building Journey: Failures and Success
Not everything went smoothly from the start. I experienced several iterations:
- First Attempt: Started simple with k3s → encountered network plugin issues
- Second Attempt: Switched to kubeadm → Guest Additions problems
- Third Attempt: Introduced Ansible automation → SSH connection issues
- Final Success: Resolved all issues and built a stable cluster!
The biggest lesson learned was “solve one problem at a time.” Trying to change too many things at once makes it difficult to identify the root cause of issues.
🔍 Solving Dynamic IP Problems with DDNS
When running servers from home, dynamic IP is a major concern. I solved this by configuring a DDNS client on my Mikrotik router.
Setup Process:
- Create a script on the Mikrotik router
- Write the script according to your DDNS provider (DuckDNS, Namecheap, etc.)
- Configure scheduler to run periodically (every 5 minutes)
This ensures your domain always points to your current public IP, even when it changes!
🌟 Conclusion and Next Steps
Throughout this journey of building a Kubernetes cluster with Vagrant and Ansible, I’ve learned:
- The importance of automation: saving time and preventing mistakes
- Modular approach: breaking down big problems into smaller units
- Testing and validation: verifying each step works correctly
Consider these next steps:
- Automating SSL certificates with Let’s Encrypt
- Building a monitoring system (Prometheus + Grafana)
- Integrating CI/CD pipelines
Running Kubernetes in a home lab is a great learning experience. Don’t fear failure and enjoy the problem-solving process! 🚀
If you have any questions or feedback, please leave them in the comments. In the next post, we’ll look more closely at application deployment and management. 😊