
10년 묵은 Matomo 데이터를 Umami로 완벽하게 이사시킨 이야기
10년 넘게 운영하던 Matomo 웹 분석 데이터를 현대적인 Umami로 성공적으로 이전한 과정을 공유합니다. DB 마이그레이션 전략과 K8s 환경에서의 실전 팁을 담았습니다.
김테크
8년차 개발자

안녕하세요. 풀링포레스트 백엔드 개발자 김테크입니다.
개발팀에서 오래된 레거시 시스템을 걷어내는 일만큼 시원섭섭하면서도 긴장되는 순간이 있을까요? 저희 팀은 꽤 오랜 기간 웹 분석 도구로 Matomo(구 Piwik)를 사용해 왔습니다. 2014년 즈음 Google Analytics의 대안으로 도입했으니 강산이 한 번 변할 시간 동안 로그가 쌓인 셈이죠. 하지만 최근 들어 이 친구가 조금 버거워지기 시작했습니다.
오늘은 10년 넘게 운영하던 Matomo를 더 가볍고 현대적인 Umami로 전환하면서, 가장 큰 골칫거리였던 '데이터 마이그레이션'을 어떻게 해결했는지 그 과정을 공유하려 합니다.
왜 잘 쓰고 있던 Matomo를 버렸나
솔직히 말해, Matomo는 훌륭한 도구입니다. 기능도 강력하고 데이터 소유권도 확실하죠. 하지만 2025년의 관점에서 보면 UI가 다소 투박하고 구식이라는 느낌을 지울 수 없었습니다. 게다가 스택 관리 측면에서도 PHP와 MySQL 조합의 Matomo 컨테이너를 유지보수하는 게 점점 귀찮은 일이 되어가고 있었죠. Docker 이미지 업데이트 때마다 미묘하게 발생하는 호환성 문제들도 스트레스였습니다.
반면 Umami는 NextJS와 PostgreSQL을 기반으로 합니다. 훨씬 가볍고, UI는 깔끔하며, 호스팅하기도 간편합니다. 복잡한 기능보다는 딱 필요한 데이터만 보여주는 직관성이 마음에 들었습니다. 그래서 결심했습니다. "그래, 이사를 가자."
가장 큰 장벽: 내 데이터는 어떡하지?
결심은 섰는데 곧바로 벽에 부딪혔습니다. Umami를 새로 설치하는 건 쉬웠지만, Matomo에 쌓여 있는 지난 10년 치의 방문자 데이터가 문제였죠. Matomo에서 데이터를 내보내 Umami로 가져오는 공식 도구를 찾아봤지만, 놀랍게도 존재하지 않았습니다. 클라우드 버전에는 기능이 있는 것 같았지만, 저희처럼 오픈소스 버전을 직접 호스팅(Self-hosted)하는 경우에는 그림의 떡이었습니다.
막막했습니다. 10년의 기록을 포기하고 0부터 시작해야 하나 고민도 했지만, 그건 개발자의 자존심이 허락하지 않았습니다. 결국 직접 해결하기로 했습니다.
전략: 데이터베이스 대 데이터베이스
API를 통해 데이터를 한 건씩 옮기는 방법도 고려해 봤습니다. 하지만 수백만 건이 넘는 세션 데이터를 API로 처리하다가는 마이그레이션이 끝날 때쯤 제가 은퇴할지도 모른다는 생각이 들더군요. 그래서 좀 더 과감하게, Raw SQL을 사용하기로 했습니다.
Matomo의 MySQL DB에서 데이터를 읽어와서, Umami의 PostgreSQL 스키마에 맞는 INSERT 문으로 변환하는 Python 스크립트를 작성하는 방식입니다. 여기서 중요한 건 데이터 매핑입니다. 방문자 세션, 페이지 뷰 이벤트, 국가, 브라우저 정보 등이 누락되지 않도록 꼼꼼하게 필드를 대조해야 했습니다.
이 과정에서 깃허브의 angristan/matomo-to-umami 프로젝트가 큰 도움이 되었습니다. 기본적인 매핑 로직이 구현되어 있어서, 이를 기반으로 우리 환경에 맞게 마이그레이션 전략을 짤 수 있었습니다.
돌다리도 두들겨 보고: 로컬 테스트
운영 중인 DB에 바로 스크립트를 돌리는 건 러시안룰렛이나 다름없습니다. 저는 로컬 환경에 Docker Compose로 Umami 인스턴스를 띄워놓고 먼저 테스트를 진행했습니다.
실제 데이터를 덤프 떠서 로컬에 부어본 뒤, Matomo 대시보드의 숫자와 마이그레이션 된 Umami 대시보드의 숫자가 일치하는지 확인했습니다. 이 과정은 필수입니다. 실제로 이 테스트 단계에서 몇 가지 매핑 오류를 발견해서 수정할 수 있었습니다.
실전: 쿠버네티스 환경에서의 마이그레이션
저희는 Matomo와 Umami 모두 쿠버네티스(k8s) 환경에서 운영 중입니다. 외부에서 DB에 직접 접속하는 건 보안상 막혀 있기 때문에, kubectl port-forward를 사용해 로컬 머신과 파드(Pod)를 연결했습니다.
# MariaDB 포트 포워딩 예시
kubectl -n matomo port-forward svc/mariadb 3306:3306 &그리고 대망의 마이그레이션 스크립트 실행. 여기서 꿀팁은 반드시 --dry-run 옵션을 먼저 사용해 보는 것입니다. 실제로 데이터를 쓰기 전에 연결이 잘 되는지, 대상 데이터 건수는 얼마나 되는지 미리 확인하는 것이죠.
# Dry-run 실행 모습
[INFO] Configured 2 site mapping(s)
[INFO] Successfully connected to MySQL database
Dry Run Mode - No SQL will be generated
...
총 세션: 1,352,812
총 이벤트: 1,999,709로그에 찍힌 130만 개의 세션과 200만 개의 이벤트가 정상적으로 인식되는 걸 확인했을 때의 안도감이란, 경험해 보지 않은 분들은 모를 겁니다.
마무리하며
검증이 끝난 후, 생성된 SQL 파일을 Umami의 PostgreSQL 파드에 밀어 넣는 것으로 긴 여정이 끝났습니다.
kubectl -n umami exec -i umami-pod -- psql -U app -d app < migration.sql이제 Matomo 컨테이너를 내리고 리소스를 확보할 수 있게 되었습니다. 10년 묵은 짐을 정리하고 새집으로 이사 온 기분입니다.
레거시 마이그레이션은 언제나 두렵습니다. 데이터 유실에 대한 공포가 가장 크죠. 하지만 DB 구조를 뜯어보고 직접 데이터를 핸들링하면서 시스템에 대한 이해도는 훨씬 깊어졌습니다. 혹시 지금 사용하는 분석 도구가 마음에 들지 않는데 데이터 때문에 주저하고 계신다면, 이번 주말에는 작은 마이그레이션 스크립트를 한번 짜보는 건 어떨까요?
생각보다 할 만하고, 결과는 아주 달콤할 겁니다.


