De la connexion au premier artefact

Votre première heure
sur Mac cloud

Consacrez la première demi-heure à la connexion, à la vérification des outils et au premier build. Utilisez la seconde pour préparer les certificats et le pipeline. Vous disposez d’un Mac physique dédié, pas d’une machine virtuelle : conservez vos habitudes de travail sous macOS, avec l’interface graphique et le terminal.

Vous avez déjà commandé ? Consultez la console pour obtenir l’adresse de l’hôte, le port, le nom d’utilisateur et les informations de connexion qui vous ont été fournis. Les variables d’exemple ne sont pas des identifiants de connexion.

00–10 min

Vérifiez l’empreinte de l’hôte et établissez la connexion SSH.

10–20 min

Vérifiez Xcode, les dépendances du projet et l’espace disque.

20–30 min

Commencez par les vérifications sans signature, puis testez l’archive.

Étape 1 · Vérifier la connexion

SSH pour le terminal, Partage d’écran pour l’interface

Générez d’abord une clé sur votre machine et ne téléversez que la clé publique. Gardez la clé privée sur votre appareil et protégez-la par une phrase secrète. Pour l’hôte, le port et le nom d’utilisateur, utilisez les informations réellement fournies dans la console.

À exécuter dans le terminal macOS local
read -r -p "Adresse de l’hôte: " MAC_HOST
read -r -p "Port SSH: " MAC_PORT
read -r -p "Nom d’utilisateur: " MAC_USER
ssh-keygen -t ed25519 -f "$HOME/.ssh/osxhost_build"
cat "$HOME/.ssh/osxhost_build.pub"
ssh -p "$MAC_PORT" "$MAC_USER@$MAC_HOST"

Le fichier de clé publique se termine par .pub . Après vous être connecté une première fois avec le mode de connexion fourni, ajoutez la clé publique au fichier distant ~/.ssh/authorized_keyspuis vérifiez l’authentification par clé depuis un autre terminal local.

Ajouter la clé publique à distance et changer le mot de passe

Sur l’hôte distant, créez ~/.sshet définissez les permissions du répertoire sur 700et celles du fichier de clé publique sur 600. Ajoutez la clé publique avec un éditeur, sans supprimer les autorisations existantes. Exécutez ensuite passwd pour modifier le mot de passe de l’utilisateur actuel.

Ouvrez un autre terminal et utilisez ssh -i ~/.ssh/osxhost_build -p "$MAC_PORT" "$MAC_USER@$MAC_HOST" pour vérifier que la connexion fonctionne, puis fermez la session initiale. Ne fermez pas la seule connexion encore opérationnelle.

Vérification : connexion à une nouvelle session par clé

Utiliser Partage d’écran via un tunnel chiffré

Lancez la commande de tunnel ci-dessous sur votre machine locale et laissez le terminal ouvert. Sous macOS, ouvrez Partage d’écran et connectez-vous à vnc://127.0.0.1:5901. Sous Windows et Linux, utilisez un client compatible avec le mode d’authentification VNC configuré et connectez-vous au port local 5901.

Partage d’écran doit être activé à distance et autorisé pour l’utilisateur concerné. Les identifiants de session graphique et la clé privée SSH sont deux moyens d’authentification distincts. N’exposez pas le port VNC à toutes les sources.

Vérification : le bureau macOS s’affiche et peut être contrôlé
Tunnel SSH local · destination : adresse de boucle locale distante
ssh -N -L 5901:127.0.0.1:5900 \
  -i "$HOME/.ssh/osxhost_build" \
  -p "$MAC_PORT" "$MAC_USER@$MAC_HOST"

Étape 2 · Mac local → Mac cloud

Trois volets de migration, sans recopier tout l’ancien environnement

Validez d’abord les données et les outils, puis enregistrez l’exécuteur CI. Vérifiez séparément la connexion et les builds sans intervention : une configuration interactive locale ne suffit pas pour un pipeline.

Volet 01 · Données

