Langsung ke konten

Cara Menyiapkan CircleCI Self-Hosted Runner di Mac Mini M4

Panduan langkah demi langkah lengkap untuk menginstal dan mengonfigurasi CircleCI self-hosted machine runner di Mac mini M4 dedikasi. Performa Apple Silicon native, caching persisten, dan hingga 90% lebih murah dibanding sumber daya macOS cloud CircleCI.

CI/CD Baca 35 menit Diperbarui Oktober 2026

Mengapa Menggunakan Self-Hosted Runner CircleCI di Mac?

CircleCI menawarkan lingkungan eksekusi macOS berbasis cloud, tetapi disertai biaya dan keterbatasan yang signifikan. CircleCI menagih job macOS dalam kredit: resource class m4pro.medium memakai 200 kredit per menit (sekitar $0.12) dan m4pro.large 400 kredit (sekitar $0.24), per Oktober 2026. Untuk tim yang sering menjalankan build iOS, ini dapat dengan cepat mencapai $300-$500 per bulan atau lebih.

Self-hosted runner di Mac Mini M4 dedikasi dari MyRemoteMac menghilangkan penagihan per menit sepenuhnya. Anda mendapatkan mesin Apple Silicon dedikasi dengan penyimpanan persisten, cache yang sudah terisi, dan akses root penuh dengan biaya bulanan tetap mulai dari $85/bulan. Berikut perbandingan detailnya:

Mengapa Menggunakan Self-Hosted Runner CircleCI di Mac?
MyRemoteMac Self-Hosted CircleCI Cloud macOS
Model Biaya $85/bln tetap (menit tanpa batas) 200 kredit/mnt pada m4pro.medium (~$0.12/menit)
Arsitektur Mac Apple M4 fisik, dialokasikan 1:1 Mesin virtual M4 Pro (6 vCPU, 28 GB)
Kecepatan Build ~5 mnt (proyek yang sama) ~14 mnt (proyek iOS menengah)
Persistensi Cache Persisten di disk (instan) Ephemeral (harus dipulihkan tiap job)
Waktu Tunggu Antrean 0 dtk (hardware dedikasi) 30 dtk - 5 mnt (bervariasi per paket)
Privasi / Kontrol Data Mesin dedikasi, kontrol penuh Infrastruktur bersama
Perangkat Lunak Kustom Akses root penuh, perangkat lunak apa pun Hanya image prainstal

Harga My Remote Mac dalam USD, belum termasuk pajak.

Manfaat Utama: Dengan self-hosted runner yang persisten, cache DerivedData, Swift Package Manager, dan CocoaPods dipertahankan di antara build. Ini saja dapat memangkas waktu build sebesar 50-70% dibanding lingkungan macOS cloud ephemeral CircleCI yang selalu mulai dari nol setiap kali. Dikombinasikan dengan performa single-thread chip M4 yang unggul, build iOS Anda akan jauh lebih cepat.

Prasyarat

Sebelum memulai, pastikan Anda memiliki hal-hal berikut:

  • Server build Mac mini M4 khusus dari My Remote Mac (mulai $85/bln, USD, belum termasuk pajak)
  • Organisasi CircleCI tempat Anda menjadi admin (self-hosted runner tersedia di semua paket, termasuk Free yang mengizinkan 5 tugas self-hosted bersamaan per Oktober 2026)
  • Akses SSH ke Mac Mini Anda (disediakan dengan langganan MyRemoteMac Anda)
  • Akun Apple Developer (untuk code signing dan provisioning profile)
  • Pemahaman dasar tentang YAML, konfigurasi CircleCI, dan perintah terminal

Langkah 1: SSH ke Mac Mini Anda dan Instal Dependensi

Pertama, hubungkan ke Mac Mini M4 Anda melalui SSH. Anda telah menerima kredensial saat menyiapkan server MyRemoteMac Anda. Kita perlu menginstal Xcode dan alat yang diperlukan untuk build iOS sebelum menyiapkan runner CircleCI.

Hubungkan melalui SSH

# Connect to your Mac mini M4
ssh admin@your-server-ip

# Verify you're on Apple Silicon
uname -m
# Expected output: arm64

# Show the macOS version
sw_vers

