接続から初回ビルド成果物まで

導入後
最初の1時間

最初の30分で接続、ツールチェーンの確認、初回コンパイルを済ませ、後半の30分で署名とパイプラインを整えましょう。提供されるのは仮想マシンではなく専有物理Macです。既存のmacOS GUIやコマンドラインのワークフローをそのまま利用できます。

注文済みの場合は、まずコンソールで実際のホスト名、ポート、ユーザー名、提供情報を確認してください。サンプルの変数を接続情報として使わないでください。

00~10分

ホストのフィンガープリントを確認し、SSH接続します。

10~20分

Xcode、プロジェクトの依存関係、ディスク容量を確認します。

20~30分

まず署名なしのチェックを行い、その後アーカイブを検証します。

ステップ1 · 接続を確認

コマンドはSSH、GUIは画面共有で操作

まずローカルで鍵を生成し、公開鍵だけをアップロードします。秘密鍵は自分のデバイスに保管し、パスフレーズを設定してください。以下のコマンドでは、ホスト、ポート、ユーザー名にコンソールで提供された実際の情報を指定します。

ローカルのmacOSターミナルで実行
read -r -p "主机地址: " MAC_HOST
read -r -p "SSH 端口: " MAC_PORT
read -r -p "用户名: " MAC_USER
ssh-keygen -t ed25519 -f "$HOME/.ssh/osxhost_build"
cat "$HOME/.ssh/osxhost_build.pub"
ssh -p "$MAC_PORT" "$MAC_USER@$MAC_HOST"

公開鍵ファイルの拡張子は .pub です。最初は提供されたログイン方法で接続し、公開鍵をリモートの ~/.ssh/authorized_keysに追加します。その後、別のローカルターミナルから鍵認証でログインできることを確認します。

公開鍵をリモートに追加してパスワードを変更

リモートで ~/.sshを作成し、ディレクトリの権限を 700、公開鍵ファイルの権限を 600に設定します。エディターで公開鍵を追加し、既存の認証設定は残してください。その後、 passwd を実行して、現在のユーザーのパスワードを変更します。

別のターミナルを開き、 ssh -i ~/.ssh/osxhost_build -p "$MAC_PORT" "$MAC_USER@$MAC_HOST" でログインできることを確認してから、元のセッションを終了します。使える接続が1つしかない場合は、先に切断しないでください。

確認項目:新しいセッションで鍵認証ログインできる

暗号化トンネル経由で画面共有

ローカルで以下のトンネルコマンドを実行し、ターミナルを開いたままにします。macOSでは「画面共有」を開いて、 vnc://127.0.0.1:5901に接続します。WindowsとLinuxでは、対応するVNC認証方式を使えるクライアントからローカルポート 5901に接続してください。

リモート側で画面共有が有効になっており、現在のユーザーにアクセスが許可されている必要があります。GUIのログイン情報とSSH秘密鍵は別々の認証情報です。VNCポートをすべての接続元に公開しないでください。

確認項目:macOSデスクトップを表示して操作できる
ローカルSSHトンネル · 接続先はリモートのループバックアドレス
ssh -N -L 5901:127.0.0.1:5900 \
  -i "$HOME/.ssh/osxhost_build" \
  -p "$MAC_PORT" "$MAC_USER@$MAC_HOST"

ステップ2 · ローカルMacからクラウドMacへ

既存環境を丸ごと複製せず、3つの手順で移行

データとツールチェーンを確認してから、CIランナーを登録します。「ログインできること」と「無人でビルドできること」を分けて確認し、ローカルの対話型設定をCIの設定と取り違えないようにしてください。

手順01 · データ

プロジェクトを移行し、平文の秘密情報は移さない

  • キーチェーンから必要な署名証明書と秘密鍵を暗号化 .p12形式で書き出し、パスワードは別の安全な経路で共有します。
  • 現在のプロジェクトに必要なプロビジョニングプロファイルだけを移行し、チーム、アプリ識別子、有効期限を確認します。
  • ログインキーチェーン全体をコピーしないでください。ビルド専用のキーチェーンを作成し、必要なものだけをインポートして署名ツールにアクセスを許可します。
  • ソースコードと必要なリソースを同期し、依存関係のディレクトリ、DerivedData、古いビルド成果物は除外します。

