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.
ssh-keygen -t ed25519 -f ~/.ssh/kvmflux_ci -C "ci-runner"
ssh-copy-id -i ~/.ssh/kvmflux_ci.pub admin@<YOUR_MAC_HOST>
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é.
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.
/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.
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.
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.
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 :
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.
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/ddvers un chemin fixe ; les builds incrémentaux passent souvent de plusieurs minutes à quelques secondes. - Paquets Swift — définissez
-clonedSourcePackagesDirPath ~/ci-cache/spmpour 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 :
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é
- SSH par clé uniquement, veille désactivée, VNC conservé en filet de sécurité.
- Xcode installé via
xcodes, licence acceptée, runtimes téléchargés en avance. - Runner enregistré comme service
launchdavec des labels significatifs. - Trousseau CI dédié avec la liste de partitions correctement configurée.
- 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.
Matériel dédié, facturé en dollars, annulable à tout moment.