연결부터 배포까지

첫 iOS 빌드 파이프라인 만들기

먼저 연결을 확인하고 툴체인을 고정한 다음 CI를 연결하세요. 실제 작업 순서에 따라 전용 물리 Mac을 반복 실행 가능한 빌드 노드로 설정합니다. 가상 머신이 아니며 macOS 그래픽 인터페이스와 명령줄을 모두 사용할 수 있습니다.

이미 호스트가 있다면 아래의 ‘시작 및 로그인’부터 진행하세요. 아직 사양을 정하지 않았다면 단일 작업으로 빌드를 검증한 뒤 필요한 동시 실행 규모를 결정하세요.

시작 및 로그인

주문과 호스트 인증 정보를 확인하고 첫 SSH 연결을 완료한 다음 로그인 공개 키를 추가하세요.

첫 연결 단계 보기

원격 연결

스크립트와 CI에는 SSH를 사용하고, Xcode·시뮬레이터·그래픽 인터페이스 디버깅에는 VNC 화면 공유를 사용하세요.

연결 설정 보기

CI 연결

self-hosted runner를 등록하고 툴체인 태그를 구분하세요. 먼저 호스트당 빌드 동시 실행 수를 1로 설정합니다.

러너 설정

결제 및 갱신

청구 주기, 추가 옵션, 만료일을 확인하세요. 주문·결제·갱신 상태는 콘솔에 표시되는 정보를 기준으로 확인합니다.

결제 안내 보기
먼저 연결 확인

시작 후 첫 1시간 동안 할 일 4가지

아래 순서는 권장 작업 절차이며, 서비스 개통이나 처리 시간에 대한 약속이 아닙니다. 먼저 콘솔에서 서비스가 개통되었는지 확인한 다음 해당 인스턴스에서 실제로 제공된 주소, 포트, 사용자 이름을 사용하세요. 예시를 보고 호스트 인증 정보를 추측하지 마세요.

  1. 인스턴스 확인

    콘솔에 로그인해 해당 서비스 상세 정보에서 머신 유형, 노드, 대여 기간을 확인하세요. 호스트 번호를 기록해 두면 이후 문제 해결, 갱신, 지원 요청을 연결하기 쉽습니다. 연결 주소와 초기 인증 정보는 권한이 있는 계정으로만 확인하세요.

  2. 첫 SSH 로그인

    콘솔에 표시된 정보를 로컬 연결 매개변수에 입력하세요. 처음 연결할 때 호스트 키 지문을 확인하세요. 신뢰할 수 있는 지문 출처가 없다면 검증을 건너뛰지 말고 먼저 지원 티켓으로 확인하세요. 연결에 성공하면 시스템과 사용자 정보를 점검합니다.

  3. 로그인 비밀번호 변경

    대화형 SSH 세션에서 실행하세요: passwd 안내에 따라 현재 사용자의 비밀번호를 변경하세요. 비밀번호를 명령 인수, 저장소, 채팅 기록 또는 빌드 로그에 넣지 마세요. 현재 세션을 유지한 채 다른 세션을 열어 새 인증 정보가 작동하는지 확인하세요.

  4. 로그인 공개 키 추가

    사용 중인 컴퓨터에서 전용 키를 생성하고 공개 키만 호스트에 추가하세요. 공개 키 로그인이 정상 작동하는 것을 확인한 뒤 비밀번호 로그인을 조정하세요. SSH 서비스 설정을 변경할 때는 호스트에서 잠기지 않도록 사용 가능한 세션을 유지하세요.

로컬 연결 매개변수 및 호스트 점검
ssh -p "$MAC_SSH_PORT" "$MAC_USER@$MAC_HOST"

whoami
sw_vers
uname -m
xcode-select -p
df -h
passwd

연결하기 전에 로컬 환경에서 MAC_SSH_PORT、MAC_USER、MAC_HOST를 설정하세요. 값은 콘솔에서 확인할 수 있습니다. 나머지 명령은 로그인한 호스트에서 실행합니다. xcode-select -p 는 현재 개발 도구 경로를 확인하는 명령입니다.