確認項目:プロジェクトのバージョンが一致し、証明書に秘密鍵が含まれ、機密ファイルがGitに含まれていない。

手順02 · ツールチェーン

バージョンを固定してから依存関係をインストール

  • 「 xcodes list 」でバージョンを確認し、必要な利用許諾に同意してから対象のXcodeをインストールします。
  • 「 xcode-select 」で使用するツールチェーンを明示的に選び、GUIで最後に選択した項目には依存しないでください。
  • Homebrewとarm64のツールチェーンを確認し、Intel環境の依存関係ディレクトリをそのまま移さないでください。
  • Rubyのバージョン管理ツールとGemfileで、Ruby、CocoaPods、fastlaneのバージョンを固定します。

確認項目:ターミナルとCIでXcode、Ruby、Bundlerのバージョンが一致している。

手順03 · CI接続

信頼できるジョブだけを実行するランナーに

  • GitHub Actions:リポジトリの設定からself-hosted runnerを登録し、macOS ARM64のパッケージを選択します。
  • GitLab Runner:プロジェクト単位でランナーを登録し、必要に応じてshell実行方式を選んで、対象プロジェクトを制限します。
  • Jenkins:macOSエージェントを作成し、分離した作業ディレクトリと制御された認証情報の注入を設定します。
  • まず同時実行数を1にして署名ビルドを確認し、ピーク時のメモリ使用量に応じて並列数を増やします。

確認項目:信頼できるコミットをpushしてビルドを実行し、ログとビルド成果物を回収できる。

ローカルからプロジェクトを同期 · リモートの既存ファイルは保持
rsync -avz \
  --exclude='.git/' \
  --exclude='build/' \
  --exclude='DerivedData/' \
  --exclude='Pods/' \
  --exclude='node_modules/' \
  -e "ssh -p $MAC_PORT -i $HOME/.ssh/osxhost_build" \
  ./ "$MAC_USER@$MAC_HOST:~/build-workspace/"

この同期コマンドはリモートのファイルを削除しません。本番パイプラインでは、バージョン管理から固定したコミットをチェックアウトしてください。キャッシュキーには少なくとも、ツールチェーンのバージョン、依存関係のロックファイル、対象アーキテクチャを含めます。信頼できない外部コントリビューターのマージリクエストから署名情報にアクセスできないようにしてください。

ステップ3 · 署名と成果物を個別に確認

Fastfileでmatch、gym、pilotを連携

まずプロジェクトのルートディレクトリで bundle installを実行し、Gemfile.lockをコミットします。以下の手順は、署名リポジトリとアプリがすでに用意され、CIに環境変数が安全に注入されていることを前提としています。新しい署名アセットの作成は行いません。

リモートの事前確認 · まずツールチェーンを確認
xcode-select -p
xcodebuild -version
xcodebuild -showsdks
ruby --version
bundle --version
bundle exec fastlane --version
security find-identity -v -p codesigning
df -h "$HOME"

署名リポジトリのURLを MATCH_GIT_URLに、復号用パスワードを MATCH_PASSWORDに設定します。アップロード認証にはサーバー側のAPIキーを使用します。キーのファイルパスは ASC_KEY_PATH で指定し、キーIDと発行者IDはそれぞれ ASC_KEY_ID、ASC_ISSUER_ID で指定します。キーのファイルはCIのシークレットストレージから実行時に書き出し、プロジェクトのリポジトリにはコミットしないでください。

以下を設定します: IOS_APP_IDENTIFIER、IOS_TEAM_ID、IOS_WORKSPACE 、 IOS_SCHEME。署名リポジトリの配布タイプは appstore と一致させます。共有schemeを確認してから、パイプライン全体を実行してください。

