새벽 2시, 9달러를 주고 홍콩 리전 Mac mini M4 인스턴스를 막 대여했다. SSH 키는 5분도 안 되어 이메일로 도착했다. 신나서 접속한 뒤 가장 먼저 입력한 명령이 brew install node. 그런데 진행 바가 bottle 다운로드 단계에서 딱 멈춰 움직이지 않는다. 터미널을 새로 고쳐보면 curl이 연결 타임아웃을 알리며 재연결을 반복한다. 20분이 지나도 원래는 3초면 끝날 tarball 하나를 여전히 기다리고 있는 상황이다. 이건 네트워크 장애가 아니라, 해외 리전에서 Homebrew 공식 CDN에 접속할 때 겪는 "일상적인 지연"일 뿐이다——게다가 새 인스턴스를 띄울 때마다 이 지연을 매번 다시 겪게 된다.
시나리오: 새 머신 받자마자, 의존성 설치가 대여 시간의 절반을 잡아먹는다
클라우드 Mac mini를 일 단위로 대여하는 장점은 언제든 켜서 쓸 수 있다는 점이지만, 단점은 새 인스턴스마다 매번 백지 상태에서 시작해야 한다는 것이다. Xcode Command Line Tools를 설치하고 팀의 setup.sh를 한 번 돌리는, 이 흔한 과정에서 brew install이 수많은 패키지를, npm install이 수많은 의존성을, pod install이 CocoaPods 인덱스를 다시 끌어온다. 공식 소스는 전부 해외 오리진 서버를 가리키고 있어서, 다운로드 속도만으로도 머신 하루치 대여료에 맞먹는 작업 시간이 사라진다. 하루만 빌려서 일회성 작업을 처리할 계획이라면 이 비용은 특히 아프게 느껴진다.
클라우드 노드에서 공식 소스가 유독 느린 이유
Homebrew의 bottle(사전 빌드된 바이너리)은 기본적으로 GitHub Packages에 저장되어 있고, npm의 공식 레지스트리와 CocoaPods의 spec 저장소 역시 해외 인프라에 호스팅되어 있다. 클라우드 사업자의 국제 대역폭 자체는 대체로 충분한 편이지만, 구체적인 CDN 노드까지의 라우팅 품질은 제각각이다. 특히 첫 연결 시 TLS 핸드셰이크와 DNS 해석이 누적되면 그것만으로도 수십~수백 밀리초의 지연이 생기고, 이게 수백 개의 의존성 패키지만큼 곱해지면 분 단위, 심하면 시간 단위의 대기로 이어진다. 머신이 느린 게 아니라 경로가 느린 것이다.
재사용 가능한 가속 파이프라인을 3단계로 구축하기
1단계: Homebrew의 저장소와 bottle 도메인 전환하기
먼저 지금 쓰는 Homebrew가 이미 국내 접근성이 좋은 미러를 가리키고 있는지 확인한 다음, 환경 변수를 한꺼번에 바꾼다. 터미널 세션을 다시 시작하면 적용된다.
git -C "$(brew --repo)" remote set-url origin \
https://mirrors.example-mirror.net/homebrew-core.git
export HOMEBREW_API_DOMAIN="https://mirrors.example-mirror.net/homebrew-bottles/api"
export HOMEBREW_BOTTLE_DOMAIN="https://mirrors.example-mirror.net/homebrew-bottles"
brew update
이 세 줄을 ~/.zprofile에 적어두면, 다음번 부팅부터는 다시 설정할 필요가 없다.
2단계: Brewfile로 의존성 목록 고정하기
brew install을 하나씩 손으로 치지 말고, 팀에서 자주 쓰는 패키지를 Brewfile에 정리해두고 한 번의 bundle 실행으로 몰아서 설치하자. 여러 노드 사이에서 버전을 일치시키는 데도 도움이 된다.
tap "homebrew/cask"
brew "node@20"
brew "cocoapods"
brew "watchman"
brew "git-lfs"
cask "visual-studio-code"
brew bundle --file=~/Brewfile
Brewfile 자체는 수십 줄 정도라 코드 저장소에 보관해두면 된다. 새 머신을 받으면 프로젝트 저장소를 git clone한 뒤 bundle을 한 번 실행하는 것만으로 끝나고, 설치 명령을 하나씩 검색하는 것보다 훨씬 빠르며 숨어 있는 의존성을 빠뜻리는 일도 줄어든다.
3단계: 언어별 패키지 매니저에도 같은 미러 적용하기
Homebrew 가속만으로는 문제의 일부만 해결된다. npm, pip, CocoaPods는 각자 기본 소스가 따로 있어서 하나씩 설정해줘야 한다.
npm config set registry https://registry.example-npm-mirror.com
pip config set global.index-url https://pypi.example-mirror.com/simple
pod repo-art add master https://cdn.example-cocoapods-mirror.com/master.git
네 개 경로를 모두 바꾸고 나면, 완전히 새로운 Mac mini에서 의존성 압축 해제부터 첫 빌드가 통과하기까지 걸리는 시간 차이가 뚜렷하게 나타난다.
| 단계 | 공식 소스 실측 | 미러 적용 후 |
|---|---|---|
| Xcode CLT + Homebrew 코어 패키지 | 약 22분 | 약 4분 |
| npm install(중형 프로젝트) | 약 9분 | 약 2분 |
| pod install(iOS 프로젝트) | 약 7분 | 약 2분 |
| 합계 | 약 40분 | 약 8분 |
미러 전환이 공짜는 아니다. 미러 사이트가 공식 저장소와 동기화되기까지 몇 분에서 몇 시간의 지연 구간이 존재한다. 중요한 버전을 업그레이드한 뒤에는 먼저
brew doctor로 자체 점검을 한 번 돌리고, 핵심 bottle에 대해shasum -a 256검증을 수행해 해시 값이 공식 릴리스와 일치하는지 확인한 뒤 프로덕션 흐름에 반영하는 것을 권장한다.
데워둔 환경을 스냅샷으로 저장해 다음번에 그대로 재사용하기
같은 노드를 주 단위나 월 단위로 계속 재대여할 계획이라면, 가속 파이프라인을 한 단계 더 발전시킬 수 있다. 의존성을 설치하고 빌드가 한 번 통과한 뒤, ~/Library/Caches/Homebrew, node_modules의 공용 캐시 디렉터리, ~/.cocoapods를 하나로 압축해서 자신의 오브젝트 스토리지에 올리거나, OnceMini 콘솔에서 현재 인스턴스의 스냅샷을 한 번 만들어두자. 다음번 갱신이나 OS 재설치 후에는 그 스냅샷에서 디스크 상태를 바로 복원하면 되고, 미러 설정 단계마저 건너뛸 수 있다. 실측으로는 이 사용자 디렉터리 캐시 아카이브 크기가 8GB~15GB 정도인데, OnceMini의 256GB부터 시작하는 SSD 플랜이라면 이 정도 여유 공간은 충분해서 일반 프로젝트 파일 저장 용량을 침범하지 않는다.
체크리스트
배포 전에 하나씩 대조해보자. 빌드가 실패한 다음에야 빠진 단계를 발견하는 상황은 피하는 게 좋다.
- Homebrew 환경 변수 세 개를
~/.zprofile에 적었는가(현재 세션에서export만 하고 끝난 게 아닌가) Brewfile을 프로젝트 저장소에 커밋했는가(누군가의 로컬 터미널 히스토리에만 남아 있는 게 아닌가)- npm/pip/CocoaPods 세 곳 미러를 모두 전환했는가(Homebrew만 바꾸고 끝난 게 아닌가)
- 핵심 bottle에 대해
shasum검증을 한 번 수행했는가 - 같은 노드를 재대여할 계획이라면, 환경 스냅샷을 한 번 만들어두었는가
자주 묻는 질문
미러로 바꾸면 bottle이 불완전하게 받아지지 않나요?
정식 미러는 공식 저장소와 주기적으로 전체 동기화되지만 수 분에서 수 시간의 지연이 있습니다. 설치 후 brew doctor와 shasum으로 핵심 bottle을 검증하세요.
환경 스냅샷에는 용량이 얼마나 필요한가요?
Command Line Tools, Homebrew 핵심 패키지, 주요 언어 런타임을 포함한 캐시는 실측 8~15GB 정도로, OnceMini 256GB 이상 SSD 플랜이면 충분합니다.
하루만 대여해도 이 가속화가 필요한가요?
단발성 작업이라면 미러 전환용 export 명령 세 줄만으로 충분하고 스냅샷은 필요 없습니다. 같은 노드를 주 단위·월 단위로 재대여할 때 스냅샷이 진짜 이득입니다.
빌드 프로세스를 위한 전용 Mac mini가 필요하신가요?
지금 주문