Guide - CI/CD

Comment configurer un runner CircleCI auto-hébergé sur Mac Mini M4

Guide complet étape par étape pour installer et configurer un machine runner CircleCI auto-hébergé sur un Mac Mini M4 dédié. Performances Apple Silicon natives, cache persistant et jusqu'à 80 % moins cher que les ressources macOS cloud de CircleCI.

35 min de lecture Mis à jour en février 2025

1. Pourquoi utiliser un runner CircleCI auto-hébergé sur Mac ?

CircleCI propose des environnements d'exécution macOS dans le cloud, mais ils sont accompagnés de coûts et de limitations significatifs. Les ressources macOS sur CircleCI utilisent un système basé sur les crédits où chaque minute sur un exécuteur macOS consomme 50 à 100 crédits selon la classe de ressource. Pour les équipes effectuant des builds iOS fréquents, cela peut rapidement atteindre 300 à 500 $ par mois ou plus.

Un runner auto-hébergé sur un Mac Mini M4 dédié de MyRemoteMac élimine entièrement la facturation à la minute. Vous obtenez une machine Apple Silicon dédiée avec un stockage persistant, des caches préchauffés et un accès root complet pour un tarif mensuel fixe à partir de 75 $/mois. Voici une comparaison détaillée :

Caractéristique CircleCI Cloud macOS My Remote Mac auto-hébergé
Modèle tarifaire 50-100 crédits/min (~0,06-0,12 $/min) 75 $/mois forfaitaire (minutes illimitées)
Architecture Intel x86 ou M1 (partagé) Apple M4 (dédié, dernière génération)
Vitesse de build ~14 min (projet iOS moyen) ~5 min (même projet)
Persistance du cache Éphémère (à restaurer à chaque job) Persistant sur disque (instantané)
Temps d'attente en file 30 s - 5 min (variable selon l'offre) 0 s (matériel dédié)
Confidentialité / Contrôle des données Infrastructure partagée Machine dédiée, contrôle total
Logiciels personnalisés Image pré-installée uniquement Accès root complet, tout logiciel

Avantage clé : Avec un runner auto-hébergé persistant, DerivedData, les caches Swift Package Manager et CocoaPods sont préservés entre les builds. Cela seul peut réduire les temps de build de 50 à 70 % par rapport aux environnements macOS cloud éphémères de CircleCI qui repartent de zéro à chaque fois. Combiné aux performances supérieures du M4 en mono-thread, vos builds iOS seront considérablement plus rapides.

2. Prérequis

Avant de commencer, assurez-vous de disposer des éléments suivants :

  • Un serveur Mac Mini M4 chez My Remote Mac (à partir de 75 $/mois)
  • Un compte CircleCI avec une offre Performance, Scale ou Server (les runners auto-hébergés nécessitent une offre payante)
  • Un accès SSH à votre Mac Mini (fourni avec votre abonnement My Remote Mac)
  • Un compte Apple Developer (pour la signature de code et les profils de provisionnement)
  • Une connaissance de base de YAML, de la configuration CircleCI et des commandes terminal

3. Étape 1 : Se connecter en SSH à votre Mac Mini et installer les dépendances

Commencez par vous connecter à votre Mac Mini M4 via SSH. Vous aurez reçu vos identifiants lors de la mise en place de votre serveur My Remote Mac. Nous devons installer Xcode et les outils nécessaires aux builds iOS avant de configurer le runner CircleCI.

Connexion 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

Installer Homebrew et les outils en ligne de commande Xcode

# 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

Installer Xcode (version complète)

Pour les builds iOS, vous avez besoin de l'application Xcode complète. Le moyen le plus rapide de l'installer sur un serveur sans écran est d'utiliser 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

Installer les simulateurs iOS et les outils de 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. Étape 2 : Installer l'agent runner CircleCI

CircleCI utilise un agent machine runner pour connecter votre Mac Mini à la plateforme CircleCI. Le machine runner reçoit les jobs de CircleCI et les exécute directement sur votre hôte macOS. C'est différent du container runner (qui ne fonctionne que sous Linux).

Créer un utilisateur dédié pour le runner

Il est recommandé de créer un utilisateur dédié pour exécuter l'agent CircleCI afin d'assurer l'isolation de sécurité :

# 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)

Télécharger et installer l'agent runner

# 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

Configurer l'agent runner

Créez le fichier de configuration du runner. Vous aurez besoin de votre jeton d'authentification du runner depuis le tableau de bord CircleCI (traité à l'étape 3). Pour l'instant, créez la structure du fichier de configuration :

# 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

Créer un Launch Agent macOS pour la persistance

Pour vous assurer que le runner démarre automatiquement au démarrage et redémarre en cas de plantage, créez 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

