Votre point de départ

En louant un Mac mini M4 dédié chez KVMFLUX, vous obtenez un accès équivalent à root sur du vrai matériel Apple : 16 Go de mémoire unifiée, 256 Go de SSD, macOS préinstallé, accessible en SSH et en VNC. Aucun partage, aucune virtualisation, donc xcodebuild voit le M4 complet et la Secure Enclave se comporte exactement comme sur la machine posée sur votre bureau.

Choisissez la région la plus proche du stockage de vos livrables, pas de votre équipe. Un runner communique avec l'hébergement Git et le CDN bien plus souvent qu'un humain ne le manipule réellement — couverture àSingapour, au Japon, en Corée du Sud, à Hong Kong, sur la côte est et la côte ouest des États-Unis.

Étape 1 — Verrouillez SSH avant tout le reste

La machine sort d'usine avec l'authentification par mot de passe activée, pour faciliter votre premier accès. Cette première session doit y mettre fin : poussez d'abord une clé, puis désactivez le mot de passe.

Terminal local
ssh-keygen -t ed25519 -f ~/.ssh/kvmflux_ci -C "ci-runner"
ssh-copy-id -i ~/.ssh/kvmflux_ci.pub admin@<YOUR_MAC_HOST>
Sur le Mac
sudo tee -a /etc/ssh/sshd_config <<'EOF'
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
EOF
sudo launchctl kickstart -k system/com.openssh.sshd

Deux réglages supplémentaires comptent pour un nœud CI : empêcher la machine de se mettre en veille, et éviter que les démons en arrière-plan ne se suspendent quand aucun écran n'est branché.

Sur le Mac
sudo pmset -a sleep 0 displaysleep 0 disksleep 0
sudo systemsetup -setrestartfreeze on

Gardez VNC comme filet de sécurité. Certaines fenêtres de Xcode — l'acceptation de licence, les autorisations au premier lancement du simulateur — n'apparaissent que dans l'interface graphique ; il vous faut un chemin d'accès qui fonctionne même si la configuration SSH pose problème.

Étape 2 — Installez la chaîne d'outils Xcode

Sautez l'App Store. xcodes permet d'installer une version précise de Xcode de manière non interactive, exactement ce qu'il faut pour un nœud sans écran. Installez d'abord Homebrew, puis la chaîne d'outils.

Sur le Mac
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install xcodesorg/made/xcodes aria2
xcodes install 16.2 --experimental-unxip
sudo xcodes select 16.2
sudo xcodebuild -license accept
sudo xcodebuild -runFirstLaunch

Confirmez les plateformes cibles réellement utilisées. Si le pipeline exécute des tests sur simulateur, téléchargez les runtimes dès maintenant, pas au moment de la première tâche.

Sur le Mac
xcodebuild -downloadPlatform iOS
xcrun simctl list runtimes
xcodebuild -version

Ajoutez les outils courants des pipelines mobiles : fastlane pour les lanes et la signature, et git-lfs si le dépôt contient des assets binaires.

Sur le Mac
brew install fastlane git-lfs jq
git lfs install --system

Étape 3 — Enregistrez la machine comme runner

GitHub Actions, GitLab et Buildkite suivent tous le même modèle : télécharger un agent, lui fournir un jeton limité, l'exécuter comme service. Voici la procédure pour GitHub Actions sur Apple Silicon.

Sur le Mac
mkdir ~/actions-runner && cd ~/actions-runner
curl -o runner.tar.gz -L \
  https://github.com/actions/runner/releases/download/v2.321.0/actions-runner-osx-arm64-2.321.0.tar.gz
tar xzf runner.tar.gz
./config.sh --url https://github.com/your-org/your-app \
  --token <REGISTRATION_TOKEN> \
  --labels macos,arm64,m4 --unattended
./svc.sh install && ./svc.sh start

Installer via svc.sh connecte le runner à launchd, ce qui lui permet de survivre à un redémarrage même sans session de bureau connectée. Ciblez-le avec des labels :

.github/workflows/ios.yml
jobs:
  build:
    runs-on: [self-hosted, macos, m4]
    steps:
      - uses: actions/checkout@v4
      - run: xcodebuild -scheme App -destination \
          'platform=iOS Simulator,name=iPhone 16' test

Le jeton d'enregistrement expire après une heure et n'est utilisable qu'une fois — c'est normal. Les identifiants durables du runner sont conservés dans le fichier .credentials du répertoire du runner, donc gardez ce compte utilisateur « ennuyeux » : pas de clé SSH personnelle, pas de session de navigateur laissée ouverte.

Étape 4 — Donnez au CI un trousseau qu'il peut déverrouiller lui-même

La signature est l'endroit où la plupart des configurations Mac auto-hébergées coincent. La solution est un trousseau dédié, créé, déverrouillé et jeté par votre lane — ainsi le trousseau de connexion n'affiche jamais de fenêtre et ne fuite rien entre les tâches.

