집에서 장난감 서버 1년 운영기
집에서 서버를 운영한 지난 1년 동안 하드웨어에 일어날 사고에 대비했지만 문제는 오히려 소프트웨어 쪽에서 주로 일어났습니다.

얼마 전 인터넷 어딘가를 지나가다가 집에서 실제 운영 중인 서비스를 지탱하는 서버를 5년에 걸쳐 운영한 이야기를 보았습니다. 그 긴 기간에 걸쳐 집에서 서버 인프라를 운영하며 서버가 기계가 침수되는 사건을 겪었다는 글을 보며 서버 인프라를 그냥 가정집에서 운영하는 일이 그리 만만하지 않다는 생각을 했습니다. 개인적으로 사용자가 있는 서비스를 운영하고 있지는 않지만 저 자신의 여러 요구사항을 충족하는 서버를 집에서 운영하고 있기는 합니다. 가령 n8n을 돌려 여러 가지 자동화가 항시 동작하고 있게 해 주고 퍼포스 서버로 제 거의 모든 파일의 이동, 변경, 삭제 기록을 남기고 또 이들 모두를 안전하게 백업하게 해 줍니다. 게임 서버를 상시 열어 놓을 수 있게 해줄 뿐 아니라 블로그 도구로 사용 중인 고스트에 설정을 변경하거나 테마를 변경해 보기 전에 별도의 환경에서 실험해본 다음 실제 서비스 환경에 적용할 수 있도록 해 주기도 합니다. 또 스테이터스 페이지를 운영하려면 외부 서비스에 돈을 내야 하는데 이를 직접 돌릴 수도 있고 웹사이트 접근 기록을 남겨 통계를 살펴보거나 데이터베이스에 필요한 로그를 남길 수 있는 등의 용도로 활용하고 있습니다. 이 서버가 멈추면 일단 저는 퍼포스와 파일을 주고받지도 못하고 자동화 기능이 모두 멈추는 등 일상 생활이 상당히 귀찮아집니다.
이 서버는 몇 년 동안 AWS에 있었습니다. AWS에는 EC2 같은 본격적인 컴퓨팅 서비스도 있지만 Lightsail 같은 비슷하면서도 훨씬 단순한 서비스도 있습니다. 저는 후자에서 아주 적은 월 비용만 지불하고 아주 작은 서버 인스턴스 하나를 확보해 여러 서비스를 네이티브로 설치해 사용했습니다. 가령 컨플루언스 클라우드 이전까지는 몇 년 동안 도쿠위키를 설치해 사용했고 지금과 비슷하게 스테이터스 페이지를 운영하는데 uptime-kuma, 웹 접근 기록을 남기는데 matomo, 노드 기반의 자동화에 n8n을 사용했고 또 퍼포스를 같은 서버에서 함께 사용하고 있었습니다. 이 환경은 짧지 않은 기간에 걸쳐 멀쩡하게 잘 돌아갔습니다만, 이 서버에 더 많은 것을 의존하려고 할 때마다 서버에 대해 별 지식이 없는 제가 해결하기에 점점 더 어려운 문제들이 생겼습니다. 가령 uptime-kuma와 n8n은 양쪽 모두 node-js를 요구했는데 제가 원인을 정확히 파악한 것인지 의심되기는 하지만 이들 둘은 종종 서로 다른 버전의 node-js를 요구했습니다. 그래서 어느 한 쪽이 잘 동작하면 다른 한 쪽은 다른 버전을 요구하며 동작하지 않곤 했는데 이 문제를 해결하기 쉽지 않았습니다. 대부분은 두 서비스가 서로 같은 버전에 의존하고 있어 문제가 일어나지 않았지만 어느 한 쪽을 업데이트 할 때 문제가 생기면 제 능력 안에서는 도무지 해결할 수가 없었습니다. 하다하다 문제를 해결하지 못할 것 같으면 작업을 시작하기 전에 만든 스냅샷을 사용해 그냥 작업 자체를 취소해 버리곤 했습니다. 또 퍼포스 서버를 함께 운영하기 시작하면서 스토리지 비용이 증가했고 이는 AWS 사용을 마무리하고 온프레미스 환경으로 옮겨 올 결심을 하게 만든 계기가 되었습니다.
하지만 AWS 서울 리전에 있던 제 작은 서버 인스턴스는 그 역할을 대체로 잘 수행했습니다. 네트워크가 끊길 일도 없었고 하드웨어가 고장 날 일도 없었습니다. 실은 AWS를 사용하면서 딱 한 번 하드웨어 오류를 겪은 적이 있습니다. 어떻게 해도 인스턴스의 오동작을 해결할 수가 없어 결국 이전 스냆샷을 다른 위치에 복원해 문제를 해결했는데 이 경험을 검색해보니 드물게 일어나는 하드웨어 오류일 가능성이 있다는 설명을 보았습니다. AWS 스스로도 하드웨어 오류 가능성에 대비해 가용성을 유지하고 싶으면 인프라를 분산하라는 조언을 하고 있었습니다. 하지만 저 때를 제외하면 하드웨어 고장이 일어나지도 않았습니다. 서버는 항상 그 자리에서 제가 설정한 대로 자기 역할을 수행했고 저는 그저 매월 청구되는 예측 가능한 요금을 내기만 하면 됐습니다. 요금은 대략 인스턴스 비용, 스토리지 비용으로 구성되는데 EC2는 데이터 전송량이나 CPU 사용량에 따른 복잡한 계산 방법에 따라 요금이 결정되지만 Lightsail은 그냥 인스턴스 비용에 스토리지 사용 요금 일부와 네트워크 사용 요금이 포함되어 있어 훨씬 예측 가능했습니다. 비록 사양이 낮아 뭘 더 시키기는 어려웠지만 딱 저 혼자 사용하는 용도로는 나쁘지 않았습니다. 이 상황은 제가 개인 파일 관리에 깃을 도저히 사용할 수 없다고 선언하고 퍼포스를 사용하기로 결정하면서 스토리지가 더 많이 필요해지면서 끝났습니다. 제 지불 능력으로는 본격적으로 AWS에 블록 스토리지 요즘을 규칙적으로 지불하는 것은 문제가 있었습니다. 그래서 AWS의 모든 기능을 온프레미스 기계로 옮기기로 결정합니다.
온프레미스로 옮길 결정을 했지만 여전히 하고 싶지 않은 몇 가지 행동이 있었습니다. 가령 하드웨어를 조각조각 구입해 제가 직접 기계를 조립하고 관리하는 일은 하고 싶지 않았습니다. 한때 그렇게 제가 사용할 기계를 조립하는 행동이 재미있다고 생각할 때도 있었지만 지금의 저는 기계를 사용한 작업 자체에 집중하기를 원했습니다. 기계가 문제를 일으키면 그냥 수리 받아 사용을 이어가기를 원합니다. 또 이전 시대보다는 훨씬 덜하지만 소위 궁합이 잘 안 맞는다고 표현하곤 하는 서로 충돌하는 드라이브에 의한 문제 해결, 전기요금, 하드웨어 별 드라이버 업데이트 같은 자잘한 문제에 신경 쓰고 싶지도 않았습니다. 또 기계가 너무 큰 소음을 내는 것을 원하지도 않았고 너무 많은 전력을 소모하기를 원하지도 않았습니다. 사실 이쯤 되면 그냥 AWS를 계속해서 유지하는 편이 더 나을 것 같은 지경입니다만 지금 제가 사용하고 있는 스토리지를 AWS에서 블록 스토리지 모양으로 사용한다면 한 달에 수 십 만원을 내야 하기 때문에 이미 돌아갈 수 없습니다. 그런데 이런 요구사항을 모두 만족하는 간단한 기계가 있었습니다. 바로 맥미니입니다. 맥미니 M1 기본 모델은 이 결정을 하던 시점에도 이미 출시 후 시간이 많이 흘러 가격이 저렴할 뿐 아니라 성능이 충분했고 팬을 내장했지만 소음이 거의 없으며 조립 실수 등으로 인한 하드웨어 고장을 일으킬 가능성도 거의 없었습니다. 특히 아주 적은 전력만 소모해 제가 원하는 거의 모든 조건을 갖췄습니다. 다만 저는 이전까지 리눅스 운영체제에 모든 소프트웨어를 직접 설치해 사용하고 있었는데 이번에는 운영체제가 달라지므로 지금까지 하던 대로 환경을 구성할 수는 없을 것 같았습니다. 하지만 이번에는 기본 모델의 8기가 램에서도 잘 돌아가는 도커를 활용할 수 있다는 사실을 깨달았습니다.
이전까지 AWS에 있는 작은 서버 인스턴스에 네이티브로 설치되어 있던 서비스들은 이제 맥미니에서 각기 다른 도커 컨테이너가 되었습니다. 도커 데스크탑에 마우스로 클릭이나 좀 하며 컨테이너를 띄우는 입장이지만 이미 누군가가 컨테이너를 예쁘게 잘 만들어둔 덕분에 저는 정말로 마우스를 좀 딸깍거리기만 하면 이전에 사용하던 서비스 데이터를 가져와 그대로 서비스를 재 구축 할 수 있었습니다. 이전과 비교해 가장 큰 장점은 문제가 발생할 때 원격에서 이를 해결하기는 꽤 어려웠지만 이제 모니터에 손을 뻗어 입력을 HDMI1에서 HDMI2로 바꾸면 바로 서버가 나타나 문제를 해결하기 훨씬 쉬웠습니다. 사실 난이도는 거의 비슷하겠지만 제 입장에서는 훨씬 쉽고 또 가깝게 느껴졌습니다. 이전에 512메가 또는 1기가 램 환경에서 서비스를 운영하던 입장에서 8기가 짜리 램은 이 기계가 완전 고사양 장비처럼 느껴지게 만들었습니다. 실은 이전에 도커라는 서비스의 존재를 알게 된 다음 AWS에 있는 기계에서 도커를 사용해 보려고 했는데 램이 부족해 순식간에 크래시되는 모습을 보았기 때문에 여러 컨테이너를 안정적으로 운영할 수 있는 기계는 출시된지 몇 년이 지난 기본 모델이라도 충분히 훌륭해 보였습니다. 이 기계는 얼마 전 교체하기 전까지 아무 소리도 내지 않았고 아주 적은 전력만을 사용했으며 아무 고장도 일으키지 않은 채 그저 그 자리에서 켜져 있는지조차 모를 정도로 가만히 자기 할 일을 수행했습니다. 다행히 집에 침수가 일어나지도 않았고 정전이 일어나지도 않았으며 공유기를 교체한 다음에는 네트워크 단절이 일어나지도 않았습니다. 그냥 아무 일 없이 평화롭게 동작했습니다. 사실 이쯤 되면 이 이야기를 왜 하기 시작했는지 조금 후회되기도 합니다.
문제는 오히려 소프트웨어와 운영 측면에서 일어났습니다. 먼저 여러 웹서비스가 Cloudflare Tunnel이라는 리버스 프록시 서비스에 의존하고 있었는데 이전에는 아무 문제 없이 동작하던 서비스가 종종 응답이 없어졌습니다. 몇몇 서비스가 응답이 없어져 무슨 일인지 살펴보면 cloudflared 컨테이너 로그에 이곳, 저곳, 그 아무데도 접속할 수 없다는 수많은 로그를 띄우고 있었습니다. 제가 할 수 있는 일은 컨테이너를 재시작 하는 것 뿐이었는데 재시작 하기만 하면 아무 일 없다는 듯 다시 멀쩡하게 동작했습니다. 근본적인 원인이야 있겠지만 제 기술 수준으로는 문제의 원인 파악도 어렵고 또 원인을 파악한다 하더라도 제가 해결할 수 없을 가능성이 높다고 생각했습니다. 동작을 살펴보니 cloudflared 컨테이너는 업타임이 늘어날수록 그 무엇과도 연결에 실패하는 상태에 더 잘 빠지는 것처럼 보였습니다. 그렇다면 제 입장에서 해결 방법은 무식하고 간단합니다. 그냥 그 스스로 문제를 일으켜 재시작하는 그냥 일정 시간마다 재시작 되도록 해 버리면 됩니다. 어차피 재시작에는 몇 초 밖에 걸리지 않으니 서비스에 거의 문제를 일으키지도 않을 겁니다. 당연히 이런 작업은 리눅스 서버에 익숙한 분들이라면 cron job을 사용할 생각을 하시겠지만 AWS에서 서버를 오랫동안 운영해 왔음에도 저에게는 여전히 익숙하지 않습니다. 그 문법을 이해했지만 여전히 루트 권한으로 실행되는 작업과 일반 유저 권한으로 실행되는 작업을 헛갈려 엉뚱한 곳에 입력해 놓고 반복 작업이 동작하지 않는다고 생각하기도 했습니다. 이 상황에서 저는 간단히 이미 잘 동작하고 있는 n8n으로 요구사항에 대응하기로 합니다. 일정 시간마다 실행되는 노드를 만들고 SSH로 호스트 서버에 연결해 cloudflared 컨테이너를 재시작합니다. cloudflared가 아무와도 연결되지 않는 문제는 더 이상 발생하지 않게 되었습니다.
개인 백업 전략에 백업 방식을 소개했습니다. 서버가 AWS에 있을 때는 백업을 전적으로 하루 단위로 수행되는 스냅샷에 의존했습니다. 아주 간단했고 스냅샷 작업이 수행되는 동안 아무런 성능 저하도 일어나지 않았습니다. 스냅샷은 7일 동안 보관되었고 그 안에 백업을 복원할 일이 생기면 그냥 스냅샷으로 새 서버 인스턴스를 생성한 다음 DNS를 그쪽으로 돌리기만 하면 문제를 해결할 수 있었습니다. 작은 문제라면 스냅샷을 7일보다 더 오랫동안 보관하려 하거나 스냅샷을 하루보다 더 짧은 주기로 기록하고 싶은 요구사항은 전혀 달성할 수 앖다는 것입니다. 또 스냅샷 역시 스토리지 요금 부과 대상이기에 서버에 퍼포스를 운영하기 시작하며 블록 스토리지 사용량이 증가하자 스냅샷 요금 역시 늘어나기 시작했습니다. 온프레미스 환경으로 옮겨 오면서 서버 상에서 돌아가는 모든 서비스를 외장 스토리지 상에 기록하도록 했는데 월 고정 비용 없이 이전과는 비교할 수도 없는 광활한 스토리지를 사용할 수 있게 된 것 까지는 좋았지만 이제 백업에 대한 온전한 책임을 져야만 했습니다. 만약 서버가 백업 없이 유실된다면 당장의 생활에 어떤 영향이 있지는 않겠지만 상당히 고통스럽고 또 불편할 겁니다. 이제 AWS가 제공하는 간단한 스냅샷은 존재하지 않았기에 직접 백업 전략을 수립하고 그에 따라 백업 작업을 완전히 자동화 해야 했습니다. 실은 지난 개인 백업 전략을 소개한 다음 몇 가지 에피소드를 겪고 나서 ‘크래시플랜을 사용하지 마세요’라고 주장하기 시작했기 때문에 지금의 백업 전략은 좀 바뀐 상태입니다만 핵심은 온프레미스 서버를 운영하기 시작하면서 백업 전략을 수립해야 했고 독립된 로컬 백업 두 개는 맥OS의 타임머신으로, 오프사이트 백업은 Arq Backup + B2 조합을 사용하고 있습니다.
처음 도커를 사용하기 시작할 때는 여러 예제들이 도커 이미지를 가져올 때 아무렇지도 않게 이미지 이름 뒤에 latest
태그를 붙여 가져오길래 이게 문제가 될 거라고 생각하지 못했습니다. 워낙 모든 예제들이 그렇게 만들어져 있었고 그냥 다들 당연히 그렇게 하는 줄 알았습니다. 하지만 서비스를 운영하는 입장에서 이게 썩 좋은 습관이 아니라는 사실을 실제 문제를 겪어본 다음에 깨달았습니다. 어떤 소프트웨어는 이전 버전에서 사용하던 스토리지 포멧을 감지하면 이를 마이그레이션 해 줍니다. 하지만 모든 소프트웨어가 모든 이전 버전으로부터 현재 버전으로 마이그레이션을 제공하지 않을 수도 있습니다. 제가 이 문제를 겪은 것은 mysql 데이터베이스 버전을 올릴 때였습니다. 처음 컨테이너를 만들 때는 8.3이 최신 버전이었는데 그 다음 최신 이미지를 가져와 인스턴스를 실행할 때는 최신 버전이 9.0이었는데 항상 latest 태그를 붙여 이미지를 가져오다 보니 제가 실행하던 버전이 뭔지, 새로 가져오는 버전이 뭔지도 몰랐습니다. 다만 새 이미지를 가져와 도커데스크탑 상에서 마우스로 실행 버튼을 딸깍 누른 다음 실행되었겠거니 하고 있었는데 데이터베이스에 의존하는 서비스들이 모두 이상한 응답을 하고 있었습니다. 데이터베이스 컨테이너 로그를 살펴보니 8.3에서 9.0으로 가는 마이그레이션을 제공하지 않아 실행을 중단한다는 메시지가 떠 있을 뿐이었고 그때서야 저는 제가 이전에 실행하던 데이터베이스 버전이 뭐였는지, 지금 업데이트 하려는 버전이 뭔지 알게 되었습니다. 다행히 마이그레이션을 지원하는 다른 정확한 버전 이미지를 가져와 실행하니 별 문제 없이 마이그레이션이 끝나 데이터베이스 컨테이너가 정상 실행되고 또 여기 의존하는 다른 여러 서비스들도 멀쩡해졌습니다. 하지만 이 사건 이후 도커 이미지를 가져올 때는 항상 정확한 버전을 가리키는 태그를 사용하고 또 버전을 변경할 때도 정확한 버전을 가리키는 태그를 사용하게 되었습니다. 어떤 컨테이너도 latest
태그로 동작하지 않습니다.
디지털 - 휴먼 API (2024)에서 퍼포스를 파일 관리 뿐 아니라 온갖 용도에 활용하고 있다고 소개했습니다. 사실 퍼포스에 파일을 서브밋 하는 대신 그냥 디렉토리로 파일을 분류해 놓고 백업을 잘 하기만 해도 아무런 문제가 없다는 사실을 종종 생각합니다. '굳이 이렇게 까지 해야 할까?' 하는 생각을 항상 합니다. 사실 그냥 파일시스템에 디렉토리 단위로 파일을 잘 구분해 사용하기만 하면 백업, 버전 관리는 맥OS의 표준 백업 프로그램인 타임머신이 알아서 해 줄 테니 더 이상 신경 쓸 필요가 없는 것이 사실입니다. 하지만 백업 프로그램의 버전 관리는 파일의 디렉토리 간 이동, 브랜치, 맥락에 기반한 버전 생성을 하지는 않습니다. 백업 프로그램은 그냥 기계적으로 파일이 바뀌면 새 버전을 생성합니다. 이는 물리적으로는 의미 있는 이전 버전을 찾을 수 있게 해 주지만 이 과정을 아주 길고 복잡하게 만듭니다. 하지만 퍼포스를 사용하며 제가 의미를 부여한 버전을 만들면 이전의 의미 있는 버전을 찾는 일이 너무나 단순해집니다. 또 디렉토리 구조를 변경할 때가 있습니다. 이전에 사용하던 파일 분류 방식이 더 이상 유효하지 않아 새로운 분류 방식을 적용합니다. 그런데 새 방식으로 전환한지 시간이 얼마 지나지 않아 아직 익숙하지 않을 때 이전에는 이 파일이 어디에 있었는지 궁금해질 때가 있습니다. 백업에 기반한 버전 관리로는 이를 파악하기 아주 어렵습니다. 하지만 퍼포스에서는 그냥 이전 상태로 되돌려보면 되고 또 각각의 파일이 이전에 어디에 있었는지 모든 기록을 파악할 수 있습니다. 또 어떤 파일을 수정할 때 그냥 그 파일을 수정하고 저장해 새 버전을 만들 수 있지만 짧은 시간 안에 이전 버전과 새 버전 양쪽 모두를 필요로 한다면 퍼포스의 로컬 디포 기준으로 그냥 파일 이름을 바꾼 형태로 브랜치를 만들 수 있습니다. 두 파일은 겉으로는 그냥 파일 이름 뒤에 ‘_최종’을 붙인 것처럼 보이지만 퍼포스에 의해 어느 버전으로부터 분리되었고 또 그 이후 어떻게 수정되어 왔는지 완전히 추적 되고 있습니다. 원한다면 아무 버전으로 돌아갈 수도 있고 이들을 머지해 한 파일로 만든 다음 나머지 한 쪽을 제거할 수도 있으며 이 모든 행동을 다 되돌릴 수도 있습니다. 근본적으로 이 모든 파일 기반의 행동이 매우 안전해집니다.
지금도 그렇지만 제가 사용하는 거의 모든 컨테이너는 다른 누군가가 이미 잘 만들어 놓은 이미지를 가져와 사용합니다. 다른 수많은 사람들이 똑같이 행동하고 있을 겁니다. 그런데 퍼포스는 제가 이 소프트웨어에 의존성이 점점 더 높아지면서 누군가 만들어 놓은 퍼포스 서버 이미지를 사용하는 것도 나쁘지 않기는 하지만 최소한 퍼포스 이미지 정도는 제가 직접 통제하는 것이 좋겠다고 판단했습니다. 사실 제가 사용하던 퍼포스 이미지는 컨테이너를 새로 생성하면 시간대를 한국 표준시로 바꾸고 오래 걸리는 작업을 터미널에서 수행하는데 필요한 tmux, 종종 퍼포먼스를 모니터링 하기 위한 htop 같은 유틸리티를 추가로 설치해야 했습니다. 만약 제가 퍼포스 이미지를 직접 통제한다면 드물기는 하지만 컨테이너를 재생성 할 때 이런 작업을 따로 수행할 필요가 없었습니다. 그래서 여전히 나머지 모든 컨테이너는 이미 누군가 만들어 놓은 이미지를 가져와 마우스로 딸깍 실행해 사용하지만 퍼포스에 한해서는 제 의도를 반영한 이미지를 만들어 사용하고 있습니다. 덕분에 퍼포스 서버가 계속해서 개발되며 기능이 추가되는 것을 관찰할 수 있고 이들 중 저에게 필요한 기능이 있다고 생각하면 선택적으로 업데이트 결정을 내릴 수 있게 되었습니다. 가령 지난 2024년에 퍼포스 서버에는 사용자 관점에서 크게 파일을 전송할 때 델타만 전송하는 기능이 추가되어 확장되었고 오브젝트 스토리지를 직접 디포 경로로 설정할 수 있게 되었습니다. 델타만 전송하는 기능은 회사에서 주로 인트라넷 환경으로 동작하는 퍼포스에는 별 도움을 주지 못할 것 같지만 제 경우처럼 인터넷을 통한 퍼포스 서버 운영에는 전송량을 줄여 큰 도움이 됩니다. 오브젝트 스토리지 지원은 처음에는 아카이브 디포에만 적용되었는데 이제 모든 디포에 적용됩니다. 하지만 이전에 아카이브 디포에 오브젝트 스토리지를 적용해 보고 그 느린 속도에 깜짝 놀란 다음에는 시도하지 않고 있습니다. 미래에 아카이브 디포를 사용한다면 잠깐 검토해볼 수 있을는지도 모르지만 트랜잭션 요금을 감안할 때 아카이브 디포에 p4 verify -a
명령 한 방에 순식간에 전재산을 탕진할 수 있는 위험을 감수할 필요는 별로 없어 보입니다.
AWS에서 도쿠위키를 운영할 때도 제 위키에 대한 의존성이 굉장히 높았습니다. 그래서 단 한 번 일어난 AWS 하드웨어 장애 때 만 하루 동안 제 위키에 접근하지 못하는 상태가 되자 저는 완전히 바보가 되었습니다. 생각을 할 수도 없고 기억을 해낼 수도 없는 그냥 밥 먹고 똥 싸는 기계에 불과했습니다. 이 때 개인 수준에서도 가용성이 중요하다는 교훈을 얻었습니다. 지금은 완전관리되는 컨플루언스 클라우드를 사용하니 그럴 일이 없지만 저 때 하루 동안 도쿠위키를 사용할 수 없게 되자 가용성을 유지하기 위해 작은 서버를 하나 더 만들어 도쿠위키만 실행하고 두 서버가 서로 같은 데이터를 바라보게 만드는 일종의 로드밸런싱 같은 뭔가를 만들었습니다. 사실 도쿠위키가 데이터베이스 기반이었다면 이 요구사항은 훨씬 안정된 모양으로 구축할 수 있었을텐데 도쿠위키는 파일시스템에 완전히 의존하기 때문에 두 서버가 같은 데이터를 바라보고 동작하게 만들기는 꽤 어려웠습니다. 지금은 어떨는지 모르겠지만 저 때는 여러 서버 사이에 파일시스템을 일관성 있게 동기화 하는 신뢰할 만한 솔루션이 거의 없었습니다. 여러 가지 방법이 있었지만 하나같이 제 요구사항을에 부합하지 않았습니다. 이 가용성 문제는 완전관리되는 위키를 사용하면서 사라졌다가 퍼포스에 의존성이 높아지면서 다시 나타났습니다. 사실 맥미니가 고장을 일으킬 일은 별로 없을 테고 만약 고장을 일으킨다면 제가 할 수 있는 일은 수리하거나 수리가 불가능하다면 새 맥미니를 구입해 복원하는 것 뿐입니다. 이 사이에 가용성이 0이 되는 것은 어쩔 수 없습니다. 다행히 아무런 데이터 유실도 일어나지 않을 겁니다. 하지만 만약 외장 스토리지에 문제가 생긴다면 상황은 완전히 달라집니다.
물론 저는 똑같이 지금 사용하던 외장 스토리지에서 하드디스크를 뽑아 교환 요청을 보낼 겁니다. 만약 교환 기간이 끝났다면 일단 새 하드디스크를 주문하고 기존 하드디스크를 관통하도록 못 여러 개를 박은 다음 폐기할 겁니다. 새 하드디스크가 도착하면 다시 복원하면 되긴 하지만 오프사이트 백업은 물론이고 로컬 백업으로부터 복원하는데도 여러 시간이 걸릴 겁니다. 아직 서버의 전체 데이터 사용량은 한 자리 수 테라바이트에 머물고 있지만 사용량이 증가함에 따라 복원 시간은 점점 더 길어질 겁니다. 이 시간이 길어짐에 따라 서버 전체를 사용할 수 없는 시간이 점점 더 길어지고 저는 이전에 도쿠위키를 사용할 수 없을 때처럼 꽤 바보 같은 상태가 될 가능성이 있습니다. 이전과 달리 이번에는 99.90%의 SLA를 제공하는 컨플루언스 클라우드가 있으니 이전과 같이 완전 바보가 되지는 않겠지만 서버의 여러 기능이 동작하지 않고 특히 퍼포스가 동작하지 않으면 아주 불편하고 괴로울 겁니다. 이번에도 가용성이 중요한 상황입니다. 그래서 그냥 뻔한 외장하드로 유지하던 것을 하드디스크 두 개를 레이드 1로 묶어 사용하기 시작했습니다. 나머지는 이전과 똑같습니다. 여전히 타임머신에 의한 로컬 백업 두 개, Arq Backup + B2에 의한 오프사이트 백업 한 개를 가지고 있습니다. 이번에는 하드디스크 두 개 중 어느 한 개가 문제를 일으키더라도 서비스가 중단되지 않습니다. 새 하드디스크가 도착해 레이드 리빌드가 끝나기 전까지 잠깐 불안하기는 하겠지만 서비스는 이전과 똑같이 동작하고 디스크 하나로 동작할 때 속도 저하는 없거나 거의 없을 겁니다. 리빌드 과정은 다른 레이드 레벨에 비해 극히 단순해 오래 걸리지 않을 테고요.
사실 문제가 생기지는 않았지만 서버에서 사용하던 스토리지를 하드디스크 하나가 들어있는 제품에서 하드디스크 두 개가 들어있는 제품으로 옮기면서 파일을 한 드라이브에서 다른 드라이브로 직접 복사해 와야 했는데 사용량이 아직 한 자리 수 테라바이트에 불과한데도 꽤 긴 시간이 걸렸습니다. 이 시간 동안 모든 서비스를 사용할 수 없었음은 물론이고요. 사실 원한다면 스토리지를 많이 사용하는 퍼포스를 제외한 나머지 서비스 스토리지를 맥미니 내장 SSD로 옮겨 서비스를 지속할 수 있음을 알고 있었지만 이건 좀 귀찮았습니다. 그냥 모든 서비스를 다 다운 시켜 놓고 스토리지를 옮겼습니다. 이전에는 만 24시간 이상이 소요되었는데 이전이 끝난 다음 서비스를 재개하고 나서 제가 파일시스템을 잘못 선택했다는 사실을 깨닫고 똑같은 작업을 다시 수행하느라 또 다른 24시간 이상이 소요되었습니다. 이 경험을 통해 서버의 가용성을 유지하는 일이 꽤 중요하다는 교훈을 다시 한 번 얻었습니다. 이제 적어도 단일 하드디스크 고장에 의해서는 서비스가 중단되지 않습니다. 또 스토리지를 확장하려 할 때도 서비스 중단이 필요 없습니다. 만약 스토리지를 확장하려 한다면 큰 하드디스크 두 개를 산 다음 첫 번째 드라이브를 교체하고 리빌드 되기를 기다리고 또 두 번째 드라이브를 교체하고 리빌드 되기를 기다린 다음 디스크 유틸리티에서 파티션 크기를 조절하기만 하면 됩니다. 이 과정 중 어느 부분에도 서비스 중단이 필요하지 않습니다. 사실 처음 인프라를 구축할 때 비슷한 시점에 생산된 비슷한 하드디스크가 비슷한 환경에 노출된 덕분에 첫 번째 하드디스크 고장이 일어나고 이 상황이 완전히 해결되기 전 두 번째 하드디스크 고장이 일어나 데이터를 유실한 여러 사례를 읽었습니다. 저 역시 비슷하게 레이드 1 환경에서 두 디스크가 각자의 문제를 해결하기 전에 비슷한 시점에 고장 날 가능성이 있음이 조금 걱정되긴 합니다. 하지만 그 정도 운이 없으면 그 다음은 백업의 영역이라고 생각하기로 했습니다.
최근에는 로컬에서 LLM을 직접 돌려 활용하고 또 n8n을 경유한 자동화를 하는 사례가 굉장히 흔해진 것 같습니다. 이전 회의를 녹음해 요약하려는 시도는 왜 멍청한가?에서 컨플루언스 클라우드에서 사용할 수 있는 아틀라시안 인텔리전스가 왜 아직 충분히 훌륭하지 않은지 이야기했는데 만약 LLM을 로컬에서 직접 구동할 수 있다면 이런 문제의 상당 부분을 직접 해결할 수 있지 않을까 싶은 생각이 들었습니다. LLM을 직접 트레이닝 하는데는 엄청난 자원과 이를 통제하는 인간의 지식이 필요하지만 이미 누군가 만든 모델을 활용하되 이 모델이 참고할 문서들을 백터 데이터베이스에 미리 기록해 놓는다면 모델을 직접 훈련 시킬 일 없이 여러 문서를 LLM이 참고하게 한 상태에 프롬프트를 입력해 이전에는 접근할 수 없었을 새로운 가능성을 열 수 있을 거라고 기대하고 있습니다. 하지만 모델을 훈련 시키는 것이 아니라 그저 모델을 사용하기만 하려 해도 지금까지는 굉장히 고사양으로 느껴지던 맥미니 M1 기본 모델은 아무 것도 할 수 없었습니다. LLM을 로컬에서 구동하고 n8n을 사용해 자동화하며 쿼드런트 벡터 데이터베이스에 문서를 미리 적재해 놓는다면 속도가 약간 느리더라도 저 혼자 사용하는 정도라면 감당할 수 있지 않을까 싶어 비용을 투자해 문제에 도전해 보기로 결정했습니다. 이전에 맥미니에 기반해 서버를 운영한 경험이 좋아서 이번에도 하드웨어는 간단히 맥미니를 선택했습니다. 다만 이번에는 미친 사람처럼 메모리를 최대한 많이 붙인 모델을 주문했고 이 사양에서는 아마도 로컬에서 LLM을 구동하는데 적어도 개인 수준에서는 어떻게 비벼볼 수 있으리라 기대하고 있습니다.
여러 장점과 확장 가능성에도 불구하고 불편하고 귀찮은 점도 있습니다. 맥미니는 개인용 서버로 사용하기에 충분합니다. 저전력, 거의 무소음 같은 특징은 너무 훌륭합니다. 하지만 여기에 외장 스토리지를 붙이는 순간 소음 문제가 발생합니다. 또 도커는 대체로 안정적으로 동작하지만 종종 문제를 일으킵니다. 도커 자체가 크래시 되어 모든 컨테이너가 동작을 멈추는 일도 일어납니다. 아마도 본격적으로 도커를 서비스에 적용하는 분들은 이런 상황의 가용성을 유지하는 어떤 방법이 있겠지만 저는 그냥 원격에서 접속해 도커를 재시작하는 것 밖에 방법이 없습니다. 원격 접속은 테일스케일을 경유한 SSH를 열어 놓고 있습니다만, 서버에 문제가 생겨 즉시 대응해야 하는 상황 대부분은 크롬 리모트 데스크탑을 사용합니다. 폰만 덜렁 들고 있는 상황에서 서버의 현재 상태를 쉽게 알 수 있고 도커 컨테이너에 의존하지 않기 때문에 도커가 크래시 된 상황에서도 여전히 사용할 수 있기 때문입니다. 실은 크롬 리모트 데스크탑을 다른 오픈소스 제품으로 바꿀 생각을 한 적이 있지만 종종 도커가 크래시되는 상황으로 미루어 크롬 리모트 데스크탑 쪽이 차라리 더 나아 보입니다.
처음 AWS에서 온프레미스 환경으로 서버를 가져올 때는 서버에 의존성이 지금처럼 높아지지 않으리라 예상했습니다. 저는 그저 AWS 비용을 매달 지불하고 싶지 않았을 뿐이었습니다. 그런데 하드웨어를 직접 통제하고 그 사양이 나쁘지 않은 수준이 되자 요구사항이 갑자기 확장되었습니다. 가령 이전에는 정말 버전 관리가 필요한 파일만 서브밋 하던 퍼포스가 지금은 그냥 제가 가지고 있는 거의 모든 파일을 서브밋 하는데 사용되는 식입니다. 만약 서버가 AWS에 있었다면 이를 LLM을 구동할 수 있는 수준으로 확장할 상상 조차 하지 않았을 겁니다. 하지만 하드웨어를 직접 통제할 수 있게 되자 이런 의사결정을 할 수 있게 되었습니다. 이 정도 저지르고 보니 이제 데이터센터로는 돌아갈 수 없을 것 같습니다. 이전에 AWS를 사용할 때처럼 이번에도 적어도 몇 년은 지금과 비슷한 체계를 유지할 것 같습니다.