호스트에서 · 복사한 공개 키 추가
install -d -m 700 "$HOME/.ssh"
touch "$HOME/.ssh/authorized_keys"
chmod 600 "$HOME/.ssh/authorized_keys"
printf '%s\n' "$LOGIN_PUBLIC_KEY" >> "$HOME/.ssh/authorized_keys"

먼저 LOGIN_PUBLIC_KEY 에 전체 공개 키 문자열을 설정한 다음 추가 명령을 실행하세요. 개인 키를 업로드하거나 같은 공개 키를 중복 추가하지 마세요. 연결 시간 초과, 인증 실패, 호스트 키 변경은 각각 다른 문제입니다. 지원 티켓을 제출할 때 문제 유형을 구분해 설명하세요.

재현 가능한 환경 만들기

Xcode 버전을 고정하고 시뮬레이터 준비

최신 버전으로 바로 업그레이드하지 말고 프로젝트에 필요한 Xcode, SDK, runtime을 먼저 기록하세요. 설치 가능 범위는 OS와 Xcode의 호환성에 따라 달라집니다. 기존 프로젝트라면 로컬에서 빌드에 성공한 조합을 우선 유지하고 업그레이드는 별도로 검증하세요.

호스트에 xcodes가 아직 설치되어 있지 않다면 팀에서 승인한 소프트웨어 설치 절차에 따라 먼저 준비하세요. 특정 버전을 설치할 때는 합법적으로 확보했으며 프로젝트 요구 사항에 맞는 로컬 Xcode 설치 패키지를 사용하세요. 아래의 XCODE_VERSION 과 XCODE_XIP 는 각각 확인된 버전 번호와 설치 패키지의 절대 경로를 나타냅니다. 설치 중 필요한 대화형 단계를 무인 빌드 작업에 넣지 마세요.

호스트에서 · 개발 도구 설치 및 확인
xcodes installed
xcodes install "$XCODE_VERSION" --path "$XCODE_XIP"
xcodes installed

export DEVELOPER_DIR="$XCODE_APP/Contents/Developer"
xcodebuild -version
xcodebuild -showsdks
xcrun simctl list runtimes

XCODE_APP 은 설치된 실제 앱 경로를 가리켜야 합니다. CI에서는 여러 작업이 시스템 전역 설정을 두고 충돌하지 않도록 작업 환경에서 DEVELOPER_DIR를 설정하는 것이 좋습니다. 시스템 기본 툴체인을 꼭 전환해야 한다면 다음 명령을 실행하세요: sudo xcode-select --switch "$XCODE_APP/Contents/Developer" 그런 다음 xcodebuild -version으로 다시 확인하세요.

선택한 Xcode를 처음 실행해 필요한 구성 요소를 준비하세요. 원격 연결로 그래픽 인터페이스를 조작할 수 있습니다. 그런 다음 Xcode의 구성 요소 설정에서 필요한 runtime을 설치하세요. xcrun simctl list devices available을 실행해 테스트 대상에 맞는 시뮬레이터를 선택하세요. 대화형으로 한 번 실행해 완전히 시작될 때까지 기다린 후 최소 테스트 작업을 실행합니다. 실제 기기용 아카이브 생성과 시뮬레이터 테스트는 서로 다른 단계입니다. runtime이 없다는 이유로 아카이브 툴체인 문제라고 잘못 판단하지 마세요.

CI 로그 앞부분에 툴체인 점검을 추가하세요. 최소한 Xcode 버전, SDK 목록, 커밋 ID를 출력해야 합니다. Xcode를 변경한 뒤에는 캐시 키를 새로 만들고 서드파티 의존성, 서명, 내보내기 절차를 검증하세요. runner 태그만 바꾸고 실제 도구 경로를 확인하지 않으면 빌드 환경의 일관성을 보장할 수 없습니다.

먼저 단일 작업, 그다음 확장

