Guida - CI/CD

Come configurare un runner self-hosted CircleCI su Mac Mini M4

Guida completa passo passo all'installazione e alla configurazione di un machine runner self-hosted CircleCI su un Mac Mini M4 dedicato. Prestazioni Apple Silicon native, caching persistente e fino all'80% più economico delle risorse macOS cloud di CircleCI.

35 min di lettura Aggiornato a marzo 2026

1. Perché usare un runner CircleCI self-hosted su Mac?

CircleCI offre ambienti di esecuzione macOS basati sul cloud, ma comportano costi e limitazioni significativi. Le risorse macOS su CircleCI usano un sistema basato su crediti in cui ogni minuto su un executor macOS consuma 50-100 crediti a seconda della resource class. Per i team che eseguono build iOS frequenti, questo può rapidamente arrivare a $300-$500 al mese o più.

Un runner self-hosted su un Mac Mini M4 dedicato di MyRemoteMac elimina del tutto la fatturazione al minuto. Ottieni una macchina Apple Silicon dedicata con archiviazione persistente, cache calde e accesso root completo per una tariffa mensile fissa a partire da $85/mese. Ecco un confronto dettagliato:

Caratteristica CircleCI Cloud macOS MyRemoteMac self-hosted
Modello di costo 50-100 crediti/min (~$0,06-$0,12/min) $85/mese fisso (minuti illimitati)
Architettura Intel x86 o M1 (condiviso) Apple M4 (dedicato, ultima generazione)
Velocità di build ~14 min (progetto iOS medio) ~5 min (stesso progetto)
Persistenza della cache Effimera (da ripristinare a ogni job) Persistente su disco (istantanea)
Tempo di attesa in coda 30s - 5min (varia in base al piano) 0s (hardware dedicato)
Privacy / controllo dei dati Infrastruttura condivisa Macchina dedicata, controllo totale
Software personalizzato Solo immagine preinstallata Accesso root completo, qualsiasi software

Vantaggio chiave: con un runner self-hosted persistente, DerivedData, le cache di Swift Package Manager e CocoaPods vengono conservati tra una build e l'altra. Questo da solo può ridurre i tempi di build del 50-70% rispetto agli ambienti macOS cloud effimeri di CircleCI, che ripartono da zero ogni volta. Combinato con le prestazioni single-thread superiori del chip M4, le tue build iOS saranno notevolmente più veloci.

2. Prerequisiti

Prima di iniziare, assicurati di avere quanto segue:

  • Un Mac Mini M4 server di MyRemoteMac (a partire da $85/mese)
  • Un account CircleCI con un piano Performance, Scale o Server (i runner self-hosted richiedono un piano a pagamento)
  • Accesso SSH al tuo Mac Mini (fornito con il tuo abbonamento MyRemoteMac)
  • Un account Apple Developer (per il code signing e i provisioning profile)
  • Familiarità di base con YAML, la configurazione di CircleCI e i comandi da terminale

3. Passaggio 1: accedi via SSH al tuo Mac Mini e installa le dipendenze

Innanzitutto, collegati al tuo Mac Mini M4 via SSH. Avrai ricevuto le tue credenziali quando hai configurato il tuo server MyRemoteMac. Dobbiamo installare Xcode e gli strumenti richiesti per le build iOS prima di configurare il runner CircleCI.

Collegati via SSH

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

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

# Check macOS version
sw_vers
# ProductName:    macOS
# ProductVersion: 15.2
# BuildVersion:   24C101

Installa Homebrew e gli 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
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"

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

# Accept the license agreement
sudo xcodebuild -license accept

Installa Xcode (versione completa)

Per le build iOS ti serve l'applicazione Xcode completa. Il modo più veloce per installarla su un server senza interfaccia grafica è usare xcodes:

# Install xcodes CLI tool
brew install xcodes

# List available Xcode versions
xcodes list

# Install the latest stable Xcode
xcodes install 16.2

# Set it as the active Xcode
sudo xcode-select -s /Applications/Xcode-16.2.app/Contents/Developer

# Verify installation
xcodebuild -version
# Xcode 16.2
# Build version 16C5032a