fastlane/Fastfile · 単一アプリのTestFlightパイプライン
default_platform(:ios)

platform :ios do
  desc "Archive a signed build and upload it to TestFlight"
  lane :release do
    setup_ci

    api_key = app_store_connect_api_key(
      key_id: ENV.fetch("ASC_KEY_ID"),
      issuer_id: ENV.fetch("ASC_ISSUER_ID"),
      key_filepath: ENV.fetch("ASC_KEY_PATH"),
      in_house: false
    )

    match(
      type: "appstore",
      readonly: true,
      git_url: ENV.fetch("MATCH_GIT_URL"),
      app_identifier: ENV.fetch("IOS_APP_IDENTIFIER"),
      team_id: ENV.fetch("IOS_TEAM_ID"),
      api_key: api_key
    )

    gym(
      workspace: ENV.fetch("IOS_WORKSPACE"),
      scheme: ENV.fetch("IOS_SCHEME"),
      configuration: "Release",
      clean: true,
      export_method: "app-store",
      output_directory: "build/artifacts",
      output_name: "release.ipa"
    )

    pilot(
      api_key: api_key,
      ipa: "build/artifacts/release.ipa",
      skip_waiting_for_build_processing: true
    )
  end
end
実行と確認 · 環境変数はCIから注入
bundle exec fastlane ios release
find build/artifacts -maxdepth 1 -type f -print

アップロードの成功は処理完了を意味しません。この例ではアップロード後の処理完了を待機しません。配信管理画面でビルドの処理結果を確認し、アップロードごとに一意のビルド番号を設定してください。readonly: true を指定するとCIによる署名リポジトリの変更を防げます。証明書またはプロビジョニングプロファイルの期限が切れた場合は、管理された環境で更新してから再実行してください。

クロスプラットフォーム開発 · ロックファイルを保持

iOSの処理を分離し、キャッシュを適切に無効化

FlutterとReact NativeのiOSビルドはいずれもXcode、CocoaPods、署名環境が必要です。まず各プラットフォームの診断を行ってから、アップロード処理を追加してください。キャッシュが使われても、依存関係の整合性確認は省略しないでください。

Flutter:まずシミュレーターで動作確認し、次にIPAを出力

Flutter SDKのバージョンを固定し、 pubspec.lockを保持します。Pubのダウンロードキャッシュを再利用し、PodsはPodfile.lock、DerivedDataはXcodeのバージョンとプロジェクト設定をキーにします。初回はキャッシュが空のため、以降の実行よりダウンロードとコンパイルに時間がかかります。

プロジェクトのルートディレクトリで以下を実行します。署名設定が完了すると、flutter build ipa --release で実機向けビルドを作成して書き出せます。

Xcodeのメジャーバージョンをまたいでビルドキャッシュを再利用しない

React Native:Node、Ruby、Podsのバージョンを固定

JavaScriptパッケージマネージャーのロックファイルをコミットし、プロジェクトで定めたインストールコマンドを使います。以下はnpmの例です。Rubyの依存関係はBundlerで管理し、システム全体のgemとプロジェクトのバージョンが互いに上書きしないようにします。

新しい依存関係のためにインデックスを更新する必要がある場合に限り、 pod install --repo-updateを使います。通常は bundle exec pod installを実行し、毎回Podsやロックファイルを削除しないでください。

キャッシュキーにアーキテクチャと依存関係のロックファイルを含める
Flutterプロジェクトのルートディレクトリ
flutter --version
flutter doctor -v
flutter pub get
flutter build ios --simulator
flutter build ipa --release
React Nativeプロジェクトのルートディレクトリ · npmを使う場合
node --version
npm ci
bundle install
(cd ios && bundle exec pod install)
xcrun simctl list devices available

シミュレーターの並列テスト数には上限を設けてください。利用可能なデバイス一覧から実際のUDIDを2つ取得し、 SIM_UDID_AとSIM_UDID_Bに設定します。次に、 IOS_WORKSPACEとIOS_SCHEME を設定したプロジェクトで以下のテストを実行します。まず1つのデスティネーションから始め、次に2つに増やしてメモリ負荷とディスク書き込みを確認してください。