Lane de signature
KEYCHAIN=ci.keychain-db
security create-keychain -p "$KEYCHAIN_PASS" $KEYCHAIN
security set-keychain-settings -lut 3600 $KEYCHAIN
security unlock-keychain -p "$KEYCHAIN_PASS" $KEYCHAIN
security import dist.p12 -k $KEYCHAIN -P "$P12_PASS" \
  -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple: \
  -s -k "$KEYCHAIN_PASS" $KEYCHAIN
security list-keychains -d user -s $KEYCHAIN login.keychain-db

La ligne set-key-partition-list est celle que tout le monde oublie — sans elle, codesign reste bloqué en attendant une fenêtre de mot de passe graphique qui n'apparaîtra jamais. Avec fastlane, match associé à un dépôt de certificats privé automatise entièrement ce processus.

Cache : conserver ce qui a déjà été construit

La véritable raison pour laquelle une machine dédiée bat un runner éphémère, c'est que l'état peut persister. Exploitez cela au maximum, sans retélécharger la moitié d'internet à chaque tâche :

  • DerivedData — pointez -derivedDataPath ~/ci-cache/dd vers un chemin fixe ; les builds incrémentaux passent souvent de plusieurs minutes à quelques secondes.
  • Paquets Swift — définissez -clonedSourcePackagesDirPath ~/ci-cache/spm pour que la résolution des dépendances réutilise les checkouts existants entre les tâches.
  • CocoaPods et Homebrew — les deux mettent déjà en cache dans le répertoire utilisateur du runner par défaut ; évitez simplement de nettoyer l'espace de travail entre les builds.

Estimez honnêtement l'usage disque. Sur un SSD de 256 Go, Xcode et les runtimes occupent environ 40 Go, et le cache d'un projet actif grimpe progressivement à 60-80 Go. Nettoyez sur un calendrier, pas en réaction à un problème :

Tâche planifiée hebdomadaire
find ~/ci-cache/dd -maxdepth 1 -mtime +14 -exec rm -rf {} +
xcrun simctl delete unavailable
df -h /

Si le projet embarque des assets volumineux ou doit faire coexister plusieurs versions de Xcode, l'option SSD supplémentaire +1 To ne coûte que $11.7/mois — bien moins cher que de déboguer un disque plein juste avant une publication.

Concurrence : combien de tâches un M4 peut-il absorber ?

Un M4 avec 16 Go de mémoire gère très bien une tâche lourde à la fois : un build propre complet avec la suite de tests sur simulateur peut solliciter tous les cœurs. Faire tourner deux tâches basées sur simulateur en parallèle fonctionne pour une petite application, mais les deux ralentissent une fois la pression mémoire installée.

Après plusieurs mois à surveiller des pipelines, voici notre règle empirique :

  • Pour des charges de build-plus-tests, un processus runner exécutant une tâche à la fois reste le réglage par défaut le plus fiable.
  • Séparez lint, tests unitaires et tests d'interface en tâches distinctes seulement après avoir ajouté une deuxième machine — les mettre en file sur la même machine n'ajoute que de la latence.
  • Les tâches nocturnes représentent de la puissance de calcul gratuite : programmez les audits de dépendances et les campagnes de captures d'écran pendant les heures creuses du fuseau horaire de la région.

Quand le temps d'attente devient le goulot d'étranglement, ajouter un nœud loué permet une montée en charge linéaire — enregistrez-le avec les mêmes labels et l'ordonnanceur répartira automatiquement la charge. Le calcul entre nœud journalier ou mensuel est traité séparément dans notre analyse des coûts de location ; les flux de travail associés apparaissent aussi dans notre aperçu des cas d'usage.

La configuration complète, en condensé

  1. SSH par clé uniquement, veille désactivée, VNC conservé en filet de sécurité.
  2. Xcode installé via xcodes, licence acceptée, runtimes téléchargés en avance.
  3. Runner enregistré comme service launchd avec des labels significatifs.
  4. Trousseau CI dédié avec la liste de partitions correctement configurée.
  5. Cache persistant associé à un nettoyage planifié.

L'ensemble se met en place en moins d'une heure de manipulation, pour aboutir à un nœud de build dont l'équipe n'a plus à se soucier — c'est exactement le but recherché.

Testez-le sur du vrai matériel

Chaque commande ci-dessus a été écrite et validée sur une machine que nous louons réellement. Louez-en une, suivez le guide, annulez si ça ne convient pas — dans tous les cas, aucune facture matérielle en jeu.

Mac Mini M4 · 16GB / 256GB
Jour$19.3 /jour
Semaine$52.2 /sem.
Mois$96.7 /mois
Trimestre$263 /trim.

Matériel dédié, facturé en dollars, annulable à tout moment.