Installa i simulatori iOS e gli strumenti di build

# Install the iOS 18 simulator runtime
xcodebuild -downloadPlatform iOS

# Verify simulator availability
xcrun simctl list runtimes
# == Runtimes ==
# iOS 18.2 (18.2 - 22C150) - com.apple.CoreSimulator.SimRuntime.iOS-18-2

# Install additional build tools
brew install xcbeautify fastlane swiftlint

4. Passaggio 2: installa il runner agent di CircleCI

CircleCI usa un machine runner agent per collegare il tuo Mac Mini alla piattaforma CircleCI. Il machine runner riceve i job da CircleCI e li esegue direttamente sul tuo host macOS. Questo è diverso dal container runner (che funziona solo su Linux).

Crea un utente dedicato per il runner

Si consiglia di creare un utente dedicato per eseguire l'agent CircleCI ai fini dell'isolamento di sicurezza:

# Create a circleci user (optional but recommended)
sudo dscl . -create /Users/circleci
sudo dscl . -create /Users/circleci UserShell /bin/zsh
sudo dscl . -create /Users/circleci RealName "CircleCI Runner"
sudo dscl . -create /Users/circleci UniqueID 550
sudo dscl . -create /Users/circleci PrimaryGroupID 20
sudo dscl . -create /Users/circleci NFSHomeDirectory /Users/circleci
sudo mkdir -p /Users/circleci
sudo chown circleci:staff /Users/circleci

# Or simply use your existing admin user (simpler setup)

Scarica e installa il runner agent

# Create a directory for the runner
sudo mkdir -p /opt/circleci

# Download the latest CircleCI machine runner for macOS ARM64
# Check https://circleci.com/docs/runner-installation-mac/ for latest version
curl -o /tmp/circleci-runner.pkg \
  https://circleci-binary-releases.s3.amazonaws.com/circleci-runner/1.0/circleci-runner_darwin_arm64.pkg

# Install the runner package
sudo installer -pkg /tmp/circleci-runner.pkg -target /

# Verify the installation
circleci-runner --version

Configura il runner agent

Crea il file di configurazione del runner. Ti servirà il tuo token di autenticazione del runner dalla dashboard di CircleCI (trattato nel Passaggio 3). Per ora, crea la struttura del file di configurazione:

# Create the configuration directory
sudo mkdir -p /opt/circleci/config

# Create the runner configuration file
sudo tee /opt/circleci/config/runner-agent-config.yaml << 'EOF'
api:
  auth_token: YOUR_RUNNER_TOKEN_HERE

runner:
  name: mac-mini-m4-runner
  working_directory: /opt/circleci/workdir
  cleanup_working_directory: true
  max_run_time: 5h

  # Optional: limit concurrent tasks
  # command_prefix: ["nice", "-n", "10"]

logging:
  file: /opt/circleci/logs/runner.log
EOF

# Create required directories
sudo mkdir -p /opt/circleci/workdir
sudo mkdir -p /opt/circleci/logs

# Set permissions (adjust user if using dedicated circleci user)
sudo chown -R admin:staff /opt/circleci

Crea un launch agent macOS per la persistenza

Per garantire che il runner si avvii automaticamente all'accensione e si riavvii in caso di crash, crea un LaunchDaemon macOS:

# Create the LaunchDaemon plist
sudo tee /Library/LaunchDaemons/com.circleci.runner.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.circleci.runner</string>
    <key>ProgramArguments</key>
    <array>
        <string>/opt/circleci/circleci-runner</string>
        <string>machine</string>
        <string>--config</string>
        <string>/opt/circleci/config/runner-agent-config.yaml</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StandardOutPath</key>
    <string>/opt/circleci/logs/runner-stdout.log</string>
    <key>StandardErrorPath</key>
    <string>/opt/circleci/logs/runner-stderr.log</string>
    <key>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
    </dict>
</dict>
</plist>
EOF

# Load and start the service
sudo launchctl load /Library/LaunchDaemons/com.circleci.runner.plist

# Verify the service is running
sudo launchctl list | grep circleci
# Expected: PID listed with com.circleci.runner

# Check the logs
tail -f /opt/circleci/logs/runner.log

