Cet article ne répond qu’à une question : vous êtes à Singapour quelques jours avec seulement un ultrabook — pouvez-vous boucler en 72 heures la chaîne modifier le code → compilation distante → TestFlight sans enregistrer un Mac Studio en soute ?
Prérequis (tout le reste s’appuie dessus) : vous disposez déjà d’un build node macOS toujours en ligne, version figée, egress prévisible — pas le Mac d’un collègue pour l’après-midi, ni un runner CI à froid à chaque job. Le runbook décrit comment le déclencher depuis la route ; sans build node stable, même la meilleure checklist SSH s’effondre.
La chronologie vient d’un vrai hotfix de notre équipe du 13 au 15 novembre 2025 (heure de Singapour), documenté au 3 juin 2026. Les identifiants sont masqués ; les extraits de logs sont les textes d’origine du terminal et de GitHub Actions — pour reproduire les mêmes contrôles chez vous.
Beaucoup d’équipes françaises confondent « être à Singapour » et « avoir besoin d’un Mac loué sur place ». Pour compiler iOS et lancer XCTest, l’emplacement du Mac cloud importe peu ; ce qui compte sur le terrain, c’est l’uplink stable et le fait que App Store Connect voit l’IP de sortie du builder, pas celle de la chambre d’hôtel.
Avant le vol, alignez-vous sur ces trois points :
-
Build node stable d’abord
IP fixe, Xcode épinglé, match en écriture unique ; en déplacement vous ne faites que déclencher, jamais monter la signature au Wi‑Fi hôtel.
commit + run ID archivés
-
Le nœud suit l’egress des artefacts
Bêta APAC seule : prioriser Singapour ; ASC nord-américain et IP de sortie fixe : builder Canada.
voir le tableau
-
Ne pas coder toute la journée en VNC
Wi‑Fi hôtel ou liaison transpacifique : le partage d’écran est fragile ; VNC seulement pour le trousseau.
SSH d’abord
Ancres vérifiables (extrait voyage nov. 2025)
Le jour de la release verte, nous avons consigné ces champs dans le ticket — votre runbook doit faire pareil, sinon impossible de distinguer réseau lent et compile lente :
En France, on oublie souvent d’archiver le hash de commit et l’URL du run Actions : on se souvient que « c’était long », pas que l’archive a pris 11 ou 38 minutes. Ces métadonnées coûtent peu et sauvent le post-mortem après Changi.
| Champ | Valeur enregistrée | Comment capturer |
|---|---|---|
| Git commit | 7f2a91c (main) | git rev-parse --short HEAD |
| GitHub Actions | Run #18472930156 · workflow ios-ship.yml | UI Actions → URL du run |
| Xcode builder | 16.2 (16C5032a) · SDK iphoneos18.2 | xcodebuild -version + en-tête de log |
| Xcode portable | 16.2 (aligné builder à T-48h) | idem, avant le départ |
| Durée archive | 11m 34s (M4 cloud 24 Go) | écart avant ** ARCHIVE SUCCEEDED ** |
| Même commit, clean build Air local | 38m 12s (après un échec) | baseline locale ; justifie l’offload |
| Traitement TestFlight | upload 4m 08s · ASC « Processing » ~22m | altool / API + mail ASC |
| Egress builder | 203.0.xxx.xxx (hôte Canada, inchangé) | curl -4 ifconfig.me sur le builder |
Build description signature: 7f2a91c7e3b2… ExecuteExternalTool …/Xcode.app/Contents/Developer/Toolchains/… ** CLEAN SUCCEEDED ** ** ARCHIVE SUCCEEDED ** [684.123 sec] ← ~11m 24s (clean inclus) note: Using codesigning identity: Apple Distribution: Acme *** (TEAMID)
Cette nuit à Singapour, déclenchement SSH via partage de connexion du téléphone ; logs de compile et d’upload uniquement sur le builder. L’ultrabook gardait le lien du run Actions et le commit. Avec des runners self-hosted, collez le run ID dans la PR — même habitude que notre article sur les runners macOS auto-hébergés sur Mac cloud.
Quel build node ce runbook suppose ? (choisir avant le vol)
La pire semaine pour comparer « on loue un Mac trois jours ? ». Nous avons listé ce que nous avons rejeté et gardé — les noms de produits ne sont que la dernière colonne, pas la conclusion :
Pour une équipe iOS avec Fastlane, match et liste blanche API ASC, le build node est un actif de conformité. Le changer pendant un salon client est un changement — pas un essai rapide.
| Option | Pourquoi ça échoue en semaine déplacement | Ce qu’il nous fallait quand même |
|---|---|---|
| Xcode Cloud | Clés match, Fastlane custom, egress fixe difficile à maîtriser ; dépannage opaque | OK pour les PR ; chaîne de signature hotfix = notre nœud |
| AWS EC2 Mac | Location min. 24h, quotas/régions ; IP de sortie souvent variable | Vrai macOS ; équipes déjà sur AWS compliance |
| Mac cloud partagé / tournant | Résidus trousseau et Derived Data ; risque de mélange de certificats | Peu cher, compile sans signature seulement |
| Mac mini au bureau | Collègue éteint, mises à jour OS, personne ne change le disque à 2 h | Contrôle total, pas 7×24 en voyage |
| Mac cloud dédié (notre choix) | Doit être allumé, épinglé, IP en liste blanche avant | SSH + egress fixe + trousseau sur une machine ; SG/Canada |
SSH de jour depuis l’APAC vers un M4 à Singapour (specs sur la page nœud Singapour), upload TestFlight toujours depuis le Canada — liste blanche API ASC et clés match déjà liées à l’egress Canada 203.0.xxx.xxx. Changer de fournisseur : fenêtre de maintenance ; changer l’egress en semaine déplacement : non. Hashvps car le renouvellement ne fait pas tourner l’IP et le matériel est du bare metal — aligné avec une machine, une IP. EC2 Mac ou mini bureau avec IP fixe + Xcode épinglé : le reste du runbook s’applique tel quel.
Séparer le problème : réseau vs puissance de calcul
Beaucoup cherchent « location Mac locale » dès l’atterrissage. Si vous compilez iOS et lancez XCTest, la location du Mac cloud n’a pas besoin d’être dans votre ville — SSH depuis Changi ressemble à SSH depuis Paris. Sur le terrain vous réglez :
- Uplink stable : eSIM roaming ou hotspot fiable pour SSH continu (voir l’aperçu GSMA sur l’eSIM ; double SIM pour séparer data et voix).
- Collaboration fuseaux : stand-ups et fenêtres de review avec l’équipe à la maison — n’impacte pas le temps de compile, mais l’heure du push.
- Egress conformité : App Store Connect et proxys d’entreprise regardent l’IP de sortie du builder, pas votre chambre.
Côté compute : avant le départ, repo cloné, certificats importés, chemins Derived Data fixes. Après l’atterrissage : git pull et scripts — pas d’installation Xcode à l’aéroport, sinon vous brûlez la fenêtre 72 h en téléchargements.
La chaîne de dépendances est ordonnée : (1) machine en ligne avec egress prévisible et signature single-writer ; (2) workflows et lanes Fastlane pour cet hôte ; (3) portable comme télécommande ; (4) qualité hôtel/roaming comme contrainte sur (3), pas sur le débit de compile. Sauter (1) en espérant (3) mène à l’archive sur MacBook Air en salle de conférence — puis « pourquoi l’upload a échoué alors que la démo IPA marchait ».
Chronologie 72 heures (horodatages réels)
T-48h · 11/11/2025 Paris : builder Canada archive + TestFlight au vert (commit 9e0b44f, run #18451002201). Les deux hôtes en xcodebuild -version 16.2. Clé SSH publique dans authorized_keys ; ServerAliveInterval 60 dans ~/.ssh/config du portable.
T-24h · 12/11/2025 : roaming activé ; mosh build-ca tenu 10 minutes. Clé match privée uniquement au Canada (voir hôte d’upload TestFlight).
T+0 · 13/11/2025 19:10 SGT Changi : premier échec SSH sur Wi‑Fi hôtel (incident ①) ; hotspot, git pull + build incrémental en 4m 02s (pas archive).
T+24h · 14/11/2025 : réunions client le jour ; 20:15 SGT push 7f2a91c. 23:41 SGT archive → 00:03 SGT upload ASC → 00:25 SGT TestFlight testable. Pas devant l’écran ; builder et Actions ont fini seuls.
T+48h–72h : démo sur site avec build TestFlight déjà traité, pas d’archive live sur Wi‑Fi salon. Upload via l’API App Store Connect depuis le builder ; roaming portable sans objet.
Entre T+0 et T+24h, l’hôte Singapour = builder interactif : RTT bas, logs « locaux » — chaque minute de compile au datacenter. Entre T+24h et upload, le Canada = porte conformité : match readonly, export, API — ASC connaissait cet egress. Ennuyeux = bien : personne n’ouvre le trousseau sur téléphone à minuit.
Nœud Singapour vs nœud Canada en déplacement court
Approfondissement régional : guide Mac distant cinq régions. En voyage, deux règles :
| Dimension | Singapour / DC APAC vous éditez sur place | Canada / DC Amérique du Nord artefacts en egress NA |
|---|---|---|
| Ressenti SSH | RTT bas, logs suivent | 150–250 ms transpacifique ; OK, compile distante |
| TestFlight / ASC | OK si egress en liste blanche | La plupart des équipes : match/API sur IP NA |
| Adapté à | Bêtas internes, collab APAC, itération jour | Publication store, notarisation, deps CDN NA |
| Migrer à cause du vol ? | Non ; plusieurs rôles d’hôte dans le repo | Non ; compile SG + upload Canada courant |
Nous n’avons pas déplacé match parce qu’un humain était à Singapour : Singapour compilait debug/interne ; le Canada uploadait. Migration de certificats = événement de changement — interdit en semaine déplacement (même répartition que builds Xcode lents sur Mac cloud M4, géographie inversée).
Checklist connectivité : roaming, Wi‑Fi hôtel, SSH
Les réseaux hôtel bloquent souvent l’UDP, coupent le TCP inactif vers 5 minutes ou réinitialisent SSH après bizarreries ARP. Mon kit minimum :
- Portable + téléphone en double chemin : SSH sur hotspot, visio sur Wi‑Fi hôtel.
ServerAliveInterval 60etServerAliveCountMax 3dans~/.ssh/config.- Longues tâches dans
tmuxouscreen; après coupure,tmux attach. - Jamais
rsync DerivedDatasur lien instable — Git seulement.
VPN entreprise en tunnel complet : demander le split avant le voyage — ressources internes via VPN, SSH builder en direct. Beaucoup d’équipes : Mac sur Tailscale uniquement. Mosh aide sur lien avec pertes ; ne remplace pas un pare-feu qui tue l’UDP — garder SSH classique en secours.
Incidents jour 2 (avec logs)
Les quatre ci-dessous le 14/11/2025 dans une même fenêtre, dans l’ordre — pas des hypothèses. Chemins masqués.
① Wi‑Fi hôtel : déconnexion SSH inactive
$ ssh build-sg 'cd ~/workspace/MyApp && git pull' client_loop: send disconnect: Broken pipe Connection to build-sg.xxx port 22: Broken pipe
Cause : NAT hôtel a tué le TCP inactif vers ~300 s. Correctif : hotspot + ServerAliveInterval 60 ; longues tâches dans tmux. Pas de récidive.
② Archive échouée : pas de certificat Distribution dans le trousseau
error: No signing certificate "iOS Distribution" found error: No profiles for 'com.acme.myapp' were found ** ARCHIVE FAILED **
Cause : collègue avait installé des certificats en login VNC sans importer Distribution dans le trousseau login du cloud ; portable OK grâce à la signature automatique Xcode. Correctif : bundle exec fastlane match appstore --readonly au Canada, vérifier security find-identity -p codesigning -v pour Apple Distribution, relancer archive (11m 34s ci-dessus).
③ Tests parallèles : runtime Simulator vs patch Xcode
xcodebuild: error: Unable to find a destination matching the provided destination specifier:
{ platform:iOS Simulator, OS:18.1, name:iPhone 16 }
Ineligible destinations: … missing matching iOS Simulator runtime
Cause : builder passé à Xcode 16.2 (runtime 18.2), workflow encore OS:18.1. Correctif : destination ios-ship.yml en 18.2, commit .xcode-version — pas un problème de suppression Derived Data.
④ Derived Data « corrompu » : disque plein
error: unable to attach DB: error: accessing build database "/Users/builder/Cache/DerivedData/…/build.db": database or disk is full
Correctif : df -h montrait 6,2 Go libres sur / ; suppression d’anciens .xcarchive et Derived Data de branche. Si message « cache corrupt », vérifier le niveau disque avant rm -rf DerivedData.
Matrice des modes d’échec
| Symptôme | Scène | Cause cloud / distante | Action |
|---|---|---|---|
| Coupure SSH | Wi‑Fi hôtel | timeout NAT inactif | hotspot + ServerAlive + tmux/mosh |
| build OK, upload KO | ASC / proxy entreprise | egress non listé | IP builder fixe ; pas d’échange d’hôte |
| local OK / remote KO | archive / signature | dérive trousseau vs match | match readonly + find-identity |
| Simulator introuvable | tests CI de nuit | SDK/runtime non verrouillés | .xcode-version + destination |
| build.db / cache | branches parallèles | disque plein imitant corruption | df -h → archives / Derived Data |
| signature expirée | fin de trimestre | certificat Distribution expiré | rotation 14 j avant ; semaine déplacement match readonly |
Boucle Xcode distante minimale (commandes)
Première nuit sur place : prouver la boucle 72 h — paramètres selon la TN2339 ; commit 7f2a91c :
ssh build-sg 'set -e
cd ~/workspace/MyApp
git fetch origin && git checkout 7f2a91c && git pull --ff-only
xcodebuild -scheme MyApp -configuration Release \
-derivedDataPath ~/Cache/DerivedData \
-destination "generic/platform=iOS" \
build 2>&1 | tee /tmp/build-7f2a91c.log'
Archive et upload dans des lanes Fastlane ; à Singapour seulement make ship COMMIT=7f2a91c, run Actions #18472930156 comme piste d’audit. Le builder est aussi un runner self-hosted.
Specs et disque : ne pas réduire en semaine déplacement
| Palier | Pression mémoire | Disque | Conseil |
|---|---|---|---|
| 16 Go / 256 Go | tests parallèles swappent vite | peut saturer en une semaine | hotfix mono-dépôt seulement |
| 24 Go / 512 Go | la plupart des dépôts iOS OK | nettoyage archives hebdo | défaut voyage |
| 24 Go / 1 To | marge confortable | cache multi-branches OK | monorepo + nombreux simulateurs |
Réduire le disque la semaine du vol déclenche l’incident ④ : archives et runtimes Simulator consomment des dizaines de Go plus vite qu’on ne croit. La finance devrait couper des jobs de tests parallèles avant le disque de l’hôte de signature.
Que mettre encore dans la valise
Volontairement plus léger : pas de MacBook Pro 16 pouces, oui portable Terminal, appareil de test Lightning/USB-C, chargeurs de secours, sauvegarde papier ou PDF hors ligne du QR eSIM roaming activé. Comptes builder, clés API, mots de passe match dans le coffre d’équipe, mais fiche d’urgence hors ligne : IP builder, port SSH, téléphone astreinte — éviter « roaming mort + 2FA SMS absente ».
Démos client : build TestFlight ou Ad Hoc déjà sur l’appareil, pas d’archive live sur Wi‑Fi salon. Séparer démo (réseau grand public) et release (egress fixe builder) — sinon « la démo s’installe donc l’upload devrait passer ».
Le matériel de test physique reste nécessaire pour Bluetooth/NFC que le Simulator ne couvre pas. Le Mac cloud remplace le débit compile/sign, pas le labo appareils.
Coût caché d’une semaine (pour celui qui valide le budget)
Acheter ou expédier un Mac mini, ou louer sur place : douane, adaptateurs, réinstallation OS, réimport certificats, nouvelle confiance d’empreinte appareil. Un build node dédié facturé à la semaine achète un environnement prêt — Derived Data, match, IP fixe pas à reconstruire en déplacement. Même cadre TCO que bureau Mac à bas coût pour startup : CapEx → OpEx sans certificats sur laptops personnels.
Le coût d’opportunité est ce que sent la direction : une heure de compile à l’hôtel = une heure de moins avec le client. Push dans le couloir, logs au retour chambre. Pour trois ou quatre vols Asie par an, un builder prévisible bat « acheter un Mac à l’aéroport ».
FAQ
Faut-il un Mac ? Une machine Git + SSH suffit (Windows possible avec nos articles Mac cloud). Appareils de test si debug device obligatoire ; la compile reste dans le cloud.
Nouveau builder trois jours avant le départ ? Oui — import certificats et premier full compile avant le vol ; sur place, incrémental seulement.
Le DC Singapour doit-il coller à la ville ? Non. Co-location baisse le RTT SSH ; publication store NA peut utiliser le Canada.
Le roaming suffit-il pour l’IPA ? Il ne devrait pas le faire. IPA du builder vers ASC ; le portable ne bouge que de petits objets Git.
Différence avec l’article « builds lents » ? Celui-là traite le portable qui chauffe ; celui-ci la déplacement géographique et réseaux incertains avec runbook et placement des nœuds.
Déménager la gateway OpenClaw / agent ? Non. Elle peut rester au Canada ; Singapour = surface SSH pour déclencher les builds.
VPN entreprise 24/7 ? Selon la politique. Tunnel complet qui casse SSH → split ou Tailscale vers le builder seulement.
Fuseaux et fenêtres de release ? Singapour UTC+8, ouest US ~15–16 h d’écart. Archive l’après-midi à Singapour, upload automatique la nuit au Canada — compatible avec les batches nord-américains suivi du soleil ; pas besoin de veiller l’upload à 3 h.
Vérifier commit / run ID ? Chiffres de notre dépôt interne, domaines/IP masqués ; reprenez le format de champs dans vos tickets, pas nos nombres.
Pourquoi deux datacenters ? Latence pour le travail quotidien vs conformité upload — une seule machine les couvre si ASC et match sont déjà sur la même IP ; notre setup les séparait volontairement.