플랫폼·iOS 리드가 막히는 지점은 SSH가 아니라 전용 원격 Mac에서 같은 커밋이 주나 세션에 걸쳐 드리프트할 때입니다. 이 글은 재현 가능 빌드를 Xcode 핑거프린트, 병렬 Xcode 버전, DerivedData 정책, 키체인 격리로 나누고 비교 표, 셸 스니펫, 사전 점검 목록을 제공합니다. 러너, SSH/VNC, Xcode Cloud 비교 글과 함께 읽으세요.
「컴파일됐다」는 한 시점의 관찰입니다. 재현성은 툴체인 상태, 의존성 해결, 서명 자료의 보이는 방식을 감사 가능한 기준선으로 고정합니다. 원격 노드에는 공급자 이미지 업데이트, 다중 사용자 잔여물, 무인 작업과 대화형 디버깅 혼재 같은 변수가 추가됩니다.
리뷰를 정직하게 유지하는 여섯 가지 통증 지점:
핑거프린트가 채팅에만 존재: xcodebuild -version과 swift --version이 빌드 로그에 남지 않아 어떤 툴체인이 돌았는지 증명할 수 없음.
xcode-select 드리프트: OS 업데이트나 수동 전환이 야간 작업을 다른 Xcode로 향하게 해 컴파일러·서명 경계 동작을 바꿈.
DerivedData 크로스토크: 브랜치가 캐시 접두사를 공유하고 증분 빌드가 맥로 상태를 맥락을 넘겨 운반.
키체인 뷰 불일치: 한 호스트의 대화형 사용자와 CI 사용자가 다른 서명 경로를 봄. SSH는 되는데 러너는 안 됨.
권한 노이즈: TCC 프롬프트가 명확한 프라이버시 오류 대신 타임아웃으로 헤드리스 작업을 멈춤.
과도한 정리: 스크립트가 「캐시 같아 보이는」 폴더를 지워 비교 불가능한 콜드 빌드를 강제.
이 둘 이상이 이 주 안에 반복되면 파이프라인 1단계에서 핑거프린트를 캡처하고 DerivedData·키체인 정책을 런북에 문서화하세요. 이는 노드 거버넌스이지 CI 벤더 잡담이 아닙니다.
머신을 계약된 CI 노드로 취급하고 런타임 정체성(CI 사용자, 홈 레이아웃, 도구 루트, 로그 경로)을 고정하세요. 디스크 등급은 일찍 계획하세요. 여러 Xcode와 시뮬레이터는 CPU 논쟁보다 빨리 커집니다.
| 차원 | 공유 대화형 개발 머신 | 전용 원격 Mac(CI 우선) |
|---|---|---|
| 런타임 정체성 | 개인 세션·GUI 상태와 섞이기 쉬움 | 전용 CI 사용자 권장. SSH/러너와 수동 디버깅 분리 |
| 툴체인 고정 | 업그레이드가 개인 습관을 따름 | 조직 승인 Xcode 마이너 고정. 변경은 변경 통제로 |
| DerivedData | 기본 경로에 여러 제품이 섞임 | 리포 또는 파이프라인별 루트 분할. 정리는 감사 가능하게 |
| 서명 자료 | 인증서가 로그인 키체인에 흩어짐 | 별 키체인·사용자 또는 노드로 분리. 릴리스와 실험 분리 |
| 관측 가능성 | 기억에 의존하기 쉬움 | 모든 빌드 로그 상단에 핑거프린트 명령 출력 |
재현성은 「업그레이드 금지」가 아니라 「모든 업그레이드에 전·후 핑거프린트와 롤백 경로를 실어 보낸다」는 뜻입니다.
DerivedData는 속도를 내다가 드리프트를 숨깁니다. 공유는 단일 메인라인과 오래가는 핫 캐시에 맞고, 격리는 실험 브랜치, ABI 민감 모듈, 릴리스 주 클린 빌드에 맞습니다. 삭제 논쟁 대신 정책을 쓰세요.
중요 파이프라인마다 루트 선택: 예 ~/DerivedData/$REPO/$BRANCH_SAFE. 암묵적 기본값에 의지하지 않기.
명시적으로 전달: -derivedDataPath 또는 CI 환경 변수 주입. 「기본값이 뭐였지」를 남기지 않기.
릴리스 전 핫 대 클린 비교: 같은 커밋은 기대 밴드 안에서만 달라야 함.
정리 단계화: 「지워도 안전」과 「거대 재다운로드를 강제」를 소유자·주기로 나눔.
디스크 임계값: 여유 공간이 빨간 선에 닿기 전에 보수적 보존이나 객체 스토리지 캐시로 전환.
러너 라벨과 정렬: 라벨마다 캐시 루트를 달리해 릴리스와 실험 작업이 충돌하지 않게. 러너 가이드 참고.
# 로그 헤더: 툴체인 핑거프린트(예)
xcodebuild -version
xcode-select -p
swift --version
/usr/bin/xcrun --show-sdk-path --sdk iphoneos
# 명시적 DerivedData(조직 repo/branch 규칙으로 치환)
DERIVED="$HOME/DerivedData/${REPO_SLUG}/${BRANCH_SAFE}"
mkdir -p "$DERIVED"
xcodebuild -scheme "App" -destination 'platform=iOS Simulator,name=iPhone 16' \
-derivedDataPath "$DERIVED" build
팁: SwiftPM과 Xcode를 함께 쓰면 swift package resolve 출력이나 잠금 파일 해시도 기록해 「같은 그래프」가 리졸버 캐시 드리프트를 가리지 않게 하세요.
많은 헤드리스 서명 실패는 「나쁜 인증서」가 아니라 다른 키체인 뷰나 무인 경로에서 한 번도 실행되지 않은 잠금 해제 정책 때문입니다. 최소 구성은 노출 축소, 대화형 디버깅을 중요 경로에서 제거, 릴리스 분리입니다.
GUI 디버깅과 러너가 같은 하드웨어를 써야 하면 라벨이나 시간대로 격리하고 일회성 VNC 승인을 문서화하세요. SSH/VNC 체크리스트에서 VNC 표면을 줄이는 것과 같은 생각입니다.
경고: 공유 원격의 전역 읽기 가능 위치에 배포용 개인키를 두지 마세요. 별 계정·노드·키체인 파일을 선호하고 인력 변동 시 로테이션하세요.
아래 범위는 공개 문서와 현장 관행에서 온 것입니다. 이해관계자 정렬에 쓰고, 청구와 실제 발자국은 계약으로 검증하세요.
xcodebuild -version을 붙이는 비용은 컴파일 시간 대비 보통 수 초이지만 분석 회수는 큽니다.노트북이나 「빌려 쓴」 Mac은 단기 비용은 줄이나 수면 정책, 업데이트 알림, 혼합 세션으로 핑거프린트·키체인 통제가 깨집니다. Linux VPS 위 중첩 macOS는 Metal과 서명 안정성을 희생하기 쉽습니다. iOS CI/CD와 자동화 에이전트에서 24/7 예측 가능한 환경, 감사 가능한 격리, 계약 가능한 디스크가 필요하면 전용 원격 Mac이 실제 운영 현실에 더 가깝습니다. NodeMini 클라우드 Mac mini 렌탈은 그 발자국에 맞습니다. 리전과 디스크를 고르고 자동화를 위해 SSH를 강화하며, 핑거프린트와 캐시 정책을 이전 가능한 운영 자산으로 취급하세요.