Importante: il runner agent non si connetterà finché non aggiungi un token di autenticazione valido. Completa prima il Passaggio 3 per generare il token, poi aggiorna il file runner-agent-config.yaml con il token reale e riavvia il servizio.

5. Passaggio 3: configura il runner nella dashboard di CircleCI

Ora devi registrare il tuo runner nell'interfaccia web di CircleCI e generare un token di autenticazione. Questo collega il tuo Mac Mini alla tua organizzazione CircleCI.

Crea una resource class

In CircleCI, i runner self-hosted sono organizzati per resource class. Una resource class è un'etichetta che mappa il tuo .circleci/config.yml a un insieme specifico di runner.

  1. Vai su CircleCI DashboardOrganization SettingsSelf-Hosted Runners
  2. Clicca su "Create Resource Class"
  3. Imposta il Namespace sul nome della tua organizzazione (ad es. your-org)
  4. Imposta il nome della Resource Class su qualcosa di descrittivo (ad es. mac-runner)
  5. Questo crea un identificatore di resource class: your-org/mac-runner

Genera un token di autenticazione del runner

  1. Dopo aver creato la resource class, clicca su "Create New Token"
  2. Assegna al token un nome descrittivo (ad es. mac-mini-m4-token)
  3. Copia immediatamente il token generato — verrà mostrato una sola volta

Aggiorna la configurazione del runner con il tuo token

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

# Update the runner configuration with your real token
sudo nano /opt/circleci/config/runner-agent-config.yaml

# Replace YOUR_RUNNER_TOKEN_HERE with the actual token:
# api:
#   auth_token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...

# Restart the runner service to apply the new token
sudo launchctl unload /Library/LaunchDaemons/com.circleci.runner.plist
sudo launchctl load /Library/LaunchDaemons/com.circleci.runner.plist

# Verify the runner connects successfully
tail -20 /opt/circleci/logs/runner.log
# Look for: "Runner is ready to receive jobs"

Una volta connesso, il runner dovrebbe apparire come "Online" nella dashboard di CircleCI sotto Self-Hosted Runners. Se non appare entro 60 secondi, controlla il file di log per eventuali messaggi di errore.

Usare la CLI di CircleCI (alternativa)

Puoi anche gestire i runner tramite la CLI di CircleCI:

# Install the CircleCI CLI
brew install circleci

# Authenticate with CircleCI
circleci setup

# Create a resource class via CLI
circleci runner resource-class create your-org/mac-runner \
  "Mac Mini M4 Runner" --generate-token

# List your runners
circleci runner instance list your-org/mac-runner

6. Passaggio 4: crea il tuo .circleci/config.yml per le build iOS

Crea un file .circleci/config.yml nella radice del tuo repository. La differenza fondamentale rispetto a una configurazione CircleCI standard è l'uso di machine: true con la tua resource_class personalizzata per puntare al tuo runner self-hosted.

version: 2.1

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

    environment:
      SCHEME: "MyApp"
      DESTINATION: "platform=iOS Simulator,name=iPhone 16 Pro,OS=18.2"
      DERIVED_DATA_PATH: "DerivedData"
      SPM_CACHE_PATH: ".spm-cache"

    steps:
      - checkout

      - run:
          name: Select Xcode version
          command: |
            sudo xcode-select -s /Applications/Xcode-16.2.app/Contents/Developer
            xcodebuild -version

      - run:
          name: Resolve Swift Package Dependencies
          command: |
            xcodebuild -resolvePackageDependencies \
              -scheme "$SCHEME" \
              -clonedSourcePackagesDirPath "$SPM_CACHE_PATH"

      - run:
          name: Build the app
          command: |
            xcodebuild build \
              -scheme "$SCHEME" \
              -destination "$DESTINATION" \
              -clonedSourcePackagesDirPath "$SPM_CACHE_PATH" \
              -derivedDataPath "$DERIVED_DATA_PATH" \
              | xcbeautify

      - run:
          name: Run unit tests
          command: |
            xcodebuild test \
              -scheme "$SCHEME" \
              -destination "$DESTINATION" \
              -clonedSourcePackagesDirPath "$SPM_CACHE_PATH" \
              -derivedDataPath "$DERIVED_DATA_PATH" \
              -resultBundlePath TestResults.xcresult \
              | xcbeautify

      - store_test_results:
          path: TestResults.xcresult

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

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