Instal Homebrew dan Xcode Command Line Tools

# Install Homebrew (if not already installed)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# Add Homebrew to PATH: zsh for your sessions, bash for CircleCI job steps
# (CircleCI runs macOS steps in a bash login shell)
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.bash_profile
eval "$(/opt/homebrew/bin/brew shellenv)"

# Install Xcode Command Line Tools
xcode-select --install

# Accept the license agreement
sudo xcodebuild -license accept

Instal Xcode (Versi Lengkap)

Untuk build iOS, Anda memerlukan aplikasi Xcode lengkap. Sejak 28 April 2026, App Store Connect hanya menerima build yang dibuat dengan Xcode 26 atau lebih baru, jadi instal rilis terbaru dengan xcodes, cara tercepat di server headless:

# Install the xcodes CLI tool
brew install xcodes

# Install the latest release of Xcode (asks for your Apple Account)
xcodes install --latest

# Show where it was installed, then make it the default Xcode
xcodes installed
# e.g. 27.0 (27A266a)  /Applications/Xcode-27.0.0.app
sudo xcode-select -s /Applications/Xcode-27.0.0.app/Contents/Developer

# Verify installation
xcodebuild -version

Instal Simulator iOS dan Build Tools

# Install the current iOS simulator runtime
xcodebuild -downloadPlatform iOS

# Verify simulator availability
xcrun simctl list runtimes

# Install additional build tools
brew install xcbeautify fastlane swiftlint

Langkah 2: Instal Agen Runner CircleCI

Machine runner 3 dari CircleCI menghubungkan Mac mini Anda ke CircleCI: ia menerima job dan menjalankannya langsung di host macOS Anda. Di macOS, CircleCI merekomendasikan instalasi melalui paket Homebrew-nya. Ini berbeda dari container runner (yang hanya bekerja di Linux).

Pilih Pengguna yang Menjalankan Job Anda

Machine runner 3 menjalankan setiap job sebagai pengguna macOS yang memulainya, dengan Homebrew, keychain, dan Xcode milik pengguna itu. Instal dan jalankan dengan pengguna admin Anda, pemilik Homebrew, bukan sebagai root: Homebrew menolak berjalan sebagai root.

# Run the steps below as the user that will run CI jobs, not with sudo
whoami

# Homebrew must work for this user (prints /opt/homebrew)
brew --prefix

Instal Machine Runner 3 dengan Homebrew

# Add CircleCI's Homebrew tap and install machine runner 3
brew tap circleci-public/circleci
brew install circleci-runner

# Check that macOS accepts the binary notarized by CircleCI
spctl -a -vvv -t install "$(brew --prefix)/bin/circleci-runner"
# Expected: accepted, source=Notarized Developer ID,
# origin=Developer ID Application: Circle Internet Services Inc.

# Remove the quarantine attribute (asks for your macOS password)
sudo xattr -r -d com.apple.quarantine "$(brew --prefix)/bin/circleci-runner"

Konfigurasikan Agen Runner

Paket Homebrew membuat file konfigurasi. Anda memerlukan token autentikasi runner dari aplikasi web CircleCI (dibahas di Langkah 3). Untuk saat ini, atur nama runner dan biarkan placeholder untuk tokennya:

# Open the configuration file created by the Homebrew package
nano "$HOME/Library/Preferences/com.circleci.runner/config.yaml"

# Contents (the token comes in Step 3):
runner:
  name: "mac-mini-m4-runner"
  working_directory: "/Users/$USER/Library/com.circleci.runner/workdir"
  cleanup_working_directory: true
api:
  auth_token: "YOUR_RUNNER_TOKEN_HERE"

# The file will hold a secret: make it readable by you only
chmod 600 "$HOME/Library/Preferences/com.circleci.runner/config.yaml"

Siapkan Layanan launchd untuk Mac Headless

Paket Homebrew juga menginstal agen launchd, com.circleci.runner. Agen biasanya mulai saat pengguna Anda login; di Mac yang hanya Anda akses lewat SSH, penyiapan headless dari CircleCI memindahkannya ke /Library/LaunchAgents agar dimuat setelah reboot. Jalankan di Langkah 3, setelah token terpasang:

# The launchd agent installed by the Homebrew package
ls ~/Library/LaunchAgents/com.circleci.runner.plist

# Headless Mac reached over SSH only: move it to the per-user agents
# folder so it loads after a reboot (CircleCI's headless setup)
sudo mv ~/Library/LaunchAgents/com.circleci.runner.plist /Library/LaunchAgents/

Penting: Runner tidak akan terhubung sampai config.yaml berisi token autentikasi yang valid. Buat token di Langkah 3, tambahkan ke file, lalu jalankan layanannya.

Langkah 3: Konfigurasikan Runner di Dasbor CircleCI

Sekarang Anda perlu mendaftarkan runner Anda di antarmuka web CircleCI dan menghasilkan token autentikasi. Ini menghubungkan Mac Mini Anda ke organisasi CircleCI Anda.

Buat Resource Class

Di CircleCI, self-hosted runner diorganisasikan berdasarkan resource class. Resource class adalah label yang memetakan .circleci/config.yml Anda ke sekumpulan runner tertentu.

  1. Di aplikasi web CircleCI, buka Runners di sidebar (Anda harus admin organisasi)
  2. Klik "Create Resource Class"
  3. Atur Namespace ke nama organisasi Anda (mis., your-org)
  4. Atur nama Resource Class ke sesuatu yang deskriptif (mis., mac-runner)
  5. Ini membuat identifier resource class: your-org/mac-runner

Hasilkan Token Autentikasi Runner

  1. Klik "Save and continue": CircleCI membuat resource class dan menampilkan token autentikasinya
  2. Salin token segera dan simpan dengan aman: token hanya ditampilkan sekali
  3. Hilang? Buat yang baru dengan CircleCI CLI: circleci runner token create your-org/mac-runner mac-mini-m4

Tambahkan Token dan Jalankan Runner

# SSH back into your Mac mini
ssh admin@your-server-ip

# Replace YOUR_RUNNER_TOKEN_HERE with the resource class token
nano "$HOME/Library/Preferences/com.circleci.runner/config.yaml"

# Start the service. Headless Mac (plist moved to /Library/LaunchAgents):
launchctl bootstrap user/$(id -u) /Library/LaunchAgents/com.circleci.runner.plist
launchctl enable user/$(id -u)/com.circleci.runner
launchctl kickstart -k user/$(id -u)/com.circleci.runner

# Or, from a desktop session (VNC), with the plist left in ~/Library/LaunchAgents:
# launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.circleci.runner.plist
# launchctl enable gui/$(id -u)/com.circleci.runner
# launchctl kickstart -k gui/$(id -u)/com.circleci.runner

# Verify the service, then read the runner log
launchctl print user/$(id -u)/com.circleci.runner
tail -20 "$HOME/Library/Logs/com.circleci.runner/runner.log"

Setelah terhubung, runner tercantum di bagian Runners pada aplikasi web CircleCI, dan circleci runner instance list your-org/mac-runner juga menampilkannya. Jika tidak muncul dalam 60 detik, periksa file log untuk pesan kesalahan.

Menggunakan CircleCI CLI (Alternatif)

Anda juga dapat mengelola runner melalui CircleCI CLI:

# Install the CircleCI CLI
brew install circleci

# Authenticate with CircleCI
circleci setup

# Create the namespace (once per organization)
circleci namespace create your-org --org-id YOUR_ORGANIZATION_ID

# Create the resource class and print its token
circleci runner resource-class create your-org/mac-runner \
  "Mac mini M4 runner" --generate-token

# List the runners connected to this resource class
circleci runner instance list your-org/mac-runner

Langkah 4: Buat .circleci/config.yml Anda untuk Build iOS

Buat file .circleci/config.yml di root repositori Anda. Perbedaan utama dari konfigurasi CircleCI standar adalah penggunaan machine: true dengan resource_class kustom Anda untuk menargetkan self-hosted runner Anda.

version: 2.1