Migrez le projet, pas les secrets en clair

  • Exportez depuis le trousseau les certificats de signature et les clés privées nécessaires dans un fichier chiffré .p12. Transmettez son mot de passe par un canal sécurisé distinct.
  • Migrez uniquement les profils de provisioning nécessaires au projet et vérifiez l’équipe, l’identifiant de l’app et la date d’expiration.
  • Ne copiez pas tout le trousseau de connexion. Créez un trousseau dédié aux builds, importez uniquement les éléments nécessaires et autorisez les outils de signature.
  • Synchronisez le code source et les ressources nécessaires, sans les répertoires de dépendances, DerivedData ni les anciens artefacts de build.

Critères de validation : même version du projet, certificat avec clé privée, aucun fichier sensible dans Git.

Volet 02 · Outils

Verrouillez les versions avant d’installer les dépendances

  • Utilisez xcodes list pour afficher les versions, puis installez la version de Xcode requise après avoir obtenu les autorisations nécessaires.
  • Utilisez xcode-select pour sélectionner explicitement la chaîne d’outils active, sans vous fier au dernier choix effectué dans l’interface graphique.
  • Vérifiez Homebrew et la chaîne d’outils arm64 ; ne recopiez pas directement les répertoires de dépendances d’un environnement Intel.
  • Fixez les versions de Ruby, CocoaPods et fastlane avec un gestionnaire de versions Ruby et un Gemfile.

Critères de validation : mêmes versions de Xcode, Ruby et Bundler dans le terminal et dans la CI.

Volet 03 · Intégration CI

N’autorisez que les tâches de confiance sur l’exécuteur

  • GitHub Actions : enregistrez un runner auto-hébergé au niveau du dépôt et sélectionnez le paquet macOS ARM64.
  • GitLab Runner : enregistrez un exécuteur au niveau du projet, choisissez le mode shell selon vos besoins et limitez son périmètre au projet.
  • Jenkins : créez un agent macOS avec un répertoire de travail isolé et une injection contrôlée des identifiants.
  • Commencez par un seul job en parallèle pour valider la signature, puis augmentez la concurrence en fonction de la mémoire utilisée au pic.

Critère de validation : une modification de confiance déclenche un build et les journaux comme les artefacts peuvent être récupérés.

Synchroniser le projet en local · conserver les fichiers distants existants
rsync -avz \
  --exclude='.git/' \
  --exclude='build/' \
  --exclude='DerivedData/' \
  --exclude='Pods/' \
  --exclude='node_modules/' \
  -e "ssh -p $MAC_PORT -i $HOME/.ssh/osxhost_build" \
  ./ "$MAC_USER@$MAC_HOST:~/build-workspace/"

Cette commande de synchronisation ne supprime aucun fichier distant. Pour un pipeline de production, récupérez de préférence un commit précis depuis le dépôt. La clé de cache doit au minimum inclure la version des outils, les fichiers de verrouillage des dépendances et l’architecture cible. N’autorisez pas les demandes de fusion externes non fiables à accéder aux identifiants de signature.

Étape 3 · Valider séparément la signature et les artefacts

Un Fastfile pour orchestrer match, gym et pilot

À la racine du projet, exécutez bundle installet validez Gemfile.lock. Le processus ci-dessous suppose que le dépôt de signature est initialisé, que l’app existe et que la CI injecte les variables d’environnement de manière sécurisée. Il ne crée pas de nouveaux éléments de signature.

Vérifications préalables à distance · contrôler les outils
xcode-select -p
xcodebuild -version
xcodebuild -showsdks
ruby --version
bundle --version
bundle exec fastlane --version
security find-identity -v -p codesigning
df -h "$HOME"

Définissez l’adresse du dépôt de signature dans MATCH_GIT_URLet le mot de passe de déchiffrement dans MATCH_PASSWORD. Pour l’API de téléversement, utilisez une clé d’API côté serveur : le chemin du fichier de clé est indiqué par ASC_KEY_PATH , l’identifiant de la clé et celui de l’émetteur par ASC_KEY_IDetASC_ISSUER_ID . La CI doit stocker le fichier de clé sous forme de secret et le créer à l’exécution. Ne le validez pas dans le dépôt du projet.

Définissez IOS_APP_IDENTIFIER,IOS_TEAM_ID,IOS_WORKSPACE et IOS_SCHEME. Le type de distribution du dépôt de signature doit correspondre à appstore . Vérifiez d’abord le scheme partagé, puis exécutez le pipeline complet.

