Si vous raisonnez en blocs de calcul comme pour un VPS et que, sur React Native / Expo, vous butez sur les files EAS, les modules natifs et le modèle des identités, cet article place sur une même grille le build hébergé et le plan macOS dédié : d’abord les irritants, puis des matrices de décision et une liste d’embarquement en six étapes, jusqu’à un rythme d’auto-hébergement auditable. Vous saurez quand conserver EAS, et quand déplacer le build iOS sur un Mac distant loué comme un nœud.
Expo Application Services (EAS) encapsule bien certificats, envoi et build cloud, ce qui convient au parcours standard. Dès qu’apparaissent beaucoup de correctifs natifs, des pods privés, ou l’exigence d’inscrire journaux de build et commandes dans un paquet de conformité, l’opacité des files et la frontière des images hébergées deviennent un frein. Les six points ci-dessous synthétisent des retours d’escalade : ils aident à décider s’il vous faut un second plan de build joint en SSH.
Files peu lisibles : en pointe, un même pipeline peut rester en file des dizaines de minutes ; quand la fenêtre de publication est imposée par le métier, l’imprévisibilité se traduit en risque. Le pool hébergé n’équivaut pas à une machine exclusive où l’on peut fixer la « concurrence max » dans un SLA interne.
Chaîne native longue : dès qu’entrent react-native-config, Firebase, cartes, Bluetooth, etc., avec podspecs ou scripts de précompilation personnés, l’efficacité du cache d’image baisse et le temps d’un build varie fortement ; le diagnostic sans shell hôte ne permet pas de confronter la sortie complète de xcodebuild -showBuildSettings.
Modèle d’identité et de signature hétérogène : un même équipement qui mélange signature gérée par EAS et match interne / AC maison génère souvent l’écart « Archive OK en local, aléa sur le cloud » : contexte de trousseau et combinaison CODE_SIGN_IDENTITY partiellement reproductible sur l’image hébergée.
Niveau disque et DerivedData : sur les hôtes partagés, un monorepo volumineux déclenche plus vite les règles de nettoyage et fait sauter la couche chaude de cache ; pour les équipes qui enchaînent tests UI et archives, cela se traduit par des durées de queue imprévues.
Rupture avec le vocabulaire CI existant : le backend et le web tournent déjà sous GitHub Actions avec labels, plafonds de concurrence et runners self-hosted, tandis qu’iOS vit dans un autre orchestrateur : la charge cognitive et l’astreinte augmentent.
Champs d’audit insuffisants : finance, santé ou exigence export imposent souvent « qui, depuis quelle IP, quelles commandes sur quelle machine de build » ; si le côté hébergé n’exporte pas des journaux SSH ou de session alignés sur votre SOC2, un nœud dédié compense la chaîne de preuve — à cadrer avec la grille tarifaire pour dimensionner l’enveloppe (concurrence, stockage, région).
Si au moins deux de ces constats vous concernent, enchaînez avec le tableau et les étapes d’embarquement ; si les builds restent rares et la couche native mince, exploitez d’abord EAS sans monter tôt un second plan. Pour le raccordement concret d’un runner GitHub Actions self-hosted sur une machine exclusive, voir l’article dédié — ici le sujet est le cadrage RN/Expo entre EAS et le plan macOS.
Mettre les deux approches sur une table ne sert pas à discréditer EAS, mais à parler d’un même langage en revue : files, image, signature, audit. On suppose ici des profils eas.json correctement utilisés et une compétence macOS d’exploitation de base.
| Axe | EAS Build (hébergé) | Mac distant dédié, auto-hébergé |
|---|---|---|
| Délai (démarrage à froid) | Élevé, sans achat de machine ni install système | Moyen : SSH, empreintes Ruby/Node, enregistrement du runner en une fois |
| Files et concurrence | Pool partagé, pics imprévisibles | CPU et disque dédiés, plafond de parallélisme et fenêtres de nettoyage explicites |
| Profondeur native | Adapté au flux Expo hébergé standard | Adapté au natif lourd, pods personnalisés, scripts de prépatch |
| Certificats et signature | Fortement intégré à la signature gérée EAS | Alignement possible avec match, KMS interne, trousseau par environnement |
| Journaux et audit | Principalement les journaux produit, granularité limitée | Collecte de xcodebuild et de session shell complète pour l’audit interne |
| Charge cognitive ops | Faible, plutôt « CI en service » | Moyenne à élevée, proche d’un cluster VPS |
« Le build hébergé couvre le passage de 0 à 1 ; le nœud exclusif, la prévisibilité et l’audit de 1 à N. »
Un compromis courant : paquets de développement et PR encore sur EAS ; archives release, matrice de tests UI et itérations native lourdes sur le Mac distant dédié. On concentre ainsi les « jours-homme » les plus coûteux dans un cadre maîtrisé, en gardant l’intégration côté hébergé pour le reste.
Le tableau suit taille d’équipe, profondeur native et dureté de la conformité. Il ne remplace pas une étude de capacité, il aligne les priorités en comité d’architecture.
| Indicateur | Rester prioritairement sur EAS | Introduire un Mac distant dédié |
|---|---|---|
| Dépendances natives | Quelques modules communautaires, pas de pod sur mesure | Pods privés, SDK binaires, drapeaux de compilation spécifiques |
| Rythme de sortie | Hebdo / bisemaine, file tolérable | Sorties journalières ou créneau figé, concurrence et fenêtre imposées |
| Conformité | Pas d’exigence forte sur les traces de commande | Audit SSH, sortie fixe ou segment de VPC |
| CI existant | iOS totalement découplé des pipelines back/web | Souhait d’un même schéma de labels et de cache qu’Actions / GitLab |
// eas.json (extrait) : profiles pour séparer build hébergé et job self-hosted
{
"build": {
"preview": { "distribution": "internal", "channel": "preview" },
"release-selfhosted": {
"extends": "production",
"env": { "EXPO_USE_FAST_RESOLVER": "1" },
"ios": { "image": "latest" }
}
},
"submit": { "production": {} }
}
Attention : mélanger sur une même branche hébergé et self-hosté impose de documenter quel profil appelle quelles identités, faute de quoi les arrivées se perdent entre trousseau et EXPO_TOKEN.
Hors matrice, une règle simple : « ça tourne » n’est pas « reproductible ». Les mises à jour d’image hébergée arrivent en arrière-plan ; sans figer Xcode et la mineure de Node, le natif RN peut basculer au gré d’une montée de version discrète. Sur un nœud dédié, on verrouille xcode-select et Bundler comme un noyau, et l’on inscrit l’empreinte dans le contrat CI — en cohérence avec le guide builds reproductibles.
On part du principe que vous générez le projet iOS en local via npx expo prebuild et devez lancer xcodebuild ou Fastlane sur l’hôte dédié. L’enchaînement rappelle l’exploitation VPS : comptes, clés, niveau disque, renvoi des logs.
Geler l’empreinte de la chaîne d’outils : noter xcodebuild -version, node -v, ruby -v, pod --version sur le Mac distant et les consigner dans BUILD_ENV.lock ; toute montée de version transite par une PR, pas par une mise à jour ad hoc en SSH.
Utilisateur non interactif pour la CI : ne pas réutiliser une session Apple ID personnelle ; prévoir un compte et un segment de trousseau pour le runner ou le job SSH, comme dans le guide builds reproductibles (isolation des trousseaux).
Isoler DerivedData et Pods : un répertoire par dépôt ou branche, par exemple ~/DerivedData/$REPO/$BRANCH et ~/PodsCache/$REPO ; le nettoyage relève d’une tâche planifiée, pas d’un effacement implicite par le système.
Ramener le job iOS dans la CI principale : labels self-hosted côté GitHub Actions / GitLab vers la machine exclusive, mêmes garde-fous d’approbation et de concurrence que pour Android ; VNC de façon contrôlée pour le debug graphique, pas de bureau laissé ouvert en permanence.
Artefacts et remontée des logs : stocker .ipa, dSYM et le journal brut xcodebuild sur un stockage objet ou un registre interne ; pour la finance, option de captation de session au niveau commande.
Pilote sur deux semaines : choisir cinq branches représentatives et comparer P50/P95 des durées de build et les types d’échec entre EAS et la machine dédiée ; si le natif lourd s’y stabilise et la variance de file baisse, basculer le trafic release.
Conseil : si la région et le stockage restent en arbitrage, parcourez d’abord la page des tarifs de location et inscrivez concurrence, niveau disque et zone de sortie dans l’annexe d’achat, puis recoupez avec les six étapes ci-dessus pour la recette d’accueil.
xcodebuild échoue aléatoirement en édition de liens.Laisser iOS entièrement sur le pool hébergé reste, à court terme, le moins exigeant en personnes. Dès que le natif, les exigences d’audit et l’unification du scheduling avec Actions ou GitLab deviennent des contraintes dures, la combinaison file opaque + image non verrouillée amplifie l’incertitude. À l’inverse, un parc de Mac interne sans gouvernance disque ni empreinte retombe vite en dette opérationnelle.
En synthèse, les livraisons RN/Expo qui exigent une file 7j/7 prévisible, des sessions de commande auditables et le même univers de labels que vos runners placent le gros de la charge sur un plan macOS dédié, EAS assurant l’intégration légère et la coordination externe. Lorsqu’on veut traiter l’environnement d’exécution comme un nœud contractuel, réduire la variance des files et couvrir l’iOS côté CI/CD et automations, la location de Mac Mini cloud NodeMini s’impose en général comme l’option la plus cohérente.
Lorsqu’il faut traiter le build iOS comme un nœud extensible : disque et concurrence stables, journaux de commande exportables, ou chaîne native incompatible avec l’image hébergée, la machine exclusive est la bonne option. Vous pouvez lancer un pilote limité en vous appuyant sur la grille des tarifs de location, puis décider du basculement des jobs de release.
Oui : séparez profils, trousseaux et secrets (signature gérée EAS sur le chemin hébergé, match ou KMS sur le chemin self-hosted) et documentez les critères de bascule dans le README. Pour la connectivité et les comptes, le centre d’aide cloud Mac (SSH, droits) complète la checklist.
L’article runners traite des labels, du cache et des files ; celui-ci fixe le partage des rôles RN/Expo entre EAS et le plan macOS dédié. Si le runner est déjà enregistré sur le Mac distant, considérez les six étapes ci-dessus comme critères d’acceptation supplémentaires.