jobs:
  build-and-test:
    machine: true
    resource_class: your-org/mac-runner

    environment:
      # Xcode for this job, without sudo (path from `xcodes installed`)
      DEVELOPER_DIR: "/Applications/Xcode-27.0.0.app/Contents/Developer"
      SCHEME: "MyApp"
      # Any device listed by: xcrun simctl list devices available
      DESTINATION: "platform=iOS Simulator,name=iPhone 17,OS=latest"

    steps:
      - checkout

      - run:
          name: Show the Xcode version
          command: xcodebuild -version

      # Caches live in $HOME, outside the job's working directory,
      # so they survive cleanup_working_directory between jobs
      - run:
          name: Resolve Swift Package Dependencies
          command: |
            xcodebuild -resolvePackageDependencies \
              -scheme "$SCHEME" \
              -clonedSourcePackagesDirPath "$HOME/spm-cache"

      - run:
          name: Build the app
          command: |
            xcodebuild build \
              -scheme "$SCHEME" \
              -destination "generic/platform=iOS Simulator" \
              -clonedSourcePackagesDirPath "$HOME/spm-cache" \
              -derivedDataPath "$HOME/DerivedData/$SCHEME" \
              | xcbeautify

      # store_test_results needs JUnit XML: xcbeautify writes test-results/junit.xml
      - run:
          name: Run unit tests
          command: |
            xcodebuild test \
              -scheme "$SCHEME" \
              -destination "$DESTINATION" \
              -clonedSourcePackagesDirPath "$HOME/spm-cache" \
              -derivedDataPath "$HOME/DerivedData/$SCHEME" \
              -resultBundlePath TestResults.xcresult \
              | xcbeautify --report junit --report-path test-results

      - store_test_results:
          path: test-results

      - store_artifacts:
          path: TestResults.xcresult
          destination: test-results

workflows:
  ios-pipeline:
    jobs:
      - build-and-test:
          filters:
            branches:
              only:
                - main
                - develop

Catatan: Nilai resource_class: your-org/mac-runner harus sama persis dengan resource class yang Anda buat di dasbor CircleCI. Jika tidak cocok, job akan tetap dalam antrean tanpa batas waktu.

Langkah 5: Optimalkan dengan Caching dan Paralelisme

Salah satu keunggulan terbesar dari self-hosted runner adalah caching persisten. Karena filesystem runner bersifat persisten, Anda tidak perlu mengunggah dan mengunduh cache seperti pada sumber daya cloud CircleCI. Namun, ada optimasi tambahan untuk memaksimalkan kecepatan build Anda.

Manfaatkan DerivedData Persisten

Karena disk runner bertahan di antara build, DerivedData sudah otomatis di-cache. Gunakan path yang konsisten:

# In your config.yml steps, always use a consistent DerivedData path:
- run:
    name: Build with persistent cache
    command: |
      xcodebuild build \
        -scheme "$SCHEME" \
        -destination "$DESTINATION" \
        -derivedDataPath ~/DerivedData/"$SCHEME" \
        -clonedSourcePackagesDirPath ~/spm-cache \
        | xcbeautify

# Periodically clean old DerivedData on the runner (cron job):
# 0 3 * * 0 find ~/DerivedData -mindepth 1 -maxdepth 1 -mtime +7 -exec rm -rf {} +

Persistensi Workspace di Antara Job

Gunakan workspace CircleCI untuk meneruskan produk hasil build ke job pengujian, yang bisa berjalan di Mac lain dalam resource class yang sama:

jobs:
  build:
    machine: true
    resource_class: your-org/mac-runner
    steps:
      - checkout
      - run:
          name: Build for testing
          command: |
            xcodebuild build-for-testing \
              -scheme "MyApp" \
              -destination "generic/platform=iOS Simulator" \
              -derivedDataPath DerivedData \
              | xcbeautify
      # Pass only the built products, not the whole DerivedData
      - persist_to_workspace:
          root: .
          paths:
            - DerivedData/Build/Products

  test:
    machine: true
    resource_class: your-org/mac-runner
    steps:
      - attach_workspace:
          at: .
      - run:
          name: Run the tests built by the previous job
          command: |
            xcodebuild test-without-building \
              -xctestrun "$(ls DerivedData/Build/Products/*.xctestrun | head -n 1)" \
              -destination "platform=iOS Simulator,name=iPhone 17,OS=latest" \
              | xcbeautify --report junit --report-path test-results
      - store_test_results:
          path: test-results

workflows:
  build-test:
    jobs:
      - build
      - test:
          requires:
            - build