fastlane/Fastfile · pipeline TestFlight pour une seule app
default_platform(:ios)

platform :ios do
  desc "Archive a signed build and upload it to TestFlight"
  lane :release do
    setup_ci

    api_key = app_store_connect_api_key(
      key_id: ENV.fetch("ASC_KEY_ID"),
      issuer_id: ENV.fetch("ASC_ISSUER_ID"),
      key_filepath: ENV.fetch("ASC_KEY_PATH"),
      in_house: false
    )

    match(
      type: "appstore",
      readonly: true,
      git_url: ENV.fetch("MATCH_GIT_URL"),
      app_identifier: ENV.fetch("IOS_APP_IDENTIFIER"),
      team_id: ENV.fetch("IOS_TEAM_ID"),
      api_key: api_key
    )

    gym(
      workspace: ENV.fetch("IOS_WORKSPACE"),
      scheme: ENV.fetch("IOS_SCHEME"),
      configuration: "Release",
      clean: true,
      export_method: "app-store",
      output_directory: "build/artifacts",
      output_name: "release.ipa"
    )

    pilot(
      api_key: api_key,
      ipa: "build/artifacts/release.ipa",
      skip_waiting_for_build_processing: true
    )
  end
end
Exécution et vérification · variables injectées par la CI
bundle exec fastlane ios release
find build/artifacts -maxdepth 1 -type f -print

Un téléversement réussi ne signifie pas que le traitement est terminé.Cet exemple ne patiente pas après le téléversement. Vérifiez le traitement du build dans le portail de distribution et attribuez un numéro de build unique à chaque téléversement.readonly: true empêche la CI de modifier le dépôt de signature. Si un certificat ou un profil de provisioning expire, mettez-le à jour dans un environnement contrôlé, puis relancez le pipeline.

Projets multiplateformes · conserver les fichiers de verrouillage

Isoler l’étape iOS et prévoir l’invalidation du cache

Les étapes iOS de Flutter et React Native dépendent toutes deux de Xcode, CocoaPods et de la configuration de signature. Commencez par les diagnostics de la plateforme, puis ajoutez l’étape de téléversement. Ne sautez pas la vérification de cohérence des dépendances, même si le cache est utilisé.

Flutter : commencer par le simulateur, puis exporter l’IPA

Fixez la version du SDK Flutter et conservez pubspec.lock. Réutilisez le cache de téléchargements Pub ; utilisez Podfile.lock comme clé pour Pods et la version de Xcode avec la configuration du projet pour DerivedData. Si le cache est vide, les téléchargements et la compilation prendront plus de temps qu’aux exécutions suivantes.

À la racine du projet, exécutez la commande ci-dessous. Une fois la configuration de signature validée,flutter build ipa --release permet d’exporter un build pour appareil réel.

Ne réutilisez pas un cache de build entre versions majeures de Xcode

React Native : verrouiller Node, Ruby et Pods

Validez le fichier de verrouillage du gestionnaire de paquets JavaScript et utilisez la commande d’installation prévue par le projet. L’exemple ci-dessous utilise npm ; gérez les dépendances Ruby avec Bundler pour éviter les conflits entre les gems système et celles du projet.

N’utilisez pod install --repo-updateque si l’ajout d’une dépendance nécessite réellement de mettre à jour l’index. Pour les installations courantes, lancez bundle exec pod installsans supprimer Pods ni les fichiers de verrouillage à chaque fois.

Incluez l’architecture et les fichiers de verrouillage des dépendances dans la clé de cache
À la racine du projet Flutter
flutter --version
flutter doctor -v
flutter pub get
flutter build ios --simulator
flutter build ipa --release
À la racine du projet React Native · projets utilisant npm
node --version
npm ci
bundle install
(cd ios && bundle exec pod install)
xcrun simctl list devices available

Limitez le nombre de tests exécutés en parallèle sur les simulateurs.Récupérez les UDID de deux appareils dans la liste des appareils disponibles et définissez-les dans SIM_UDID_AetSIM_UDID_B. Exécutez les tests ci-dessous dans un projet où IOS_WORKSPACEetIOS_SCHEME sont configurés. Pour la première exécution, utilisez une seule cible, puis passez à deux et surveillez la mémoire utilisée et les écritures disque.