호스트를 self-hosted runner로 등록

같은 물리 노드에서 실행되는 작업은 CPU, 메모리, 디스크, 사용자 환경을 공유합니다. 처음에는 호스트당 빌드 작업을 1개만 실행하세요. 아카이브, 서명, 정리가 모두 안정적으로 작동하는지 확인한 뒤 실제 최대 사용량을 기준으로 동시 실행을 늘리거나 별도 노드를 추가하세요.

GitLab Runner: 태그와 실행기 함께 확인

프로젝트의 runner 설정에서 프로젝트 runner를 만들고 해당 인증 토큰을 준비한 다음, 다음 세 태그를 설정하세요: macos、arm64、ios-archive 。인스턴스 주소와 인증 토큰은 임시로 GITLAB_URL、GITLAB_RUNNER_TOKEN에 넣고 전용 빌드 사용자 계정으로 shell executor를 등록하세요. 작업을 마치면 임시 토큰 변수를 삭제합니다.

GitLab Runner · 등록 및 동시 실행 설정
gitlab-runner register \
  --non-interactive \
  --url "$GITLAB_URL" \
  --token "$GITLAB_RUNNER_TOKEN" \
  --executor "shell" \
  --description "armrdp-ios-archive"

unset GITLAB_RUNNER_TOKEN
gitlab-runner verify

runner가 실제 사용하는 config.toml 에서 전역 concurrent = 1로 설정하고 해당 runner의 limit = 1도 설정하세요. 설치된 버전에 맞는 서비스 관리 방법으로 runner를 시작합니다. 대화형 검증에 성공했다고 해서 백그라운드 서비스도 실행 중인 것은 아닙니다.

프로젝트에서 · .gitlab-ci.yml 아카이브 작업
ios_archive:
  tags:
    - macos
    - arm64
    - ios-archive
  script:
    - xcodebuild -version
    - xcodebuild archive -workspace "$IOS_WORKSPACE" -scheme "$IOS_SCHEME" -destination 'generic/platform=iOS' -archivePath "$CI_PROJECT_DIR/output/App.xcarchive"
  artifacts:
    paths:
      - output/App.xcarchive
    expire_in: 7 days

프로젝트 변수에 실제 IOS_WORKSPACE 와 IOS_SCHEME를 설정하고 다음 섹션의 서명 준비를 먼저 완료하세요. 여기서는 아카이브만 생성하며 내보내기나 업로드는 포함하지 않습니다. 산출물을 7일간 보관하는 설정은 예시이므로 팀의 보관 정책에 맞게 변경할 수 있습니다. 인증서, 개인 키 또는 임시 Keychain을 artifacts에 넣지 마세요.

GitHub Actions: runner 프로세스 하나당 작업 하나

저장소 설정에 안내된 runner 설치 단계에서 macOS ARM64용 프로그램을 받아 압축을 푼 디렉터리로 이동하세요. REPOSITORY_URL 에는 현재 저장소 주소를, RUNNER_TOKEN 에는 이번 등록에 사용할 토큰을 설정하세요. 작업이 잘못된 툴체인으로 라우팅되지 않도록 등록 설정과 워크플로 모두에 태그를 넣어야 합니다.

GitHub Actions · 호스트 등록
./config.sh \
  --url "$REPOSITORY_URL" \
  --token "$RUNNER_TOKEN" \
  --name "armrdp-ios-archive" \
  --labels "macos,arm64,ios-archive" \
  --work "_work"

unset RUNNER_TOKEN
./run.sh
프로젝트에서 · GitHub Actions 워크플로
name: iOS archive
on:
  workflow_dispatch:

permissions:
  contents: read

concurrency:
  group: ios-archive
  cancel-in-progress: false

