VPS처럼 연산을 관리하는 사고에 익숙하신데, React Native/Expo에서 EAS 대기열, 네이티브 모듈, 자격 증명 형태에 막히셨다면, 이 글은 호스팅 빌드와 전용 macOS 면을 한 장의 대조표에 놓습니다. 먼저 아픔을 쪼갠 뒤, 결정용 표와 6단계 런북, 마지막으로 감사 가능한 셀프 호스팅 리듬으로 이어집니다. 읽기를 마치면 언제 EAS를 이어 쓰는 것이 맞는지, 언제 노드를 임대하듯 iOS 빌드를 전용 리모트 Mac으로 옮기는 것이 맞는지가 분명해집니다.
Expo Application Services(EAS)는 인증서, 업로드, 클라우드 빌드를 잘 감싸 주어 표준 경로에 맞습니다. 다만, 저장소에 네이티브 패치, 비공개 Pod, 혹은 빌드 로그와 명령 감사를 컴플라이언스 패키지에 담아야 하면, 호스팅 풀의 불투명한 대기와 이미지 경계가 마찰로 바뀝니다. 아래 여섯 가지는 실제 장애 대응에서 뽑은 정리이며, SSH로 들어갈 수 있는 빌드 면이 더 필요한지 가늠하는 데 쓰시면 됩니다.
대기열의 의미가 불명확합니다. 같은 워크플로도 피크에선 수십 분을 기다릴 수 있으며, 비즈니스 쪽에서 릴리스 창을 잠가 두었다면, 이러한 불확실성이 곧 사고 위험으로 이어집니다. 전용기처럼 최대 동시 실행을 내부 SLA에 적기 어렵습니다.
네이티브 의존 체인이 깁니다. react-native-config, Firebase, 지도, 블루투스 등이 커스텀 Podspec이나 사전 컴파일 스크립트를 요구하면, 이미지 캐시 적중이 떨어지고 한 번의 빌드 시간 변동이 커집니다. xcodebuild -showBuildSettings 전체를 대조하려는데 호스트 셸이 없다면, 원인 추적이 막힙니다.
자격 증명·서명 모델이 갈라집니다. EAS 호스팅 서명과 내부 match, 자체 CA를 동시에 쓰면, 로컬 Archive는 되는데 클라우드는 간헐적 실패가 생깁니다. 열쇠고리맥락과 CODE_SIGN_IDENTITY 조합이 호스팅 이미지에 완전 복제되지 않는 경우가 많기 때문입니다.
디스크와 DerivedData 수위를 통제할 수 없습니다. 큰 모노레포는 호스팅 쪽에서 정리 정책에 더 자주 휩쓸여, 캐시에 뜨거운 층이 사라집니다. UI 테스트와 Archive를 반복하는 팀에는 예측하기 어려운 꼬리가 붙습니다.
이미 쓰는 CI 레이블 체계와 끊깁니다. 백엔드·웹에 GitHub Actions의 레이블, 동시 상한, 셀프 호스팅 러너를 써 두고, iOS만 다른 오케스트레이션에 싣는 구조이면, 운영 멘탈이 갈리고, 당번 비용이 오릅니다.
감사 필드가 부족합니다. 금융, 의료, 해외 컴플라이언스는 ‘누가, 어느 IP에서, 어느 빌드기에, 어떤 명령을’ 남기는지를 요구합니다. 호스팅 측이 내부 SOC2에 맞는 SSH·세션 로그를 내보내지 못하면, 전용 노드로 증거 사슬을 메워야 합니다.
위에서 둘 이상에 해당하시면, 대조 표와 런북을 이어 읽는 것이 좋습니다. 가끔만 빌드하고, 네이티브 층이 얇다면, EAS를 먼저 쓰고, 면을 일찍 쪼갤 필요는 없습니다. 러너를 전용기에 붙이는 세부는 사내 GitHub Actions 셀프 호스팅 러너 글을 참고하시고, 이 글은 RN/Expo에서의 역할 경계에 맞춥니다.
두 안을 한 표에 둔 이유는 EAS를 부정하려는 것이 아니라, 검토회에서 대기열, 이미지, 서명, 감사를 같은 말로 말하려는 것입니다. 아래는 eas.json 프로필을 쓰시고, macOS 기초 운영을 갖추었다는 전제를 둡니다.
| 차원 | EAS Build(호스팅) | 전용 리모트 Mac 셀프 호스팅 |
|---|---|---|
| 전달 속도(콜드 스타트) | 높음. 기기 구매·시스템 설치를 덜 끌고 갑니다. | 중간. SSH, Ruby/Node 핑거프린트, 러너 등록을 한 번에 끝내야 합니다. |
| 대기열·동시성 통제 | 플랫폼 풀에 맡겨, 피크는 예측하기 어렵습니다. | 전용 CPU/디스크이며, 동시 상한과 정리 창을 문서에 박을 수 있습니다. |
| 네이티브 스택 복잡도 | 표준 Expo 호스팅 흐름에 잘 맞습니다. | 깊은 네이티브, 맞춤 Pod, 사전 컴파일, 로컬 패치에 맞습니다. |
| 서명·인증서 전략 | EAS 호스팅 자격과 깊게 맞닿습니다. | match, 자체 KMS, 환경별 열쇠고리와 끝까지 맞출 수 있습니다. |
| 로그·감사 | 플랫폼 로그가 중심이며, 제품이 허용하는 정도에 묶입니다. | xcodebuild와 셸 세션을 끝까지 수집해 내부 감사에 맞출 수 있습니다. |
| 운영 멘탈 | 낮음. ‘서비스형 CI’에 가깝습니다. | 중~높음. ‘VPS 군집’에 가깝습니다. |
「호스팅 빌드는 0에서 1까지, 전용 노드는 1에서 N의 예측 가능성·감사 가능성에 가깝습니다.」
흔한 절충은 일상 PR·패키징은 EAS에 남기고, Release Archive, UI 테스트 행렬, 시행착오가 잦은 네이티브 반복을 전용 리모트 Mac으로 보내는 것입니다. 가장 비싼 인력이 드는 구간을 통제 가능한 쪽에 두고, 동시에 호스팅 쪽의 통합 편의는 유지합니다.
아래는 팀 규모 × 네이티브 깊이 × 컴플라이언스 강도로 끊은 실무 결론입니다. 용량 계획을 대체하지는 않지만, 아키텍처 검토에서 우선순위를 맞출 때 쓰시면 됩니다.
| 신호 | EAS를 주력으로 | 전용 리모트 Mac |
|---|---|---|
| 네이티브 의존 | 커뮤니티 모듈만 조금, 커스텀 Pod가 없을 때 | 비공개 Pod, 바이너리 폐쇄 SDK, 커스텀 컴파일 플래그가 있을 때 |
| 릴리스 리듬 | 주간·격주, 대기열 변동을 조금 감쌀 때 | 일간이거나, 시간 상자 릴리스로 동시·창을 써야 할 때 |
| 컴플라이언스 | 감사 필드 강제가 약할 때 | SSH/명령 수준 감사, 고정 출구, 구획된 VPC가 필요할 때 |
| 기존 CI | iOS와 백엔드가 완전히 떨어질 때 | iOS 잡을 GitHub Actions·GitLab과 같은 레이블·캐시에 두고 싶을 때 |
// eas.json 일부: 프로필로 「호스팅」과 「외부 셀프 호스팅」을 갈랐습니다
{
"build": {
"preview": { "distribution": "internal", "channel": "preview" },
"release-selfhosted": {
"extends": "production",
"env": { "EXPO_USE_FAST_RESOLVER": "1" },
"ios": { "image": "latest" }
}
},
"submit": { "production": {} }
}
주의: 한 브랜치에 호스팅·셀프 호스팅을 섞는다면, README에 어느 프로필이 어느 자격 증명을 쓰는지 분명히 적으십시오. 그렇지 않으면 신규 팀원이 열쇠고리와 EXPO_TOKEN 사이를 헤맵니다.
표 밖의 단단한 경험은, ‘돌아간다’를 ‘재현 가능’과 섞지 말 것입니다. 호스팅 이미지는 뒤에서 올라가고, 저장소에 Xcode·Node 소버전을 박지 않으면, 네이티브 층이 뜻없는 업그레이드 한 번에 붉어질 수 있습니다. 전용 노드는 xcode-select와 Ruby Bundler를 커널 버전처럼 잠그고, CI 계약에 핑거프린트를 씁니다.
로컬에서 npx expo prebuild로 iOS 프로젝트를 낼 수 있고, 전용기에서 xcodebuild나 Fastlane을 돌릴 수 있다는 전제입니다. VPS 익숙하신 분께 맞춰, 계정·키·디스크 수위·로그 반송 네 가지를 한 번에 관통하는 순서로 적었습니다.
툴체인 핑거프린트를 얼립니다. 리모트 Mac에서 xcodebuild -version, node -v, ruby -v, pod --version을 기록해 저장소의 BUILD_ENV.lock에 둡니다. 올릴 때는 PR로만, 누군가 SSH로 손으로 올리는 일을 막습니다.
CI용 비로그인 대화형 사용자를 둡니다. 개인 Apple ID 세션으로 배치 잡을 돌리지 말고, 러너·SSH 잡에 전용 사용자와 열쇠고리 구획을 씁니다. 사내 재현 가능한 빌드 글의 열쇠고리 격리와 맞춥니다.
DerivedData와 Pods 경로를 쪼갭니다. 저장소·브랜치마다, 예를 들어 ~/DerivedData/$REPO/$BRANCH와 ~/PodsCache/$REPO에 따로 쌓고, 정리는 시스템에 맡기지 않고 cron에 적은 정책으로 합니다.
iOS 잡을 주 CI에 다시 붙입니다. GitHub Actions·GitLab에서 셀프 호스팅 레이블을 전용기로 향하게 하고, Android 잡과 같은 승인·동시성 게이트를 씁니다. 화면이 필요한 순간엔, 장기로 데스크톱을 켜 두지 말고, 통제된 VNC 창을 쓰는 편이 낫습니다.
산출물·로그를 반송합니다. 통제한 객체 스토리지나 내부 아티팩트 저장소에 .ipa, dSYM, xcodebuild 원본 로그를 둡니다. 금융 고객이면, 사후 조사에 맞는 명령 수준 녹화를 더합니다.
2주 대조 실험을 합니다. 대표 브랜치 다섯을 골라, EAS와 전용기의 P50·P95 빌드와 실패 유형을 동시에 기록합니다. 전용기가 네이티브가 무거운 케이스에서 안정적이고 대기열 분산이 작다면, Release 트래픽을 옮깁니다.
안내: 지역·디스크 등급을 아직 정하지 못하셨다면, Mac Mini 대여 가격을 먼저 읽고, 동시 × 디스크 수위 × 출구 지역 세 축을 조달 첨부에 넣은 뒤, 위의 여섯 단계와 합쳐 검수하십시오.
xcodebuild가 링크에서 무작위로 쓰러질 수 있습니다.iOS 빌드를 호스팅 풀에만 묶으면, 당장 인력이 덜 듭니다. 다만, 네이티브 의존, 감사 필드, 기존 Actions·GitLab과의 같은 스케줄이 ‘될 수 없는 제약’이면, 불투명한 대기와 못 박을 수 없는 이미지가 불확실성을 키웁니다. 반대로, Mac 군집이 디스크 거버넌스·핑거 전략 없이 서면, ‘또 다른 기술 부채’로 무너질 수도 있습니다.
정리하면, 7×24로 대기를 예상하고, 명령 세션을 감사하고, 기존 러너 레이블과 맞출 RN/Expo 팀은 무거운 부하는 전용 macOS 쪽이 낫고, EAS는 가볍게 통합하거나 대외 협업에 쓰는 쪽이 맞는 경우가 많습니다. 실행 환경을 계약한 노드로 두고, 대기 분산을 줄이며, iOS CI/CD와 돌아가는 자동화에 쓰시려면, NodeMini Mac Mini 클라우드 대여를 검토하시는 편이 합리적입니다.
iOS 빌드를 늘리기 쉬운 노드로 취급해야 하고, 디스크·동시를 고정하고, 명령 수준으로 로그를 내보내야 하거나, 혹은 네이티브 체인이 호스팅 이미지에 맞지 않을 때, 전용 리모트 Mac이 맞습니다. Mac Mini 대여 가격을 보고, 작은 파일럿 먼저 붙이신 뒤, Release 잡을 전부 옮길지 정하십시오.
그렇기 때문에, 프로필과 열쇠고리 경계를 나눕니다. 호스팅은 EAS 서명, 셀프 호스팅은 match나 기업 KMS에 두고, README에 언제 어느 쪽을 쓰는지 적습니다. 연결·권한은 클라우드 Mac 도움말 센터의 SSH·계정을 함께 읽으십시오.
러너 글은 레이블, 캐시, 대기를 다루고, 이 글은 RN/Expo에서 EAS와 전용 사이 역할을 다룹니다. 이미 리모트 Mac에 러너를 올리셨다면, 이 글의 여섯 단계를 상선 검수 확장으로 쓰시면 됩니다.