Tests Xcode · deux cibles de simulateur prises en charge par le projet
xcodebuild test \
  -workspace "$IOS_WORKSPACE" \
  -scheme "$IOS_SCHEME" \
  -destination "platform=iOS Simulator,id=$SIM_UDID_A" \
  -destination "platform=iOS Simulator,id=$SIM_UDID_B" \
  -parallel-testing-enabled YES \
  -maximum-concurrent-test-simulator-destinations 2 \
  -resultBundlePath "build/TestResults-$(date +%s).xcresult"

Conteneurs · séparer les services Linux des builds macOS

Les conteneurs peuvent héberger des services associés, mais ne remplacent pas une machine Xcode

Le nœud est un Mac physique dédié. Les conteneurs Linux de Docker Desktop et OrbStack s’exécutent dans un environnement Linux : ne confondez pas le nœud physique avec des conteneurs qui partageraient le noyau macOS.

Tâche Environnement conseillé À prendre en compte
Bases de données de test, cache et API internes Conteneur Linux Privilégiez les images arm64 et limitez la mémoire ainsi que les interfaces d’écoute.
Archive Xcode et tests sur simulateur Système hôte macOS Nécessite le SDK macOS, les outils de signature et le runtime du simulateur.
Services disponibles uniquement en image amd64 Valider la compatibilité au préalable L’émulation peut entraîner un surcoût ; ne vous fiez pas directement aux performances attendues en arm64.
Services associés exécutés en continu À choisir selon les besoins d’isolation des ressources Ils partagent la mémoire physique, le SSD et le réseau avec les builds. Limitez les ressources et conservez des sauvegardes.
Après avoir installé et démarré l’outil de conteneurs choisi, vérifiez
uname -m
docker version
docker info --format '{{.Architecture}}'
docker system df
docker stats --no-stream

Gérez vos conteneurs avec Docker Desktop ou OrbStack, mais évitez d’utiliser les deux sans savoir vers quel environnement Docker pointe le contexte actif. Avant d’ajouter des services, notez la mémoire et l’espace disque disponibles. Ne faites pas de la suppression des données de conteneurs un réflexe de dépannage.

Extension · identifier les appareils avant toute écriture

Déplacez le cache vers un disque externe, sans traiter plusieurs machines comme une seule

L’ajout d’un SSD et l’interconnexion Thunderbolt 5 sont des options distinctes. Le nom réel de l’appareil, le chemin de montage, la prise en charge des interfaces et la topologie de connexion dépendent des informations de votre commande. Ne formatez ni ne partitionnez rien avant d’avoir tout vérifié.

SSD externe : vérifier le point de montage et les permissions

Utilisez diskutil list external pour identifier le périphérique externe, puis consulter les informations du volume concerné. Si le volume est formaté mais pas monté, vérifiez son identifiant puis exécutez diskutil mount "$DISK_IDENTIFIER". Ne déduisez pas qu’il s’agit d’un SSD externe à partir du seul numéro du disque.

Vous pouvez y placer les caches de dépendances, DerivedData et les artefacts temporaires. Indiquez le chemin réel dans la variable CI BUILD_CACHE_ROOT, vérifiez qu’il est accessible en écriture par l’utilisateur de build et que le chemin reste valide après un redémarrage. Conservez des sauvegardes séparées du code source et des éléments de signature.

Une capacité accrue ne remplace pas une sauvegarde

Interconnexion TB5 : vérifier la topologie de chaque machine

L’interconnexion ne fusionne pas automatiquement les processeurs ni la mémoire unifiée de plusieurs machines en une seule réserve accessible à un processus. L’application ou l’ordonnanceur CI doit répartir les tâches ; chaque machine doit disposer de ses propres outils, exécuteur et répertoire de travail.

Si votre configuration utilise une connexion réseau Thunderbolt, vérifiez l’interface réseau, l’adresse et le routage de chaque machine, puis testez la connexion directe. Avant de commander, précisez le nombre de machines, leur modèle et l’usage prévu dans un ticket. Ne supposez pas que tous les modèles disposent des mêmes interfaces.

Les tâches distribuées nécessitent une prise en charge par l’application
Vérifications à distance en lecture seule · aucune modification du disque ou du réseau
diskutil list external
ls -la /Volumes
df -h
system_profiler SPThunderboltDataType
networksetup -listallhardwareports