jobs:
  archive:
    runs-on: [self-hosted, macos, arm64, ios-archive]
    env:
      DEVELOPER_DIR: ${{ vars.DEVELOPER_DIR }}
      IOS_WORKSPACE: ${{ vars.IOS_WORKSPACE }}
      IOS_SCHEME: ${{ vars.IOS_SCHEME }}
    steps:
      - uses: actions/checkout@v4
      - name: Archive
        run: |
          xcodebuild -version
          xcodebuild archive \
            -workspace "$IOS_WORKSPACE" \
            -scheme "$IOS_SCHEME" \
            -destination 'generic/platform=iOS' \
            -archivePath "$RUNNER_TEMP/App.xcarchive"

저장소 변수에 도구 경로, workspace, scheme을 먼저 설정하세요. 이 예시는 환경을 먼저 검증하기 쉽도록 수동 실행을 사용합니다. 서명 인증 정보가 있는 runner를 신뢰할 수 없는 외부 코드에 바로 노출하지 마세요. runner 프로세스 하나는 한 번에 한 작업만 처리하며, concurrency 는 같은 그룹의 워크플로 실행도 제한합니다. 이는 호스트 수준의 리소스 한도가 아닙니다.

검증이 끝나면 다운로드한 프로그램에서 제공하는 서비스 스크립트로 상시 실행을 설정하고, 서비스 사용자와 수동 테스트 사용자가 같은지 확인하세요. 한 사용자 계정에서 서명을 준비하고 다른 사용자 계정으로 서비스를 실행하면 대화형 빌드는 성공하지만 CI에서 인증서나 프로비저닝 프로파일을 찾지 못하는 문제가 흔히 발생합니다.

자격 증명과 코드 분리

빌드 사용자 계정에서 서명 환경 준비

배포 인증서, 해당 개인 키, 프로비저닝 프로파일은 프로젝트에서 사용하는 팀 및 Bundle Identifier와 일치해야 합니다. 무인 자동화에 연결하기 전에 제어된 작업에서 서명을 검증하세요. 내보내기 실패를 숨기려고 서명 검사를 끄지 마세요.

자동화 작업에는 별도의 빌드 Keychain을 사용하고, CI의 보호된 비밀 변수로 비밀번호를 전달하세요. 인증서를 가져온 뒤 꼭 필요한 서명 도구에만 접근 권한을 부여하고 모든 앱이 개인 키에 접근하도록 허용하지 마세요. 아래 점검 명령은 현재 사용자가 유효한 서명 ID를 확인할 수 있는지 확인합니다. 프로비저닝 프로파일, 내보내기 설정, 프로젝트 설정이 모두 일치함을 보장하지는 않습니다.

호스트에서 · 서명 ID 및 프로비저닝 프로파일 디렉터리 확인
security list-keychains -d user
security find-identity -v -p codesigning
printf '%s\n' "$HOME/Library/MobileDevice/Provisioning Profiles"
printf '%s\n' "$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles"

Xcode 버전에 따라 프로비저닝 프로파일 경로가 다를 수 있으므로 현재 툴체인이 실제로 읽는 경로를 확인하세요. 가져온 후 유효 기간, 앱 식별자, 서명 유형을 점검합니다. 아카이브는 성공했지만 내보내기에 실패한다면 Xcode를 반복 설치하는 대신 내보내기 설정의 방식, 팀 식별자, 프로비저닝 프로파일 매핑을 중점적으로 확인하세요.

팀에서 이미 fastlane match를 사용 중이라면 기존 암호화 인증서 저장소와 접근 정책을 그대로 따르세요. 검증 단계에서는 bundle exec fastlane match appstore --readonly를 사용해 기존 서명 자료를 먼저 읽고 빌드 노드가 팀 인증서를 실수로 수정하지 않도록 하세요. 저장소 접근 자격 증명, 복호화 비밀번호, Keychain 비밀번호는 각각 별도로 관리하세요. 프로덕션 서명 변수는 보호된 브랜치 또는 제어된 수동 작업에만 공개합니다.

작업이 끝나면 임시 파일을 삭제하고 임시 Keychain을 잠그세요. 로그에는 필요한 오류 코드와 단계 결과만 남기고 개인 키 내용, 인증서 비밀번호, 등록 토큰, 비밀 변수 전체 값을 출력하지 마세요. 전용 물리 머신으로 리소스를 분리하더라도 프로젝트 자격 증명에는 최소 권한 원칙을 적용해야 합니다.