Eksekusi Pengujian Paralel

- run:
    name: Run tests in parallel
    command: |
      # Xcode clones the simulator and runs test classes on up to 4 clones
      xcodebuild test \
        -scheme "MyApp" \
        -destination "platform=iOS Simulator,name=iPhone 17,OS=latest" \
        -parallel-testing-enabled YES \
        -maximum-parallel-testing-workers 4 \
        -derivedDataPath ~/DerivedData/MyApp \
        | xcbeautify

Test Splitting CircleCI

Untuk suite pengujian besar, test splitting CircleCI membagi kelas pengujian ke beberapa tugas paralel. Setiap tugas memerlukan runner sendiri, jadi parallelism: 3 memerlukan tiga Mac dalam resource class; di satu Mac, tugas-tugas berjalan bergantian:

jobs:
  test:
    machine: true
    resource_class: your-org/mac-runner
    # One task per runner: 3 tasks need 3 Macs in this resource class
    parallelism: 3
    steps:
      - checkout
      - run:
          name: Split test classes and run this task's share
          command: |
            # One XCTest class per file, named like the file (LoginTests.swift)
            CLASSES=$(circleci tests glob "MyAppTests/**/*Tests.swift" \
              | xargs -n1 basename | sed 's/\.swift$//' \
              | circleci tests split)

            # -only-testing takes Target/Class identifiers, not file paths
            ONLY_TESTING=""
            for CLASS in $CLASSES; do
              ONLY_TESTING="$ONLY_TESTING -only-testing:MyAppTests/$CLASS"
            done

            xcodebuild test \
              -scheme "MyApp" \
              -destination "platform=iOS Simulator,name=iPhone 17,OS=latest" \
              $ONLY_TESTING \
              | xcbeautify --report junit --report-path test-results
      - store_test_results:
          path: test-results

Contoh Workflow

Berikut contoh workflow lengkap yang siap produksi untuk skenario CI/CD iOS yang umum.

Pipeline Build, Test, dan Deploy iOS Lengkap

version: 2.1

jobs:
  lint:
    machine: true
    resource_class: your-org/mac-runner
    steps:
      - checkout
      - run:
          name: Run SwiftLint
          command: swiftlint lint --reporter json > swiftlint-results.json || true
      - store_artifacts:
          path: swiftlint-results.json

  build-and-test:
    machine: true
    resource_class: your-org/mac-runner
    environment:
      # Xcode for this job, without sudo (path from `xcodes installed`)
      DEVELOPER_DIR: "/Applications/Xcode-27.0.0.app/Contents/Developer"
    steps:
      - checkout
      - run:
          name: Resolve dependencies
          command: |
            xcodebuild -resolvePackageDependencies \
              -scheme "MyApp" \
              -clonedSourcePackagesDirPath ~/spm-cache
      - run:
          name: Build and test
          command: |
            xcodebuild test \
              -scheme "MyApp" \
              -destination "platform=iOS Simulator,name=iPhone 17,OS=latest" \
              -clonedSourcePackagesDirPath ~/spm-cache \
              -derivedDataPath ~/DerivedData/MyApp \
              -resultBundlePath TestResults.xcresult \
              -parallel-testing-enabled YES \
              | xcbeautify --report junit --report-path test-results
      - store_test_results:
          path: test-results
      - store_artifacts:
          path: TestResults.xcresult

  deploy-testflight:
    machine: true
    resource_class: your-org/mac-runner
    environment:
      DEVELOPER_DIR: "/Applications/Xcode-27.0.0.app/Contents/Developer"
    steps:
      - checkout
      - run:
          name: Install dependencies
          command: bundle install
      # MATCH_PASSWORD and the App Store Connect API key variables
      # (ASC_KEY_ID, ASC_ISSUER_ID, ASC_KEY_CONTENT) come from a CircleCI
      # context or the project's environment variables
      - run:
          name: Build and upload to TestFlight
          command: bundle exec fastlane beta

workflows:
  ios-pipeline:
    jobs:
      - lint
      - build-and-test:
          requires:
            - lint
      - deploy-testflight:
          requires:
            - build-and-test
          filters:
            branches:
              only: main

Contoh Integrasi Fastlane