Xcodeテスト · プロジェクトで使用可能な2台のシミュレーターを指定
xcodebuild test \
  -workspace "$IOS_WORKSPACE" \
  -scheme "$IOS_SCHEME" \
  -destination "platform=iOS Simulator,id=$SIM_UDID_A" \
  -destination "platform=iOS Simulator,id=$SIM_UDID_B" \
  -parallel-testing-enabled YES \
  -maximum-concurrent-test-simulator-destinations 2 \
  -resultBundlePath "build/TestResults-$(date +%s).xcresult"

コンテナの役割 · LinuxサービスとmacOSビルドを分ける

コンテナは関連サービスの実行に使えますが、Xcodeホストの代わりにはなりません

ノードは専有物理Macです。Docker DesktopやOrbStackが提供するLinuxコンテナ環境は、引き続きLinuxランタイム上で動作します。「物理ノード」だからといって、コンテナとmacOSが同じカーネルを共有するわけではありません。

タスク推奨実行環境注意点
テスト用データベース、キャッシュ、内部APILinuxコンテナarm64イメージを優先し、メモリとリッスン範囲を制限します。
XcodeアーカイブとシミュレーターテストmacOSホストmacOS SDK、署名ツール、シミュレーターランタイムが必要です。
amd64イメージのみを提供するサービスまず互換性を検証エミュレーションで負荷が増える場合があり、arm64と同等の性能は期待できません。
常時稼働する関連サービスリソース分離の要件に応じて判断ビルドと物理メモリ、SSD、ネットワークを共有するため、リソースを制限し、バックアップを保管してください。
コンテナツールを選んで起動し、以下を確認
uname -m
docker version
docker info --format '{{.Architecture}}'
docker system df
docker stats --no-stream

Docker DesktopかOrbStackのどちらか一方を選び、コンテナ環境を管理してください。現在のDocker contextの接続先が不明な状態を避けられます。サービスを追加する前に、空きメモリとディスク容量を記録してください。コンテナデータの削除を、標準のトラブル対処にしないでください。

拡張機能 · デバイスを確認してから書き込む

キャッシュを拡張ストレージに移し、複数台を1台として扱わない

追加SSDとThunderbolt 5接続は、それぞれ個別の構成オプションです。デバイス名、マウントパス、ポートの対応状況、接続トポロジーは注文内容をご確認ください。内容を確認する前に、フォーマットやパーティション操作を実行しないでください。

追加SSD:マウントポイントと権限を確認

まず diskutil list external で外付けデバイスを特定し、対象ボリュームの情報を確認します。フォーマット済みでも未マウントの場合は、識別子を確認してから diskutil mount "$DISK_IDENTIFIER"を実行してください。ディスク番号だけで追加SSDだと判断しないでください。

依存関係のキャッシュ、DerivedData、作業中の成果物の保存先としておすすめです。実際のパスをCI変数 BUILD_CACHE_ROOTに設定し、ビルドユーザーが書き込めること、再起動後もパスが有効なことを確認してください。ソースコードと署名データのバックアップは別途保管します。

容量拡張はバックアップの代わりにならない

TB5接続:各マシンの接続トポロジーを確認

接続しても、複数台のCPUやユニファイドメモリが自動的に統合され、1つのプロセスから使えるリソースプールになるわけではありません。アプリケーションまたはCIのスケジューラーでタスクを分散し、各マシンにツールチェーン、ランナー、作業ディレクトリを個別に設定してください。

提供構成にThunderboltネットワーク接続が含まれる場合は、各マシンのネットワークインターフェース、アドレス、ルーティングを確認し、ピア間の接続を検証してください。購入前に、台数、機種、データ転送の用途をサポートチケットでお知らせください。すべての機種で同じポート機能が使えると想定しないでください。

