시작 지점

KVMFLUX에서 전용 클라우드 맥미니 M4를 대여하면 실제 Apple 하드웨어에 대한 루트에 준하는 관리 권한을 받습니다: 16GB 통합 메모리, 256GB SSD, macOS가 미리 설치되어 있으며 SSH와 VNC로 접속할 수 있습니다. 공유도 가상화도 없기 때문에 xcodebuild는 완전한 M4를 그대로 보고, Secure Enclave도 책상 위 머신과 똑같이 동작합니다.

팀과 가까운 리전보다는 산출물 저장소와 가까운 리전을 고르세요. 러너가 사람보다 훨씬 자주 Git 호스팅과 CDN과 통신하기 때문입니다 — 싱가포르, 일본, 대한민국, 홍콩, 미국 동부, 미국 서부를 지원합니다.

1단계 — 다른 무엇보다 먼저 SSH를 잠그세요

머신은 처음 접속을 편하게 하기 위해 비밀번호 로그인이 켜진 상태로 배송됩니다. 첫 세션에서 바로 끝내야 할 일입니다: 키를 먼저 올리고, 비밀번호는 그다음 끄세요.

로컬 터미널
ssh-keygen -t ed25519 -f ~/.ssh/kvmflux_ci -C "ci-runner"
ssh-copy-id -i ~/.ssh/kvmflux_ci.pub admin@<YOUR_MAC_HOST>
Mac에서
sudo tee -a /etc/ssh/sshd_config <<'EOF'
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
EOF
sudo launchctl kickstart -k system/com.openssh.sshd

CI 노드에는 두 가지 설정이 더 중요합니다: 머신이 잠들지 않게 하고, 모니터가 연결되지 않은 상태에서도 백그라운드 데몬이 멈추지 않게 하는 것입니다.

Mac에서
sudo pmset -a sleep 0 displaysleep 0 disksleep 0
sudo systemsetup -setrestartfreeze on

VNC는 최후의 수단으로 남겨두세요. 라이선스 동의창이나 시뮬레이터 최초 실행 권한처럼 일부 Xcode 팝업은 GUI에서만 나타나므로, SSH 설정이 잘못되었을 때도 들어갈 수 있는 경로가 필요합니다.

2단계 — Xcode 툴체인 설치

App Store는 건너뛰세요. xcodes는 지정한 Xcode 버전을 비대화형으로 설치할 수 있어 헤드리스 노드에 정확히 필요한 방식입니다. Homebrew를 먼저 설치한 뒤 툴체인을 설치하세요.

Mac에서
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install xcodesorg/made/xcodes aria2
xcodes install 16.2 --experimental-unxip
sudo xcodes select 16.2
sudo xcodebuild -license accept
sudo xcodebuild -runFirstLaunch

실제로 빌드할 대상 플랫폼을 확인하세요. 파이프라인이 시뮬레이터 테스트를 돌린다면 첫 작업이 오기 전에 지금 런타임을 미리 내려받으세요.

Mac에서
xcodebuild -downloadPlatform iOS
xcrun simctl list runtimes
xcodebuild -version

모바일 파이프라인에서 흔히 쓰는 도구도 함께 설치하세요: 레인과 서명을 위한 fastlane, 저장소에 바이너리 자산이 있다면 git-lfs.

Mac에서
brew install fastlane git-lfs jq
git lfs install --system

3단계 — 머신을 러너로 등록하기

GitHub Actions, GitLab, Buildkite의 방식은 모두 같습니다: 에이전트를 내려받고, 범위가 제한된 토큰을 발급받아 서비스로 실행합니다. 아래는 Apple Silicon용 GitHub Actions 버전입니다.

Mac에서
mkdir ~/actions-runner && cd ~/actions-runner
curl -o runner.tar.gz -L \
  https://github.com/actions/runner/releases/download/v2.321.0/actions-runner-osx-arm64-2.321.0.tar.gz
tar xzf runner.tar.gz
./config.sh --url https://github.com/your-org/your-app \
  --token <REGISTRATION_TOKEN> \
  --labels macos,arm64,m4 --unattended
./svc.sh install && ./svc.sh start

svc.sh로 설치하면 러너가 launchd에 등록되어 로그인 세션이 없어도 재부팅 후에도 계속 살아 있습니다. 대상을 지정할 때는 라벨을 사용하세요:

.github/workflows/ios.yml
jobs:
  build:
    runs-on: [self-hosted, macos, m4]
    steps:
      - uses: actions/checkout@v4
      - run: xcodebuild -scheme App -destination \
          'platform=iOS Simulator,name=iPhone 16' test

등록 토큰은 한 시간 뒤 만료되고 한 번만 사용할 수 있는데, 이는 의도된 동작입니다. 러너의 장기 인증 정보는 러너 디렉터리의 .credentials 파일에 저장되므로 이 계정은 계속 "심심하게" 유지하세요: 개인 SSH 키도, 브라우저 세션도 남기지 마세요.

4단계 — CI가 스스로 잠금을 풀 수 있는 키체인 만들기

서명은 대부분의 셀프 호스팅 Mac 구성에서 가장 자주 막히는 지점입니다. 해법은 레인이 만들고, 잠금을 풀고, 다 쓰면 버리는 전용 키체인입니다 — 이렇게 하면 로그인 키체인이 팝업을 띄우지도, 작업 사이에 정보가 새지도 않습니다.