Jika Anda menggunakan Fastlane untuk otomatisasi build, berikut cara mengintegrasikannya dengan self-hosted runner CircleCI Anda:

# Fastfile (fastlane/Fastfile)
default_platform(:ios)

platform :ios do
  desc "Run tests"
  lane :test do
    scan(
      scheme: "MyApp",
      device: "iPhone 17",
      derived_data_path: File.expand_path("~/DerivedData/MyApp"),
      result_bundle: true,
      output_directory: "./test_output",
      # store_test_results reads JUnit XML
      output_types: "junit",
      output_files: "junit.xml"
    )
  end

  desc "Build and push to TestFlight"
  lane :beta do
    # App Store Connect API key: no Apple ID password or 2FA on the runner
    app_store_connect_api_key(
      key_id: ENV["ASC_KEY_ID"],
      issuer_id: ENV["ASC_ISSUER_ID"],
      key_content: ENV["ASC_KEY_CONTENT"]
    )
    match(type: "appstore", readonly: true)
    increment_build_number(
      build_number: ENV["CIRCLE_BUILD_NUM"]
    )
    gym(
      scheme: "MyApp",
      export_method: "app-store",
      derived_data_path: File.expand_path("~/DerivedData/MyApp")
    )
    pilot(skip_waiting_for_build_processing: true)
  end
end
# .circleci/config.yml using Fastlane
version: 2.1

jobs:
  fastlane-test:
    machine: true
    resource_class: your-org/mac-runner
    steps:
      - checkout
      - run:
          name: Install dependencies
          command: bundle install
      - run:
          name: Run Fastlane tests
          command: bundle exec fastlane test
      - store_test_results:
          path: ./test_output
      - store_artifacts:
          path: ./test_output

  fastlane-deploy:
    machine: true
    resource_class: your-org/mac-runner
    steps:
      - checkout
      - run:
          name: Install dependencies
          command: bundle install
      - run:
          name: Deploy to TestFlight
          command: bundle exec fastlane beta

workflows:
  ios-workflow:
    jobs:
      - fastlane-test
      - fastlane-deploy:
          requires:
            - fastlane-test
          filters:
            branches:
              only: main

Perbandingan Performa

Berikut perbandingan performa dan biaya yang detail antara sumber daya macOS cloud CircleCI dan Mac Mini M4 self-hosted dari MyRemoteMac:

Benchmark Waktu Build

Benchmark Waktu Build
Mac Mini M4 Self-Hosted CircleCI Cloud macOS Peningkatan
Clean build (aplikasi menengah) 5 mnt 14 mnt 2.8x lebih cepat
Build inkremental 1.5 mnt 14 mnt (tanpa cache) 9.3x lebih cepat
Resolusi dependensi SPM 5 dtk (di-cache di disk) 3-5 mnt (unduh setiap kali) ~60x lebih cepat
Suite unit test (500 pengujian) 2.5 mnt 8 mnt 3.2x lebih cepat
Waktu tunggu antrean 0 dtk 30 dtk - 5 mnt Instan

Analisis Biaya Bulanan

Analisis Biaya Bulanan
Ukuran Tim Biaya MyRemoteMac Build/Bulan Biaya CircleCI Cloud Penghematan Bulanan
Dev Solo $85/bln 100 build (rata-rata 10 mnt) $120/bln $35/bln
Tim Kecil (5) $85/bln 500 build (rata-rata 10 mnt) $600/bln $515/bln
Tim Menengah (15) $229/bln (M4 Pro) 1500 build (rata-rata 10 mnt) $1,800/bln $1,571/bln
Enterprise (50+) $458/bln (2x M4 Pro) 5000+ build $6,000+/bln $5,542+/bln

Harga My Remote Mac dalam USD, belum termasuk pajak.

Kesimpulan: Dengan tarif CircleCI untuk kelas m4pro.medium (200 kredit, sekitar $0.12 per menit, per Oktober 2026), satu build 10 menit berbiaya sekitar $1.20, sehingga Mac mini M4 khusus seharga $85/bln (USD, belum termasuk pajak) lebih murah mulai sekitar 71 build per bulan. Cache yang sudah terisi di Mac persisten juga memangkas waktu tunggu tim Anda di setiap build.

Pemecahan Masalah Umum