캐시는 다시 만들 수 있는 데이터로 취급

확장 볼륨 확인 후 DerivedData 이전

+1TB SSD 또는 +2TB SSD를 추가로 구매할 수 있습니다. 데이터 이전을 계획하기 전에 주문과 호스트에서 확장이 완료되었는지 확인하세요. 볼륨 이름, 마운트 경로, 파일 시스템은 실제 제공 정보를 기준으로 하며 다른 호스트의 디스크 식별자를 그대로 사용하지 마세요.

실행하세요: diskutil list 및 df -h로 용량과 마운트 지점을 확인하세요. 알 수 없는 디스크에 지우기나 파티션 명령을 실행하지 마세요. 빌드 사용자에게 쓰기 권한이 있는 캐시 디렉터리를 만들고 작은 파일로 읽기·쓰기를 테스트하세요. 재시작 후에도 마운트가 정상 작동하는지 확인한 뒤 상시 실행 runner에서 새 경로를 사용하세요.

이전하기 전에 새 작업을 받지 않도록 하고 진행 중인 아카이브와 서명 작업이 끝날 때까지 기다리세요. DerivedData는 다시 만들 수 있는 캐시이므로 쓰기 중일 수 있는 기존 캐시를 복사하기보다 새 위치에서 다시 생성하는 것이 좋습니다. 아래에서는 명시적으로 -derivedDataPath를 지정하므로 사용자 디렉터리 전체를 확장 볼륨으로 옮길 필요가 없습니다.

호스트에서 · 마운트 확인 및 빌드 캐시 경로 지정
diskutil list
df -h

test -d "$BUILD_VOLUME" && test -w "$BUILD_VOLUME"
mkdir -p "$BUILD_VOLUME/DerivedData/$CACHE_KEY"

xcodebuild archive \
  -workspace "$IOS_WORKSPACE" \
  -scheme "$IOS_SCHEME" \
  -destination 'generic/platform=iOS' \
  -derivedDataPath "$BUILD_VOLUME/DerivedData/$CACHE_KEY" \
  -archivePath "$BUILD_VOLUME/Archives/$BUILD_ID/App.xcarchive"

실행 전에 BUILD_VOLUME 을 쓰기 가능한 것으로 확인된 마운트 디렉터리로 설정하세요. CACHE_KEY 는 저장소, Xcode 버전, 빌드 구성을 구분해야 합니다. BUILD_ID 에는 현재 작업의 고유 ID를 사용해 작업 간 아카이브가 덮어쓰이지 않게 하세요. 동시에 실행되는 작업은 같은 쓰기 가능한 DerivedData 디렉터리를 공유하지 마세요.

먼저 캐시 없이 빌드를 한 번 완료한 뒤 후속 작업의 캐시 적중 여부와 디스크 증가량을 관찰하세요. 아카이브, 시뮬레이터 데이터, 의존성 캐시에 각각 보관 정책을 설정하고 삭제 전에 사용 중인 작업이 없는지 확인하세요. 빌드 산출물은 팀이 관리하는 별도 저장소에 보관해야 하며 호스트 캐시를 유일한 백업으로 삼지 마세요. 대여 기간이 끝나기 전에 내보내고 백업을 읽을 수 있는지 검증하세요.

문제를 재현 가능하게 설명

오류만 붙이는 것보다 지원 티켓에 단계를 적는 것이 효과적입니다

호스트, 주문 또는 결제 관련 문제는 콘솔에 로그인해 지원 티켓을 제출하세요. 실제 서비스와 연결해 확인할 수 있습니다. 로그인할 수 없다면 support@armrdp.com으로 이메일을 보내세요. 이 두 가지가 공식 문의 채널입니다.

