Mac mini 홈서버로 전환 이유
사이드 프로젝트에서 AWS 비용이 매달 약 10만 원이 발생하다 보니, 자연스럽게 대체재를 고민하게 되었습니다. 그러던 중 이미 보유하고 있던 Mac mini(M1) 기기를 활용해 홈서버를 구축해 보기로 했습니다. 전기세 등을 고려했을 때 월 1,000원 이하로 유지 가능하다는 점도 큰 매력으로 다가왔습니다.
1. 유지하고 이전할 서비스 구분
이미지, 동영상 등 유저가 등록한 데이터를 저장할 공간은 여전히 필요하므로 S3는 그대로 유지하기로 했습니다. 반면 가장 비용이 많이 드는 EC2에 배포된 자바 애플리케이션과 RDS(MySQL)는 홈 서버로 이전하기로 했습니다. 이 중 MySQL을 우선적으로 이전하기로 했습니다.
추가로 비용 문제로 운영하지 못했던 테스트 환경도 함께 구성해보기로 했습니다.
2. Mac mini 스펙과 컨테이너 도입
Mac mini의 스펙은 CPU: 8 Core ,메모리: 16GB, 저장공간: 256GB으로 구성되어 있었습니다. 하나의 물리 장치에서 해당 자원으로 여러 서비스를 운영해야 하기 때문에 컨테이너 기술을 도입하기로 했습니다. 그 운영 도구로 Kubernates를 선택했습니다. 많이 사용이 되는 기술이며, 학습 측면에서도 좋은 기회라도 판단했기 때문입니다.
3. 로컬 Kubernetes 환경 - Minikube
Mac에서는 로컬 개발용 Kubernetes 도구로 Minikube를 사용할 수 있습니다. brew를 통해 쉽게 설치할 있었습니다.
$ brew install minikube
Kubernetes의 경우 리눅스 커널 기반 도구입니다. 따라서 macOS에서는 직접 실행이 불가능하고, VM을 통해 리눅스 환경을 띄워서 동작시켜야 합니다. 이때 VM을 띄우는 도구를 정하는 것이 Minikube 클러스터를 생성할 때 부여하는 driver 옵션입니다.
Minikube가 지원하는 driver는 다양하지만 M1 칩 지원 여부, 구동 속도, 추가 비용 발생 여부 등을 고려해서 docker를 사용하기로 했습니다. 추가로 물리 기기의 리소스를 고려해서 운영 DB 노드의 경우 CPU 2 Core, 메모리 2G를 할당하기로 했습니다.
$ minikube start -p prod-db --driver=docker --cpus=2 --memory=2g
4. Minikube의 간단 특징
Minikube는 기본적으로 단일 노드 클러스터를 구성합니다. Kubernetes의 일반 구조인 Master/Worker 노드 개념을 모두 하나의 노드 안에서 처리하는 방식입니다. 옵션을 통해 여러 노드를 구성할 수는 있습니다. 하지만 단일 머신 기반이다 보니 자원의 한계와 장애 격리 측면 등의 제약 사항이 존재합니다. 즉, 시뮬레이션 용도에 가깝습니다.
하지만 이런 한계가 있지만 우리가 운영하는 서비스와 상황을 고려했을 때 가장 적절한 도구라고 판단했습니다.
5. MySQL 마이그레이션과 외부 연결 문제
MySQL을 Minikube를 통해서 띄우는 것은 문제 없이 잘 진행되었습니다. 우리 서비스의 데이터가 많지 않은 편이어서 덤프를 통해서 쉽게 이전할 수 있었습니다.
문제는 같이 일하는 팀원들이 외부에서 데이터를 확인할 수 있도록 외부 접속을 테스트할 때 발생했습니다. 외부 네트워크에서 접근이 안 되는 것이었습니다. MySQL 설정과 Minikube tunnel 등을 점검하면서 테스트했지만 계속해서 실패했습니다. 그래서 정확하게 구조를 파악하고 원인을 분석하기로 했습니다. 그 길이 가장 빠른 길이라고 판단했습니다.
6. 네트워크 구조를 이해하며 해결 실마리 찾기
Minikube를 Docker Driver 기반으로 실행했을 때 어떤 구조로 구성이 되는가를 확인하기 시작했습니다.
1. Host OS(Mac)과 Guest OS(Linux)로 이루어져 있으며, 두 OS 간의 네트워크는 분리되어 있습니다.
2. Minikube를 통해서 Pod에 프로그램을 실행하면 Guest Os(Linux)와 Pod 간의 네트워크만 연결이 됩니다.
⮕ Host OS와 Guest OS를 연결해주는 것은 수동으로 해줘야 합니다.
3. Docker Driver의 경우 네트워크 브리지 역할을 하는 도구 vpnkit을 사용하는데 Host OS의 127.0.0.1과의 연결만 해줍니다.
4. 외부 네트워크에서 Host OS의 127.0.0.1에 직접 연결이 불가능해서 리다이렉트 해주는 방식이 필요합니다.
7. 외부 연결하기 - Host OS와 Guest OS 연결
Minikube에서 Host OS와 Guest OS를 연결하는 방법으로 크게 2가지가 있습니다. 서비스 단위로 포트 포워딩을 하거나 클러스터 단위로 포트 포워딩을 해줄 수 있습니다.
서비스 단위 포트 포워딩은 kubectl port-forward 명령어로 실행할 수 있습니다. 클러스터 단위는 minikube tunnel 명령어를 통해서 실행할 수 있습니다. minikube tunnel의 경우 Service Type을 LoadBalancer로 설정해야 하며 Host OS에서 127.0.0.1로 접근 가능하도록 해줍니다.
클러스터 단위로 Host OS와 Guest OS를 연결하고 싶었기에 minikube tunnel 명령어를 사용했으며, 터미널 종료 시 종료되므로 nohup을 사용해 백그라운드에서 실행되도록 해주었습니다.
8. 외부 연결하기 - 외부와 Host OS(127.0.0.1) 연결
이제 남은 문제는 외부에서 들어온 요청을 어떻게 127.0.0.1로 넘길 것인가였습니다. 이를 해결하는 방법은 다양하겠지만 사용자 공간에서 리다이렉트 하는 프로그램 socat과 커널 레벨에서 리다이렉트 하는 PF(Packet Filter) 2가지를 비교하여 결정하기로 했습니다. 속도적인 측면과 안정성을 고려해서 PF 기반 리다이렉션을 사용하기로 했습니다.
✔ /etc/pf.anchors/com.redirect.rule 파일 설정
rdr pass on en0 inet proto tcp from any to any port 30306 -> 127.0.0.1 port 30306
✔ /etc/pf.conf 파일 설정
rdr-anchor "com.redirect"
load anchor "com.redirect" from "/etc/pf.anchors/com.redirect.rule"
✔ pf 적용
sudo pfctl -f /etc/pf.conf
sudo pfctl -e
9. 마치며
이번 홈서버 구성은 단순한 마이그레이션을 넘어, 시스템 구조와 네트워크에 대한 깊은 이해가 필수적이라는 걸 깨닫는 계기가 되었습니다. 앞으로 자바 애플리케이션 배포와 HTTPS 설정 작업에서도, 이번 경험을 바탕으로 더 빠르고 정확하게 대응할 수 있을 것 같습니다.
10. 참고 문서
Improving Docker with Unikernels: Introducing HyperKit, VPNKit and DataKit | Docker
Learn from Docker experts to simplify and advance your app development and management with Docker. Stay up to date on Docker events and new version
www.docker.com
'프로젝트' 카테고리의 다른 글
AWS 대신 Mac mini로 홈서버 구축하기: Minikube로 애플리케이션 이전 (0) | 2025.07.10 |
---|---|
어뷰징 대응의 시작 - 고정 윈도우 기반 Rate Limit 시범 운영기 (0) | 2025.06.25 |
반복되는 장애, 우리는 어떻게 대응하고 있을까? (0) | 2025.06.11 |
개발 환경의 시간대 차이가 만든 버그: LocalDateTime 이슈 해결기 (0) | 2025.05.31 |
코틀린 Data Class와 Mybatis 같이 사용할 때 주의점 (0) | 2025.03.04 |