Runner terputus atau muncul sebagai "Offline"

Runner bisa kehilangan koneksi setelah masalah jaringan, crash, atau reboot. Jika dijalankan di domain gui, runner baru kembali saat penggunanya login; penyiapan headless dari Langkah 2 menghindari hal itu. Periksa layanan dan log-nya:

# Check the service (use gui/ instead of user/ if you started it
# from a desktop session)
launchctl print user/$(id -u)/com.circleci.runner

# View the runner log
tail -50 "$HOME/Library/Logs/com.circleci.runner/runner.log"

# Restart the service
launchctl kickstart -k user/$(id -u)/com.circleci.runner

# If the token was revoked, create a new one, put it in
# ~/Library/Preferences/com.circleci.runner/config.yaml and restart
circleci runner token create your-org/mac-runner mac-mini-m4

resource_class tidak ditemukan atau job macet dalam antrean

Jika job tetap dalam antrean dengan "No matching runner found", resource class di konfigurasi Anda tidak cocok dengan dasbor:

# Verify the exact resource class name in the CircleCI web app:
# Runners (sidebar) lists your resource classes

# The resource_class in .circleci/config.yml must match exactly:
# resource_class: your-org/mac-runner  (case-sensitive!)

# Check your runner is online:
circleci runner instance list your-org/mac-runner

# Common mistakes:
# - Wrong namespace (org name vs personal namespace)
# - Typo in resource class name
# - Runner is offline or token is invalid
# - Using 'docker' executor instead of 'machine: true'

Kesalahan code signing Xcode

Code signing di mesin CI memerlukan pengelolaan keychain yang cermat. Proses runner mungkin tidak memiliki akses ke login keychain:

# Option 1: Use Fastlane Match (recommended)
# In your Fastfile:
match(type: "appstore", readonly: true)

# Option 2: Manual keychain management in your job steps
- run:
    name: Setup code signing
    command: |
      # Decode and import the certificate
      echo "$BUILD_CERTIFICATE_BASE64" | base64 --decode > /tmp/cert.p12

      # Create a temporary keychain
      security create-keychain -p "ci" /tmp/ci.keychain
      security set-keychain-settings -lut 21600 /tmp/ci.keychain
      security unlock-keychain -p "ci" /tmp/ci.keychain

      # Import the certificate
      security import /tmp/cert.p12 -P "$P12_PASSWORD" \
        -A -t cert -f pkcs12 -k /tmp/ci.keychain
      # Let codesign use the key without a GUI prompt
      security set-key-partition-list -S apple-tool:,apple:,codesign: \
        -s -k "ci" /tmp/ci.keychain
      security list-keychain -d user -s /tmp/ci.keychain

      # Install the provisioning profile (Xcode 16 and later location)
      PROFILES=~/Library/Developer/Xcode/UserData/Provisioning\ Profiles
      mkdir -p "$PROFILES"
      echo "$PROVISIONING_PROFILE_BASE64" | base64 --decode \
        > "$PROFILES/profile.mobileprovision"

Simulator gagal boot atau time out

Simulator dapat mengalami kondisi buruk pada mesin CI yang berjalan lama. Reset di antara build:

# Add a pre-build step to clean simulators
- run:
    name: Reset simulators
    command: |
      xcrun simctl shutdown all 2>/dev/null || true
      xcrun simctl erase all 2>/dev/null || true

# If a specific runtime is missing, reinstall it:
xcodebuild -downloadPlatform iOS

# List available simulators
xcrun simctl list devices available

Ruang disk menipis

Build Xcode menghasilkan data dalam jumlah besar. Siapkan pembersihan otomatis pada runner Anda:

# Check available disk space
df -h /

# Clean DerivedData folders unused for a week
find ~/DerivedData ~/Library/Developer/Xcode/DerivedData \
  -mindepth 1 -maxdepth 1 -mtime +7 -exec rm -rf {} +

# Delete simulators the current Xcode no longer supports
xcrun simctl delete unavailable

# List simulator runtimes, then delete the ones you no longer test on
xcrun simctl runtime list
# xcrun simctl runtime delete <runtime-identifier>

# Clean Homebrew cache
brew cleanup --prune=7