Les tarifs des quatre durées de location pour les options d’extension sont indiqués sur la page des offres. Pour modifier une commande existante, ouvrez d’abord un ticket afin de confirmer la procédure et la migration des données. Ne modifiez pas la structure du disque pendant un build de production.

Dernière étape · isoler le problème à partir d’éléments concrets

Commencez par recueillir les informations de diagnostic essentielles avant de modifier la configuration

Notez le numéro de commande, le nœud, l’heure de l’incident et son fuseau horaire, ainsi que le commit du dernier build réussi. Conservez la première erreur et le code de sortie, pas seulement la dernière ligne du journal. Les commandes ci-dessous permettent de cerner le problème, mais ne résolvent pas automatiquement toutes les pannes.

01

Impossible de se connecter en SSH

Vérifiez d’abord l’adresse, le port, le nom d’utilisateur et le chemin de la clé privée. En cas de délai d’attente, commencez par vérifier l’accès réseau. En cas d’échec d’authentification, vérifiez le nom d’utilisateur, l’autorisation de la clé publique et les permissions. Si l’empreinte de l’hôte a changé, vérifiez-la par ticket ; ne l’ignorez pas.

Terminal local · la sortie peut contenir des informations sur l’hôte
ssh -vv -o ConnectTimeout=10 \
  -i "$HOME/.ssh/osxhost_build" \
  -p "$MAC_PORT" "$MAC_USER@$MAC_HOST"
Ouvrir un ticket de connexion
02

Certificat expiré ou identité de signature introuvable

Vérifiez que le certificat inclut une clé privée et n’a pas expiré, et que le profil de provisioning correspond à l’app et à l’équipe. Le trousseau dédié à la CI doit aussi être accessible pendant la session de build. Corrigez d’abord les éléments de signature dans un environnement contrôlé, puis synchronisez-les avec match en lecture seule.

Terminal distant · afficher les identités de signature et les trousseaux
security find-identity -v -p codesigning
security list-keychains -d user
bundle exec fastlane match appstore --readonly
Ouvrir un ticket de signature
03

Disque plein, impossible d’écrire l’archive

Commencez par distinguer le volume système du volume externe et repérez l’espace occupé par DerivedData, les simulateurs et les artefacts de build. Ne supprimez que les caches dont la régénération est confirmée ; ne supprimez pas en masse des trousseaux, des fichiers de signature ou des répertoires de travail en cours d’utilisation.

Terminal distant · consulter l’espace utilisé
df -h
du -sh "$HOME/Library/Developer/Xcode/DerivedData" \
  "$HOME/Library/Developer/CoreSimulator" \
  "$HOME/build-workspace" 2>/dev/null
xcrun simctl list devices unavailable
Ouvrir un ticket concernant le disque
04

Xcode reste bloqué sur l’indexation

Vérifiez d’abord si le processus d’indexation est toujours actif, puis contrôlez l’installation des dépendances et l’espace disque disponible. L’indexation dans l’interface graphique et la réussite d’un build en ligne de commande sont deux choses différentes. Consultez les journaux pour déterminer si l’archive est réellement bloquée.

Terminal distant · consulter les processus et la configuration de build
ps -axo pid,%cpu,%mem,etime,comm | grep -E 'Xcode|SourceKit|swift'
xcode-select -p
xcodebuild -list -workspace "$IOS_WORKSPACE"
df -h "$HOME"
Ouvrir un ticket Xcode

N’ajoutez dans aucun ticket de clé privée, mot de passe de certificat, jeton d’accès ni copie complète du dépôt de signature.Masquez les identifiants et les chemins sensibles dans les journaux avant de les envoyer. Si vous ne pouvez pas vous connecter à la console, écrivez à support@osxhost.comen indiquant votre numéro de commande et le problème rencontré. L’e-mail et les tickets de la console sont les canaux d’assistance publics.

Réussissez d’abord un archive, puis augmentez la concurrence

Indiquez dans le pipeline les versions des outils, l’injection des éléments de signature, les clés de cache et le répertoire des artefacts. Pour louer une machine, passez commande ; si vous êtes bloqué, ouvrez un ticket avec les résultats du diagnostic.