Nota: il valore resource_class: your-org/mac-runner deve corrispondere esattamente alla resource class che hai creato nella dashboard di CircleCI. Se non corrisponde, i job rimarranno in coda a tempo indeterminato.

7. Passaggio 5: ottimizza con caching e parallelismo

Uno dei maggiori vantaggi di un runner self-hosted è il caching persistente. Poiché il filesystem del runner è persistente, non devi caricare e scaricare le cache come fai con le risorse cloud di CircleCI. Tuttavia, ci sono ottimizzazioni aggiuntive per massimizzare la velocità delle build.

Sfrutta i DerivedData persistenti

Poiché il disco del runner persiste tra una build e l'altra, i DerivedData sono già memorizzati in cache automaticamente. Usa un percorso coerente:

# 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 -maxdepth 1 -mtime +7 -exec rm -rf {} +

Persistenza del workspace tra i job

Usa i workspace di CircleCI per passare gli artefatti tra i job nello stesso workflow:

jobs:
  build:
    machine: true
    resource_class: your-org/mac-runner
    steps:
      - checkout
      - run:
          name: Build
          command: |
            xcodebuild build \
              -scheme "MyApp" \
              -destination "generic/platform=iOS" \
              -derivedDataPath DerivedData
      - persist_to_workspace:
          root: .
          paths:
            - DerivedData

  test:
    machine: true
    resource_class: your-org/mac-runner
    steps:
      - checkout
      - attach_workspace:
          at: .
      - run:
          name: Run tests
          command: |
            xcodebuild test \
              -scheme "MyApp" \
              -destination "platform=iOS Simulator,name=iPhone 16 Pro,OS=18.2" \
              -derivedDataPath DerivedData \
              | xcbeautify

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

Esecuzione parallela dei test

- run:
    name: Run tests in parallel
    command: |
      xcodebuild test \
        -scheme "MyApp" \
        -destination "platform=iOS Simulator,name=iPhone 16 Pro,OS=18.2" \
        -destination "platform=iOS Simulator,name=iPhone 15,OS=17.5" \
        -parallel-testing-enabled YES \
        -maximum-parallel-testing-workers 4 \
        -derivedDataPath DerivedData \
        | xcbeautify

Test splitting di CircleCI

Per suite di test di grandi dimensioni, usa il test splitting integrato di CircleCI per distribuire i test tra runner paralleli:

jobs:
  test:
    machine: true
    resource_class: your-org/mac-runner
    parallelism: 3
    steps:
      - checkout
      - run:
          name: Split and run tests
          command: |
            # Generate test plan
            TESTS=$(circleci tests glob "**/*Tests.swift" | \
              circleci tests split --split-by=timings)

            # Run only this container's portion of tests
            xcodebuild test \
              -scheme "MyApp" \
              -destination "platform=iOS Simulator,name=iPhone 16 Pro,OS=18.2" \
              -only-testing:$TESTS \
              | xcbeautify

8. Esempi di workflow

Ecco esempi di workflow completi e pronti per la produzione per scenari CI/CD iOS comuni.

Pipeline completa di build, test e deploy iOS

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
    steps:
      - checkout
      - run:
          name: Select Xcode
          command: sudo xcode-select -s /Applications/Xcode-16.2.app/Contents/Developer
      - 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 16 Pro,OS=18.2" \
              -clonedSourcePackagesDirPath ~/spm-cache \
              -derivedDataPath ~/DerivedData/MyApp \
              -resultBundlePath TestResults.xcresult \
              -parallel-testing-enabled YES \
              | xcbeautify
      - store_test_results:
          path: TestResults.xcresult
      - store_artifacts:
          path: TestResults.xcresult

  deploy-testflight:
    machine: true
    resource_class: your-org/mac-runner
    steps:
      - checkout
      - run:
          name: Select Xcode
          command: sudo xcode-select -s /Applications/Xcode-16.2.app/Contents/Developer
      - run:
          name: Install certificates with Fastlane Match
          command: |
            fastlane match appstore --readonly
      - run:
          name: Build and upload to TestFlight
          command: |
            fastlane beta
          environment:
            FASTLANE_USER: ${APPLE_ID}
            MATCH_PASSWORD: ${MATCH_PASSWORD}

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