# Set up a weekly cron job for automatic cleanup
(crontab -l 2>/dev/null; echo "0 4 * * 0 find ~/DerivedData -mindepth 1 -maxdepth 1 -mtime +7 -exec rm -rf {} + ; /opt/homebrew/bin/brew cleanup --prune=7") | crontab -

Pertanyaan yang Sering Diajukan

Berapa biaya CircleCI self-hosted runner di Mac Mini M4?
Mac mini M4 khusus dari My Remote Mac mulai $85/bln (USD, belum termasuk pajak) dengan menit build tanpa batas, dan CircleCI tidak menagih per menit build pada self-hosted runner. Job macOS cloud CircleCI berbiaya sekitar $0.12 per menit pada kelas m4pro.medium (200 kredit seharga $0.0006 per kredit, per Oktober 2026), kira-kira $300-500/bln untuk tim aktif. Dengan runner sendiri, biaya tetap dapat diprediksi berapa pun volume build-nya.
Bisakah saya menggunakan CircleCI self-hosted runner untuk build iOS dan macOS?
Ya. Self-hosted runner di Mac Mini M4 dapat menjalankan beban kerja macOS apa pun, termasuk build iOS, build aplikasi macOS, pengujian paket Swift, pengujian UI Xcode, dan otomatisasi Fastlane. Karena berjalan secara native di Apple Silicon, build lebih cepat dibanding runner cloud berbasis emulasi atau Intel.
Apa perbedaan antara machine runner dan container runner CircleCI?
Machine runner CircleCI menjalankan job langsung di sistem operasi mesin host, yang diperlukan untuk build macOS/iOS yang membutuhkan Xcode, simulator, dan framework Apple. Container runner menjalankan job di dalam kontainer Docker dan hanya tersedia di Linux. Untuk build Mac, Anda harus menggunakan machine runner.
Bagaimana cara menjaga CircleCI self-hosted runner saya tetap diperbarui?
Machine runner 3 tidak memperbarui dirinya sendiri: dengan paket Homebrew, Anda memilih kapan memperbarui dengan menjalankan brew upgrade circleci-runner, lalu me-restart layanannya. Periksa changelog runner setiap bulan dan jaga Xcode serta macOS tetap diperbarui.
Apakah self-hosted runner lebih cepat dibanding macOS cloud CircleCI?
Ya, biasanya 2-3x lebih cepat untuk clean build dan hingga 9x lebih cepat untuk build inkremental. CircleCI menjalankan setiap job macOS cloud di mesin virtual M4 Pro yang baru, sehingga DerivedData dan cache paket harus dipulihkan setiap kali. Mac mini M4 self-hosted adalah mesin fisik khusus untuk Anda, dengan cache DerivedData dan SPM yang persisten dan tanpa menunggu mesin cloud menyala.
Bisakah saya menjalankan beberapa job CircleCI secara bersamaan di satu Mac Mini?
Tidak dengan satu runner. CircleCI mendukung satu machine runner per mesin, dan setiap runner mengambil satu job dalam satu waktu, sehingga job yang dikirim ke resource class yang sama menunggu sampai Mac kosong. Untuk menjalankan job secara paralel, tambahkan satu Mac untuk setiap job bersamaan tambahan dan daftarkan di resource class yang sama: CircleCI mengirim setiap job dalam antrean ke runner yang kosong, dalam batas tugas self-hosted bersamaan paket Anda (5 di Free, 20 di Performance, per Oktober 2026). Di dalam satu job, Xcode tetap bisa menjalankan pengujian secara paralel di beberapa simulator. Untuk job yang lebih berat, Mac mini M4 Pro (CPU 12-core, 24 GB, mulai $229/bln, USD, belum termasuk pajak) memberi ruang lebih.

Mulai dengan Mac Mini M4 untuk Pipeline CircleCI Anda

Deploy Mac Mini M4 dedikasi sebagai CircleCI self-hosted runner Anda. Menit build tanpa batas mulai dari $85/bulan.

Harga My Remote Mac dalam USD, belum termasuk pajak.

Butuh detail lebih lanjut?

Jelajahi dokumentasi lengkap untuk panduan langkah demi langkah, referensi konfigurasi, dan pemecahan masalah.

Buka dokumentasi →