빌드는 끝났지만 Simulator 테스트와 앱 서명 단계에서 실패하고, Linux 작업자에는 Apple SDK가 없습니다.
가장 빠른 해법은 Bazel 9 iOS 빌드에서 플랫폼을 나누는 것입니다. 일반 검사와 비애플 테스트는 Linux에 남기고, Xcode, Apple SDK, Simulator, 서명과 패키징을 쓰는 작업은 실제 macOS 노드로 보냅니다.
이번 주 권장 행동: 현재 CI에서 실패한 작업의 이름을 추측하지 말고 실행 로그와 작업 정보를 수집한 뒤, 작은 iOS 프로젝트를 깨끗한 원격 맥에서 끝까지 빌드하고 서명해 보십시오.
이 글은 Bazel 9를 iOS 프로젝트에 연결하는 빌드 엔지니어, Linux CI 집합을 관리하는 DevOps 엔지니어, Apple 플랫폼 빌드 용량을 늘리려는 기술 책임자를 위한 글입니다. 단일 원격 맥으로 시작할지, Linux와 원격 맥을 섞을지, 아직 이전하지 않을지를 판단하는 데 초점을 둡니다.
마지막 확인은 2026년 8월 29일입니다. Bazel의 공식 발표와 지원 정책, Apple의 Xcode 26 안내, rules_apple과 rules_swift의 공개 자료를 기준으로 정리했습니다. 세부 규칙 조합과 작은 버전의 호환성은 변경될 수 있으므로 배포 전 Bazel 9 공식 발표, rules_apple 공식 릴리스를 다시 확인해야 합니다.
먼저 나눠야 할 것은 도구가 아니라 실행 플랫폼입니다
Bazel은 빌드 그래프와 작업 실행을 조정합니다. 그러나 Apple SDK나 Xcode 도구 모음을 제공하지는 않습니다. rules_apple은 Apple 대상 규칙을 정의하고, rules_swift는 Swift 관련 규칙을 담당하며, Xcode는 SDK와 컴파일, 링크, Simulator, 서명에 필요한 Apple 도구를 제공합니다. 각 역할은 Bazel 플랫폼과 도구 모음 문서, rules_swift 안내서, Apple Xcode 26 릴리스 노트에서 따로 확인해야 합니다.
따라서 명령이 Linux에서 시작된다는 사실만으로 iOS 납품이 가능하다고 판단하면 안 됩니다. Apple SDK를 읽는 작업, Apple 플랫폼 바이너리 링크, Simulator 실행, 보관, 서명과 앱 내보내기는 일치하는 macOS와 Xcode 환경을 요구합니다. Apple의 플랫폼 빌드 요구 사항도 제출 도구와 SDK 조건을 별도로 제시하므로, Apple의 플랫폼 빌드 요구 사항을 배포 계획에 포함해야 합니다.
Bazel 9의 지원 상태가 확인되더라도 프로젝트의 실제 규칙 버전, rules_apple, rules_swift, Xcode 26과 SDK의 조합이 곧바로 검증되는 것은 아닙니다. MODULE.bazel에서 선언한 모듈과 릴리스 기록을 확인하고, 문제가 공식적으로 해결된 것인지 단순한 커뮤니티 제보인지 구분해야 합니다.
세 가지 CI 구조를 같은 지표로 비교합니다
| 선택지 | Linux에 둘 작업 | macOS에 둘 작업 | 적합한 조건 | 먼저 볼 지표 |
|---|---|---|---|---|
| 단일 원격 맥 | 일반 검사와 일부 생성 작업 | 빌드, 링크, Simulator, 서명, 패키징 | 작은 팀이 전체 흐름을 먼저 검증할 때 | 작업 성공, 재부팅 복구, 대기 시간 |
| Linux와 원격 맥 혼합 | 검사, 일반 생성, 독립 테스트 | Apple SDK 작업과 배포 작업 | 중간 규모 이상 팀이 작업을 병렬화할 때 | 플랫폼별 작업 수, 캐시 적중, 맥 대기열 |
| 이전 보류 | 기존 검증 흐름 유지 | 필요한 순간에만 별도 검증 | 규칙과 Xcode 조합이 아직 불명확할 때 | 실패 원인, 미선언 의존성, 재현성 |
혼합 구조가 기본 선택처럼 보이더라도 모든 팀에 즉시 맞는 것은 아닙니다. 작은 팀은 단일 원격 맥에서 깨끗한 복제본, 테스트, 서명, 내보내기까지 통과시키는 편이 관리 지점이 적습니다. 반대로 Linux 집합이 이미 크고 Apple 작업이 대기하는 팀은 일반 검사를 Linux에 두고 macOS 작업자만 확장하는 편이 합리적입니다.
여기서 원격 캐시와 원격 실행은 다른 기능입니다. 원격 캐시는 산출물을 저장하고 다시 사용하는 기능입니다. 원격 실행은 작업을 다른 실행 노드에서 수행하는 기능입니다. 원격 맥에 SSH로 접속하는 방식은 또 다른 운영 경로입니다. Bazel 원격 실행 규칙과 Bazel 원격 빌드 실행 안내를 기준으로 세 경로의 설정과 장애 기록을 분리해야 합니다.
작업 라우팅은 스크립트 이름이 아니라 action 정보로 확인합니다
ios_test라는 이름이 있다고 해서 모든 과정이 macOS에서 실행된다고 단정할 수 없습니다. 반대로 일반적인 생성 스크립트 안에서 Xcode 도구가 호출될 수도 있습니다. Bazel의 실행 기록과 action 정보를 확인해 실제 플랫폼, 입력 파일, 사용 도구를 찾아야 합니다.
예를 들어 저장소와 대상 이름은 실제 값으로 바꾸되, 처음에는 분석 결과를 파일로 남기는 방식이 안전합니다.
bazel aquery 'mnemonic(".*", //app:ios_app)' \
--output=textproto > /tmp/<action-record>.textproto
출력에서는 다음 항목을 확인합니다.
mnemonic: "SwiftCompile"
arguments: "... <xcode-tool-path> ..."
input_dep_set_ids: ...
execution_info: ...
platform: "darwin"
위와 같은 Apple 도구 경로 또는 macOS 플랫폼 제약이 보이면 해당 작업은 원격 맥 대상입니다. 실제 출력 형식은 규칙과 Bazel 설정에 따라 달라질 수 있으므로, 예시의 값 자체를 성공 조건으로 복사하지 말고 저장소에서 반복 확인해야 합니다.
Linux에 남길 후보는 소스 형식 검사, 일반 정적 분석, 플랫폼과 무관한 코드 생성, Apple SDK를 입력으로 요구하지 않는 단위 테스트입니다. 다만 테스트가 Simulator나 실제 Apple 프레임워크를 호출하면 후보에서 제외합니다. 실행 로그에 호스트 파일 경로, 전역 PATH, 로컬 스크립트가 나타나면 먼저 의존성을 선언하거나 macOS 작업으로 옮겨야 합니다.
재현성은 모듈과 숨은 의존성을 함께 측정합니다
Bazel 9 이전 설정을 그대로 옮기는 작업에서는 WORKSPACE만 확인해서는 부족합니다. 프로젝트가 MODULE.bazel을 어떻게 사용하는지, 전환하지 않은 외부 의존성 진입점이 남아 있는지 별도로 확인해야 합니다. Bazel 9의 변경 사항과 모듈 사용 방식은 Bazel 9 발표 자료를 기준으로 점검합니다.
검증표에는 다음 항목을 기록합니다.
MODULE.bazel의 모듈 버전과 무결성 정보rules_apple과rules_swift의 정확한 릴리스- Xcode 26과 macOS SDK의 정확한 버전
- 선택된 Swift 도구 모음과 Apple 플랫폼 제약
- 저장소 밖의
PATH, 호스트 파일, 전역 캐시 사용 여부 - 인증서, 키체인, 프로비저닝 프로파일의 주입 방식
그다음 로컬 캐시를 비운 상태에서 깨끗한 복제본을 만들고 동일한 입력으로 반복합니다.
git clone <repository-url> <clean-directory>
cd <clean-directory>
bazel clean --expunge
bazel test //... --profile=/tmp/<profile>.json
성공 여부만 기록하지 말고 분석 결과, 사용한 도구 경로, 캐시 적중 여부, 실패한 action과 재시도 결과를 보관해야 합니다. 깨끗한 복제본에서만 실패한다면 로컬 캐시나 개발자 계정에 숨어 있던 의존성이 있었을 가능성이 큽니다.
서명과 Simulator가 납품 경계를 결정합니다
서명 없는 빌드는 개발 중간 산출물일 수 있지만, 배포 가능한 iOS 결과를 증명하지는 않습니다. Simulator 테스트가 통과해도 보관 파일의 서명과 내보내기가 실패할 수 있습니다. Apple의 코드 서명과 프로비저닝 프로파일 기술 문서를 기준으로 인증서, 키체인, 프로파일의 관계를 확인해야 합니다.
검증 순서는 다음처럼 구성합니다.
- macOS 노드에 프로젝트가 요구하는 Xcode와 SDK를 고정합니다.
MODULE.bazel,rules_apple,rules_swift와 도구 모음 조합을 저장소에서 재현합니다.- 서명 없이 빌드해 Apple SDK와 링크 단계의 실행 플랫폼을 확인합니다.
- Simulator 테스트를 그래픽 로그인 없이 실행하고 결과 파일을 보관합니다.
- 별도 키체인과 프로비저닝 프로파일로 보관 파일을 생성합니다.
- 서명 정보와 내보낸 결과를 검사한 뒤 노드를 재부팅하고 같은 흐름을 반복합니다.
인증서와 키체인을 원격 캐시나 일반 빌드 캐시에 넣으면 안 됩니다. 작업 로그에도 비밀 값이 남지 않도록 마스킹해야 합니다. 그래픽 세션이 없으면 서명이 멈추거나, 재부팅 뒤 키체인이 잠긴다면 해당 노드는 운영 CI에 넣기 전에 복구 절차를 다시 설계해야 합니다.
캐시와 대기열 기록으로 확장 시점을 판단합니다
성능을 추측해 “원격 맥이 빠르다”고 결론 내리기보다 단계별 지표를 수집해야 합니다. 최소한 다음 항목을 같은 기간에 기록합니다.
- 전체 작업 중 Linux와 macOS에서 실행된 action 수
- 핵심 빌드 단계별 실행 시간과 실패 재시도
- 원격 캐시 적중과 누락
- macOS 작업자 대기열에 머문 시간
- 네트워크 전송과 저장소 입출력에서 발생한 지연
- 재부팅, 연결 끊김, 작업자 교체 뒤 복구 결과
캐시 적중이 낮은데 CPU 사용량도 낮다면 계산 노드보다 입력 경로, 선언되지 않은 환경 변수 또는 캐시 키가 병목일 수 있습니다. macOS 대기열만 길다면 Linux 검사를 옮기는 것보다 Apple 작업자 수와 작업 분할을 먼저 검토해야 합니다. 반대로 특정 링크나 Simulator 단계만 반복해서 실패하면 노드 수를 늘려도 문제가 해결되지 않습니다.
원격 캐시를 추가해도 Apple 전용 작업이 Linux에서 실행되는 것은 아닙니다. 캐시는 결과를 전달할 뿐이며, Apple SDK와 Xcode를 호출하는 action의 실행 위치는 플랫폼 제약과 도구 모음 설정으로 결정됩니다.
원격 맥 노드의 운영 판정 기준
노드 투입 전에는 작은 공개 프로젝트 또는 공개 가능한 최소 프로젝트로 다음 흐름을 통과시킵니다.
깨끗한 복제본
→ 모듈과 도구 모음 확인
→ Bazel 분석과 빌드
→ Simulator 테스트
→ 보관 파일 생성
→ 서명과 내보내기 검사
→ 재부팅 뒤 같은 작업 재실행
단일 원격 맥은 한 팀이 하나의 Xcode 조합을 사용하고, 우선 전체 납품 경로를 검증해야 할 때 적합합니다. Linux와 원격 맥 혼합 구조는 검사와 일반 테스트의 실행량이 크고, Apple 전용 작업을 별도 대기열로 관리할 수 있을 때 적합합니다. 두 구조 모두 캐시, 서명 비밀 값, 작업자 이미지와 복구 절차를 분리해야 합니다.
다음 조건이면 이전을 잠시 멈추는 편이 낫습니다.
- 규칙 릴리스와 Xcode 조합을 재현하지 못합니다.
- 깨끗한 복제본에서 같은 입력으로 결과가 달라집니다.
- 서명에 사람이 그래픽 로그인해야 합니다.
- 노드 교체 뒤 키체인과 프로파일을 자동 복구하지 못합니다.
- action이 어느 플랫폼에서 실행되는지 로그로 증명할 수 없습니다.
원격 맥 배치를 실제로 시작할 때는 NodeMini의 원격 맥 선택 페이지에서 필요한 접근 방식과 운영 조건을 확인하고, 먼저 한 노드로 위의 증거를 확보하는 방식이 안전합니다. Xcode 버전을 분리해야 하는 프로젝트라면 같은 노드에 도구를 계속 덮어쓰기보다 환경을 격리하는 별도 운영 계획을 세워야 합니다.
자주 확인하는 경계
Xcode가 없는 Linux에서도 Bazel iOS 빌드가 가능한가요?
일반 분석이나 Apple 도구를 호출하지 않는 일부 작업은 가능합니다. 그러나 Apple SDK를 이용한 컴파일과 링크, Simulator, 서명과 패키징까지 포함한 전체 결과는 macOS와 Xcode가 있는 노드에서 확인해야 합니다.
Linux 작업이 실제로 macOS에서 실행되는지 어떻게 확인하나요?
Bazel 실행 기록과 aquery 결과에서 플랫폼 제약, 도구 경로와 action 입력을 확인합니다. CI 단계 이름이나 셸 스크립트 이름만 보고 라우팅을 판단하면 안 됩니다.
원격 맥 접속과 Bazel 원격 실행은 같은 기능인가요?
아닙니다. 원격 맥 접속은 작업자가 호스트에 접근하는 방법입니다. 원격 실행은 Bazel action을 다른 노드에서 수행하는 방식이고, 원격 캐시는 산출물을 저장하고 재사용하는 기능입니다. 장애 원인과 보안 경계를 각각 기록해야 합니다.
서명 키를 원격 캐시에 저장해도 되나요?
안 됩니다. 인증서와 키체인은 캐시와 분리하고, 임시 키체인과 최소 권한 계정을 사용해야 합니다. 로그에 비밀 값이 남지 않는지와 재부팅 뒤 자동 복구가 되는지도 확인해야 합니다.
언제 Mac 노드를 더 추가해야 하나요?
macOS 대기 시간이 반복적으로 길어지고, 캐시 적중과 입력 전송은 정상이며, Apple action 자체가 병목이라는 기록이 있을 때 확장을 검토합니다. 기록 없이 노드부터 늘리면 저장소 입출력이나 잘못된 라우팅 문제를 가리지 못합니다.
현재 Linux 중심 CI는 일반 검사와 생성 작업을 처리하는 데 효율적일 수 있지만, Apple SDK가 없고 Simulator를 실행할 수 없으며 코드 서명과 보관 파일 생성 단계에서 별도 호스트가 필요합니다. 가상 macOS나 임시 작업자에 의존하면 Xcode 조합, 키체인 복구와 노드 교체를 통제하기도 어렵습니다. 이런 조건이라면 장비를 바로 구매하기보다 NodeMini의 원격 맥에서 실제 Bazel iOS 프로젝트를 실행하고 캐시, 테스트, 서명, 재부팅 복구 결과를 기록하는 편이 먼저입니다. 그 증거를 바탕으로 단일 노드를 유지할지 혼합 CI로 확장할지 결정하면 됩니다. 자세한 접속과 운영 조건은 NodeMini의 맥 원격 사용 안내에서 확인할 수 있습니다.