Esempio di integrazione con Fastlane

Se usi Fastlane per l'automazione delle tue build, ecco come integrarlo con il tuo runner self-hosted CircleCI:

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

platform :ios do
  desc "Run tests"
  lane :test do
    scan(
      scheme: "MyApp",
      device: "iPhone 16 Pro",
      derived_data_path: "~/DerivedData/MyApp",
      result_bundle: true,
      output_directory: "./test_output"
    )
  end

  desc "Build and push to TestFlight"
  lane :beta do
    match(type: "appstore", readonly: true)
    increment_build_number(
      build_number: ENV["CIRCLE_BUILD_NUM"]
    )
    gym(
      scheme: "MyApp",
      export_method: "app-store",
      derived_data_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

9. Confronto delle prestazioni

Ecco un confronto dettagliato di prestazioni e costi tra le risorse macOS cloud di CircleCI e un Mac Mini M4 self-hosted di MyRemoteMac:

Benchmark dei tempi di build

Scenario CircleCI Cloud macOS Mac Mini M4 self-hosted Miglioramento
Clean build (app media) 14 min 5 min 2,8 volte più veloce
Build incrementale 14 min (senza cache) 1,5 min 9,3 volte più veloce
Risoluzione delle dipendenze SPM 3-5 min (download ogni volta) 5 sec (in cache su disco) ~60 volte più veloce
Suite di unit test (500 test) 8 min 2,5 min 3,2 volte più veloce
Tempo di attesa in coda 30s - 5 min 0 sec Istantaneo

Analisi dei costi mensili

Dimensione del team Build/mese Costo CircleCI Cloud Costo MyRemoteMac Risparmio mensile
Sviluppatore singolo 100 build (10 min in media) $100/mese $85/mese $25/mese
Team piccolo (5) 500 build (10 min in media) $500/mese $85/mese $425/mese
Team medio (15) 1500 build (10 min in media) $1.500/mese $229/mese (M4 Pro) $1.271/mese
Enterprise (50+) 5000+ build $5.000+/mese $458/mese (2x M4 Pro) $4.542+/mese

In sintesi: per qualsiasi team che esegue più di ~75 build al mese, un Mac Mini M4 self-hosted si ripaga immediatamente. Il risparmio sui costi si amplifica ulteriormente perché le build sono più veloci su hardware dedicato con cache calde, il che significa che ogni build consuma meno minuti in partenza.

10. Risoluzione dei problemi comuni

Il runner si disconnette o appare "Offline"

Il runner agent può perdere la connessione a causa di problemi di rete o di un processo in crash. Il LaunchDaemon dovrebbe riavviarsi automaticamente, ma in caso contrario:

# Check if the process is running
ps aux | grep circleci-runner

# Check the LaunchDaemon status
sudo launchctl list | grep circleci

# View the error logs
tail -50 /opt/circleci/logs/runner-stderr.log
tail -50 /opt/circleci/logs/runner.log

# Restart the service
sudo launchctl unload /Library/LaunchDaemons/com.circleci.runner.plist
sudo launchctl load /Library/LaunchDaemons/com.circleci.runner.plist

# If the token expired, generate a new one in CircleCI dashboard
# and update /opt/circleci/config/runner-agent-config.yaml

resource_class non trovata o job bloccati in coda

Se i job restano in coda con "No matching runner found", la resource class nella tua configurazione non corrisponde a quella della dashboard:

# Verify the exact resource class name in CircleCI dashboard:
# Organization Settings > Self-Hosted Runners > 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'

Errori di code signing di Xcode

Il code signing su una macchina CI richiede un'attenta gestione del keychain. Il processo del runner potrebbe non avere accesso al keychain di login:

# 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
      security list-keychain -d user -s /tmp/ci.keychain

      # Install provisioning profile
      mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
      echo "$PROVISIONING_PROFILE_BASE64" | base64 --decode \
        > ~/Library/MobileDevice/Provisioning\ Profiles/profile.mobileprovision

Il simulatore non si avvia o va in timeout

I simulatori possono entrare in uno stato errato sulle macchine CI a lunga esecuzione. Resettali tra una build e l'altra:

# 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

Spazio su disco in esaurimento

Le build di Xcode generano quantità significative di dati. Configura una pulizia automatica sul tuo runner:

# Check available disk space
df -h /

# Clean old DerivedData
rm -rf ~/Library/Developer/Xcode/DerivedData/*

# Remove old simulator runtimes
xcrun simctl runtime delete all

# Clean Homebrew cache
brew cleanup --prune=7

# Remove old CircleCI working directories
find /opt/circleci/workdir -maxdepth 1 -mtime +3 -exec rm -rf {} +

# Set up a weekly cron job for automatic cleanup
(crontab -l 2>/dev/null; echo "0 4 * * 0 rm -rf ~/Library/Developer/Xcode/DerivedData/* && brew cleanup --prune=7") | crontab -

11. Domande frequenti

Quanto costa un runner self-hosted CircleCI su Mac Mini M4?

Un Mac Mini M4 dedicato di MyRemoteMac parte da $85/mese con minuti di build illimitati. È notevolmente più economico dei runner macOS cloud di CircleCI, che costano circa $0,06-$0,12 al minuto (all'incirca $300-500/mese per team attivi). I runner self-hosted non hanno costi al minuto, quindi i tuoi costi sono prevedibili indipendentemente dal volume di build.

Posso usare un runner self-hosted CircleCI per build iOS e macOS?

Sì. Un runner self-hosted su un Mac Mini M4 può eseguire qualsiasi carico di lavoro macOS, incluse build iOS, build di app macOS, test di pacchetti Swift, test UI Xcode e automazione Fastlane. Poiché gira nativamente su Apple Silicon, le build sono più veloci rispetto ai runner cloud emulati o basati su Intel.

Qual è la differenza tra machine runner e container runner di CircleCI?

Il machine runner di CircleCI esegue i job direttamente sul sistema operativo della macchina host, cosa necessaria per le build macOS/iOS che richiedono Xcode, simulatori e framework Apple. Il container runner esegue i job all'interno di container Docker ed è disponibile solo su Linux. Per le build Mac devi usare il machine runner.

Come mantengo aggiornato il mio runner self-hosted CircleCI?

Il machine runner agent di CircleCI supporta gli aggiornamenti automatici per impostazione predefinita. Puoi anche aggiornare manualmente scaricando l'ultima release da CircleCI e sostituendo il binario. Si consiglia di verificare la presenza di aggiornamenti mensilmente e di mantenere aggiornati anche Xcode e macOS.

Un runner self-hosted è più veloce del macOS cloud di CircleCI?

Sì, tipicamente 2-3 volte più veloce per le clean build e fino a 9 volte più veloce per le build incrementali. I runner macOS cloud di CircleCI usano hardware Intel o M1 condiviso con ambienti effimeri, il che significa che ogni build parte con una cache fredda. Un Mac Mini M4 self-hosted offre prestazioni Apple Silicon dedicate, cache DerivedData e SPM persistenti e nessun tempo di attesa in coda.

Posso eseguire più job CircleCI contemporaneamente su un Mac Mini?

Sì. Il Mac Mini M4 ha una CPU a 10 core e 16 GB o più di RAM, che possono gestire comodamente 2-3 job di build simultanei. Per carichi di lavoro più pesanti, il Mac Mini M4 Pro con 14 core e 24 GB di RAM può gestire 4-6 job simultanei. Puoi configurare il numero massimo di task simultanei del runner nel file di configurazione del runner.

Inizia con un Mac Mini M4 per le tue pipeline CircleCI

Distribuisci un Mac Mini M4 dedicato come tuo runner self-hosted CircleCI. Minuti di build illimitati a partire da $85/mese.

Cerchi maggiori dettagli?

Consulta la documentazione completa per guide passo passo, riferimenti di configurazione e risoluzione dei problemi.

Apri la documentazione →