Important : L'agent runner ne se connectera pas tant que vous n'aurez pas ajouté un jeton d'authentification valide. Complétez d'abord l'étape 3 pour générer le jeton, puis mettez à jour le fichier runner-agent-config.yaml avec le vrai jeton et redémarrez le service.

5. Étape 3 : Configurer le runner dans le tableau de bord CircleCI

Vous devez maintenant enregistrer votre runner dans l'interface web CircleCI et générer un jeton d'authentification. Cela connecte votre Mac Mini à votre organisation CircleCI.

Créer une classe de ressource

Dans CircleCI, les runners auto-hébergés sont organisés par classes de ressources. Une classe de ressource est un label qui associe votre .circleci/config.yml à un ensemble spécifique de runners.

  1. Allez dans Tableau de bord CircleCIParamètres de l'organisationRunners auto-hébergés
  2. Cliquez sur "Créer une classe de ressource"
  3. Définissez le Namespace avec le nom de votre organisation (ex. : your-org)
  4. Définissez le nom de la classe de ressource avec un nom descriptif (ex. : mac-runner)
  5. Cela crée un identifiant de classe de ressource : your-org/mac-runner

Générer un jeton d'authentification du runner

  1. Après avoir créé la classe de ressource, cliquez sur "Créer un nouveau jeton"
  2. Donnez au jeton un nom descriptif (ex. : mac-mini-m4-token)
  3. Copiez immédiatement le jeton généré — il ne sera affiché qu'une seule fois

Mettre à jour la configuration du runner avec votre jeton

# 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"

Une fois connecté, le runner devrait apparaître comme "En ligne" dans le tableau de bord CircleCI sous Runners auto-hébergés. S'il n'apparaît pas dans les 60 secondes, vérifiez le fichier journal pour les messages d'erreur.

Utiliser le CLI CircleCI (alternative)

Vous pouvez également gérer les runners via le CLI 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. Étape 4 : Créer votre .circleci/config.yml pour les builds iOS

Créez un fichier .circleci/config.yml à la racine de votre dépôt. La différence clé avec une configuration CircleCI standard est l'utilisation de machine: true avec votre resource_class personnalisée pour cibler votre runner auto-hébergé.

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

Remarque : La valeur resource_class: your-org/mac-runner doit correspondre exactement à la classe de ressource que vous avez créée dans le tableau de bord CircleCI. Si elle ne correspond pas, les jobs resteront en file d'attente indéfiniment.

7. Étape 5 : Optimiser avec le cache et le parallélisme

L'un des plus grands avantages d'un runner auto-hébergé est le cache persistant. Comme le système de fichiers du runner est persistant, vous n'avez pas besoin de télécharger et restaurer les caches comme avec les ressources cloud CircleCI. Cependant, il existe des optimisations supplémentaires pour maximiser la vitesse de vos builds.

Exploiter le DerivedData persistant

Puisque le disque du runner persiste entre les builds, DerivedData est déjà mis en cache automatiquement. Utilisez un chemin cohérent :

# 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 {} +

Persistance de l'espace de travail entre les jobs

Utilisez les espaces de travail CircleCI pour transmettre des artefacts entre les jobs d'un même 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

Exécution parallèle des tests

- 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

Répartition des tests CircleCI

Pour les suites de tests volumineuses, utilisez la répartition de tests intégrée de CircleCI pour distribuer les tests sur des runners parallèles :

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. Exemples de workflows

Voici des exemples de workflows complets, prêts pour la production, pour les scénarios CI/CD iOS courants.

Pipeline complet de build, test et déploiement 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

Exemple d'intégration Fastlane

Si vous utilisez Fastlane pour votre automatisation de build, voici comment l'intégrer avec votre runner CircleCI auto-hébergé :

# 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. Comparaison des performances

Voici une comparaison détaillée des performances et des coûts entre les ressources macOS cloud de CircleCI et un Mac Mini M4 auto-hébergé de My Remote Mac :

Benchmarks des temps de build

Scénario CircleCI Cloud macOS Mac Mini M4 auto-hébergé Amélioration
Build propre (app moyenne) 14 min 5 min 2,8x plus rapide
Build incrémental 14 min (pas de cache) 1,5 min 9,3x plus rapide
Résolution des dépendances SPM 3-5 min (téléchargement à chaque fois) 5 sec (cache sur disque) ~60x plus rapide
Suite de tests unitaires (500 tests) 8 min 2,5 min 3,2x plus rapide
Temps d'attente en file 30 s - 5 min 0 sec Instantané

Analyse des coûts mensuels

Taille de l'équipe Builds/mois Coût CircleCI Cloud Coût My Remote Mac Économies mensuelles
Développeur solo 100 builds (10 min moy.) 100 $/mois 75 $/mois 25 $/mois
Petite équipe (5) 500 builds (10 min moy.) 500 $/mois 75 $/mois 425 $/mois
Équipe moyenne (15) 1500 builds (10 min moy.) 1 500 $/mois 179 $/mois (M4 Pro) 1 321 $/mois
Entreprise (50+) 5000+ builds 5 000+ $/mois 358 $/mois (2x M4 Pro) 4 642+ $/mois