서명 레인
KEYCHAIN=ci.keychain-db
security create-keychain -p "$KEYCHAIN_PASS" $KEYCHAIN
security set-keychain-settings -lut 3600 $KEYCHAIN
security unlock-keychain -p "$KEYCHAIN_PASS" $KEYCHAIN
security import dist.p12 -k $KEYCHAIN -P "$P12_PASS" \
  -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple: \
  -s -k "$KEYCHAIN_PASS" $KEYCHAIN
security list-keychains -d user -s $KEYCHAIN login.keychain-db

set-key-partition-list 이 줄은 누구나 빠뜨리기 쉬운 부분입니다 — 이게 없으면 codesign은 절대 나타나지 않을 GUI 비밀번호 팝업을 계속 기다립니다. fastlane을 쓴다면 프라이빗 인증서 저장소와 함께 쓰는 match가 이 과정을 전부 자동화해 줍니다.

캐시: 결과물을 디스크에 남겨두기

전용 머신이 임시 러너보다 나은 진짜 이유는 상태를 유지할 수 있다는 점입니다. 이를 활용해서 매 작업마다 전 세계를 다시 내려받지 마세요:

  • DerivedData-derivedDataPath ~/ci-cache/dd로 고정 경로를 지정하면 증분 빌드 시간이 보통 몇 분에서 몇 초로 줄어듭니다.
  • Swift 패키지-clonedSourcePackagesDirPath ~/ci-cache/spm을 설정해 작업 사이에 이미 있는 체크아웃을 재사용하도록 하세요.
  • CocoaPods와 Homebrew — 둘 다 기본적으로 러너 사용자의 홈 디렉터리에 캐시됩니다. 빌드 사이에 작업 공간을 지우지 않으면 됩니다.

디스크 사용량은 솔직하게 예상하세요. 256GB SSD에서 Xcode와 런타임이 약 40GB를 차지하고, 활발한 프로젝트의 캐시는 점점 60~80GB까지 늘어납니다. 문제가 생기고 나서가 아니라 계획적으로 정리하세요:

주간 예약 작업
find ~/ci-cache/dd -maxdepth 1 -mtime +14 -exec rm -rf {} +
xcrun simctl delete unavailable
df -h /

프로젝트에 대용량 자산이 있거나 여러 Xcode 버전을 같이 두어야 한다면, 추가 SSD +1TB 옵션은 $11.7/월밖에 하지 않아, 릴리스 당일 디스크가 가득 찬 문제를 뒤늦게 해결하는 것보다 훨씬 저렴합니다.

동시성: M4 한 대로 몇 개의 작업을 처리할 수 있을까요?

16GB 메모리의 M4는 무거운 작업 하나를 처리할 때 성능이 좋습니다: 완전한 클린 빌드와 시뮬레이터 테스트 스위트 한 번이면 모든 코어를 다 씁니다. 시뮬레이터 기반 작업 두 개를 동시에 돌리는 것은 소규모 앱에서는 괜찮지만, 메모리 압박이 커지면 둘 다 느려집니다.

몇 달간 파이프라인을 운영하며 정리한 경험 법칙입니다:

  • 빌드+테스트 작업 부하는 러너 프로세스 하나당 한 번에 한 작업을 처리하는 것이 가장 안전한 기본값입니다.
  • 린트, 유닛 테스트, UI 테스트는 두 번째 머신을 추가한 뒤에만 별도 작업으로 분리하세요 — 같은 머신에서 줄을 세우면 오버헤드만 늘어납니다.
  • 야간 작업은 공짜로 얻는 컴퓨팅입니다: 의존성 감사와 스크린샷 배치는 해당 리전의 업무 시간 외로 예약하세요.

대기 시간이 병목이 되면 대여 노드를 추가해 선형적으로 확장할 수 있습니다 — 같은 라벨로 등록만 하면 스케줄러가 자동으로 부하를 분산합니다. 일간과 월간 노드 중 어느 쪽이 나은지 계산은 다른 글에서 다뤘습니다: 대여 기간 비용 분석. 관련 워크플로는 활용 사례 개요에서도 볼 수 있습니다.

전체 구성, 요약본

  1. SSH는 키로만 로그인, 슬립은 끄고, VNC는 예비 통로로 유지.
  2. xcodes로 Xcode 설치, 라이선스 동의, 런타임 사전 다운로드.
  3. 의미 있는 라벨을 붙인 launchd 서비스로 러너 등록.
  4. 파티션 목록이 설정된 전용 CI 키체인.
  5. 지속적인 캐시와 예약 정리.

전체 설정에 걸리는 시간은 한 시간이 채 안 되지만, 그 결과로 팀이 더 이상 신경 쓸 필요가 없는 빌드 노드를 얻게 됩니다 — 이게 바로 핵심입니다.

실기기에서 직접 시험해 보세요

위의 모든 명령은 실제로 대여 중인 머신에서 작성하고 검증했습니다. 한 대를 대여해서 따라 해보고, 맞지 않으면 해지하세요 — 어느 쪽이든 하드웨어 청구서가 남지 않습니다.

Mac Mini M4 · 16GB / 256GB
일간$19.3 /일
주간$52.2 /주
월간$96.7 /월
분기$263 /분기

전용 하드웨어, 미국 달러 결제, 언제든 해지 가능.