문제 유형에 맞는 정보를 추가하되 비밀번호, 개인 키, 전체 결제 자격 증명은 제출하지 마세요.
항목권장 정보용도
호스트 또는 주문 번호콘솔에 표시된 해당 번호와 현재 노드서비스를 정확히 식별해 다른 인스턴스와 혼동하지 않도록 합니다
발생 시간시작 및 종료 시각, 시간대, 현재도 지속 중인지 여부서비스 기록과 작업 로그를 대조합니다
문제 유형연결 시간 초과, 인증 실패, 빌드 실패, 서명 실패 또는 결제 상태네트워크, 툴체인, 결제 문제를 구분합니다
재현 단계실행 순서, 최소 명령, 예상 결과, 실제 결과추가 확인에 필요한 배경 정보를 줄입니다
환경 및 로그Xcode 버전, runner 서비스 사용자, 오류 전후의 민감 정보가 제거된 로그버전 또는 권한 관련 문제인지 확인합니다
업무 영향작업 하나에만 영향을 주는지 호스트 전체에 영향을 주는지, 사용할 수 있는 대체 빌드 경로가 있는지영향 범위와 현재 대응 상황을 설명합니다

답변 시간과 해결 시간은 구분하세요

지원 티켓 처리 진행 상황과 답변 시간은 콘솔에 기록된 실제 정보를 기준으로 확인하세요. 첫 답변이 문제 해결을 뜻하지는 않습니다. 연결 문제는 호스트 상태와 접속 경로를 확인해야 할 수 있고, 빌드 문제는 작업 로그와 재현 단계가 필요한 경우가 많으며, 결제 문제는 주문과 거래 기록을 연결해야 합니다. 각 상황에 동일한 고정 해결 시간을 적용할 수 없습니다.

답변을 기다리는 동안 새 증거는 같은 티켓에 추가하고 대기 시간과 영향이 확대되었는지 적으세요. 현장 상태를 바꿀 수 있는 재설치, 디스크 초기화, 일괄 정리 작업을 반복하지 마세요. 오류가 CI에서만 나타난다면 같은 사용자 계정에서 대화형 실행과 서비스 실행 결과가 어떻게 다른지 기록하세요. 서명 문제라면 민감 정보를 제거한 오류만 제공하세요.

결제, 갱신 및 만료 전 확인

서비스는 일·주·월·분기 단위로 선불 결제합니다. 주문을 확인할 때는 머신 유형, 노드, 이용 기간, 추가 옵션을 함께 확인하세요. 갱신, 자동 갱신 설정, 결제 결과는 콘솔의 현재 설정과 실제 응답을 기준으로 합니다. 결제를 제출했다고 주문이 개통된 것은 아니므로 결제 페이지의 스크린샷만으로 서비스 상태를 판단하지 마세요.

결제 수단은 USDT-TRC20 및 Visa / Mastercard / Amex(Stripe)만 지원하며 모든 결제는 USD로 처리됩니다. 실제 사용 가능한 결제 게이트웨이는 백엔드 응답을 기준으로 확인하세요. 온체인 결제 시 네트워크, 수취 정보, 금액을 확인하세요. 확인이 필요하면 주문 번호와 거래 ID를 제공하고 지갑 개인 키나 전체 카드 정보를 제출하지 마세요.

만료 전에 새 빌드를 중단하고 코드 변경 사항, 아카이브 산출물, 필요한 설정을 내보낸 뒤 자체 저장 공간에서 복구할 수 있는지 확인하세요. 계속 사용할 예정이라면 갱신 후 새 만료일을 다시 확인하세요. 대여를 종료할 예정이라면 만료 후 호스트를 장기 보관 장소로 사용하지 마세요.

먼저 하나의 scheme에서 안정적으로 빌드

호스트 1대, 작업 1개로 시작해 툴체인, 서명, 산출물을 검증한 다음 runner를 늘리세요. 전용 물리 Mac은 일 단위로 대여할 수 있으며 시작 가격은 $21.1/일입니다. 실제 이용 가능 여부는 콘솔의 실시간 정보를 확인하세요.