En résumé : Pour toute équipe effectuant plus de ~75 builds par mois, un Mac Mini M4 auto-hébergé est immédiatement rentable. Les économies se cumulent davantage car les builds sont plus rapides sur du matériel dédié avec des caches préchauffés, ce qui signifie que chaque build consomme moins de minutes en premier lieu.

10. Résolution des problèmes courants

Le runner se déconnecte ou apparaît "Hors ligne"

L'agent runner peut perdre la connexion en raison de problèmes réseau ou d'un processus planté. Le LaunchDaemon devrait redémarrer automatiquement, mais si ce n'est pas le cas :

# 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 introuvable ou jobs bloqués en file d'attente

Si les jobs restent en file d'attente avec "Aucun runner correspondant trouvé", la classe de ressource dans votre configuration ne correspond pas au tableau de bord :

# 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'

Erreurs de signature de code Xcode

La signature de code sur une machine CI nécessite une gestion soigneuse du trousseau. Le processus runner peut ne pas avoir accès au trousseau de session :

# 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

Le simulateur ne démarre pas ou expire

Les simulateurs peuvent se retrouver dans un état incorrect sur les machines CI à longue durée de fonctionnement. Réinitialisez-les entre les builds :

# 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

Espace disque insuffisant

Les builds Xcode génèrent des quantités importantes de données. Configurez un nettoyage automatique sur votre 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. Questions fréquentes

Combien coûte un runner CircleCI auto-hébergé sur Mac Mini M4 ?

Un Mac Mini M4 dédié chez My Remote Mac commence à 75 $/mois avec des minutes de build illimitées. C'est nettement moins cher que les runners macOS cloud de CircleCI qui coûtent environ 0,06 à 0,12 $ par minute (environ 300 à 500 $/mois pour les équipes actives). Les runners auto-hébergés n'ont aucun frais à la minute, donc vos coûts sont prévisibles quel que soit le volume de builds.

Puis-je utiliser un runner CircleCI auto-hébergé pour les builds iOS et macOS ?

Oui. Un runner auto-hébergé sur un Mac Mini M4 peut exécuter n'importe quelle charge de travail macOS, y compris les builds iOS, les builds d'applications macOS, les tests de paquets Swift, les tests UI Xcode et l'automatisation Fastlane. Comme il s'exécute nativement sur Apple Silicon, les builds sont plus rapides que sur des runners cloud émulés ou basés sur Intel.

Quelle est la différence entre le machine runner et le container runner de CircleCI ?

Le machine runner de CircleCI exécute les jobs directement sur le système d'exploitation de la machine hôte, ce qui est nécessaire pour les builds macOS/iOS qui ont besoin de Xcode, des simulateurs et des frameworks Apple. Le container runner exécute les jobs dans des conteneurs Docker et n'est disponible que sur Linux. Pour les builds Mac, vous devez utiliser le machine runner.

Comment maintenir mon runner CircleCI auto-hébergé à jour ?

L'agent machine runner CircleCI prend en charge les mises à jour automatiques par défaut. Vous pouvez également mettre à jour manuellement en téléchargeant la dernière version depuis CircleCI et en remplaçant le binaire. Il est recommandé de vérifier les mises à jour mensuellement et de maintenir Xcode et macOS à jour également.

Un runner auto-hébergé est-il plus rapide que les runners macOS cloud de CircleCI ?

Oui, généralement 2 à 3 fois plus rapide pour les builds propres et jusqu'à 9 fois plus rapide pour les builds incrémentaux. Les runners macOS cloud de CircleCI utilisent du matériel Intel ou M1 partagé avec des environnements éphémères, ce qui signifie que chaque build démarre avec un cache vide. Un Mac Mini M4 auto-hébergé offre des performances Apple Silicon dédiées, des caches DerivedData et SPM persistants, et aucun temps d'attente en file d'attente.

Puis-je exécuter plusieurs jobs CircleCI simultanément sur un seul Mac Mini ?

Oui. Le Mac Mini M4 dispose d'un CPU 10 cœurs et de 16 Go de RAM ou plus, ce qui permet de gérer confortablement 2 à 3 jobs de build simultanés. Pour des charges de travail plus lourdes, le Mac Mini M4 Pro avec 14 cœurs et 24 Go de RAM peut gérer 4 à 6 jobs simultanés. Vous pouvez configurer le nombre maximum de tâches simultanées du runner dans le fichier de configuration du runner.

Démarrez avec un Mac Mini M4 pour vos pipelines CircleCI

Déployez un Mac Mini M4 dédié comme runner CircleCI auto-hébergé. Minutes de build illimitées à partir de 75 $/mois avec un essai gratuit de 7 jours.