分散タスクにはアプリケーション側の対応が必要
リモートの読み取り専用チェック · ディスクとネットワークを変更しない
diskutil list external
ls -la /Volumes
df -h
system_profiler SPThunderboltDataType
networksetup -listallhardwareports

拡張オプションの4種類の契約期間と料金はプランページをご覧ください。既存の注文内容を変更する場合は、作業方法とデータ移行の手順をサポートチケットで確認してから進めてください。本番ビルド中にディスク構成を変更しないでください。

最後のステップ · 診断情報をもとに原因を特定

最小限の診断情報を集めてから設定を変更

注文番号、ノード、発生時刻とタイムゾーン、最後に正常だったビルドのコミット番号を記録してください。最初のエラーと終了コードを残し、ログの最後の行だけを送らないでください。以下のコマンドは原因の切り分けに使うもので、すべての問題を自動修復するものではありません。

01

SSHで接続できない

まずアドレス、ポート、ユーザー名、秘密鍵のパスを確認します。接続がタイムアウトする場合は、最初にネットワーク到達性を確認してください。認証に失敗する場合は、ユーザー名、公開鍵の登録、ファイル権限を確認します。ホストのフィンガープリントが変わった場合は、無視せずサポートチケットで確認してください。

ローカルターミナル · 出力にホスト情報が含まれる場合があります
ssh -vv -o ConnectTimeout=10 \
  -i "$HOME/.ssh/osxhost_build" \
  -p "$MAC_PORT" "$MAC_USER@$MAC_HOST"
接続について問い合わせる
02

証明書が無効、または署名IDが見つからない

証明書に秘密鍵が含まれているか、有効期限が切れていないか、プロビジョニングプロファイルがアプリとチームに一致するかを確認してください。CI専用キーチェーンにも、ビルドセッションからアクセスできる必要があります。管理された環境で署名アセットを修復してから、readonlyのmatchで同期してください。

リモートターミナル · 署名IDとキーチェーン一覧を確認
security find-identity -v -p codesigning
security list-keychains -d user
bundle exec fastlane match appstore --readonly
署名について問い合わせる
03

ディスク容量不足でアーカイブを書き込めない

まずシステムボリュームと追加ボリュームを区別し、DerivedData、シミュレーター、ビルド成果物の使用量を確認します。再生成できると確認したキャッシュだけを削除してください。キーチェーン、署名ファイル、使用中の作業ディレクトリを一括削除しないでください。

リモートターミナル · ディスク使用量を確認
df -h
du -sh "$HOME/Library/Developer/Xcode/DerivedData" \
  "$HOME/Library/Developer/CoreSimulator" \
  "$HOME/build-workspace" 2>/dev/null
xcrun simctl list devices unavailable
ディスクについて問い合わせる
04

Xcodeのインデックス作成が長時間続く

まずインデックス作成のプロセスが動作中か確認し、依存関係のインストール状況と空きディスク容量をチェックしてください。GUIのインデックス作成とコマンドラインビルドでは完了条件が異なります。ログでアーカイブが実際に停止しているか確認できます。

リモートターミナル · プロセスとビルド設定を確認
ps -axo pid,%cpu,%mem,etime,comm | grep -E 'Xcode|SourceKit|swift'
xcode-select -p
xcodebuild -list -workspace "$IOS_WORKSPACE"
df -h "$HOME"
Xcodeについて問い合わせる

サポートチケットに秘密鍵、証明書のパスワード、アクセストークン、署名リポジトリの全内容を添付しないでください。送信前にログ内の認証情報と機密パスをマスキングしてください。コンソールにログインできない場合は、 support@osxhost.com宛てにメールを送り、注文番号と問題の内容をお知らせください。メールとコンソールのサポートチケットが公式サポート窓口です。

まずアーカイブを1つ完成させてから並列数を増やす

ツールチェーンのバージョン、署名情報の注入、キャッシュキー、成果物の保存先をパイプラインに記録しましょう。マシンが必要な場合はご注文ください。手順で問題が起きた場合は、診断結果を添えてサポートチケットをお送りください。