Le pipeline reste en attente, ne trouve pas Xcode ou perd son agent après le redémarrage du Mac.
La solution la plus rapide consiste à conserver d’abord un agent macOS hébergé ; déployez ensuite un agent auto-hébergé sur un Mac distant uniquement si votre équipe a besoin d’un environnement Xcode fixe, de caches persistants, d’un accès au réseau interne ou d’un trousseau de signature maîtrisé. Un agent affiché « Online » est seulement enregistré : il ne devient exploitable en production qu’après une vraie compilation, un redémarrage réussi et une vérification de l’isolement des identifiants.
Cette page concerne les développeurs qui exécutent des compilations ou des tests iOS et macOS avec Azure Pipelines et qui doivent conserver une chaîne d’outils stable. Elle s’adresse également aux ingénieurs DevOps responsables d’un Agent Pool toujours disponible, ainsi qu’aux équipes mobiles qui gèrent certificats, profils de provisioning et droits de publication.
Commencer par le bon périmètre : agent hébergé ou Mac distant
Un agent macOS hébergé reste le choix par défaut pour un dépôt qui accepte une image standard, ne dépend pas d’un cache local durable et peut installer ses outils pendant l’exécution. La documentation officielle distingue les agents hébergés des agents auto-hébergés et précise les responsabilités qui restent à la charge de l’équipe lorsque la machine est administrée directement (comparaison officielle des types d’agents Azure Pipelines).
Le Mac distant devient pertinent lorsque le pipeline doit retrouver exactement le même environnement d’une exécution à l’autre. Cela concerne notamment :
- une version précise de Xcode qui n’est pas encore disponible dans l’image hébergée ;
- un cache de dépendances ou de compilation dont la reconstruction ralentit chaque tâche ;
- un accès à un dépôt interne, à un service de test ou à une ressource protégée par réseau privé ;
- un trousseau macOS et des certificats contrôlés par une équipe restreinte ;
- des tests graphiques, audio ou vidéo nécessitant une session macOS persistante ;
- un besoin de laisser tourner un nœud de construction pendant les périodes où aucun poste local n’est disponible.
Cette liberté entraîne toutefois des coûts techniques souvent sous-estimés. L’équipe doit surveiller les mises à jour macOS et Xcode, la croissance du disque, les permissions du compte de service, le nettoyage des espaces de travail et la récupération après panne. Elle doit aussi décider qui peut se connecter en SSH ou en VNC, car un accès administrateur trop large transforme un nœud de compilation en point d’entrée transversal vers plusieurs projets.
Les dépôts contenant du code externe non approuvé doivent rester sur un environnement isolé. Les recommandations de sécurité d’Azure Pipelines rappellent qu’un agent auto-hébergé peut conserver des fichiers, des secrets ou des modifications entre deux tâches ; l’agent hébergé est donc préférable lorsque le code exécuté n’est pas entièrement maîtrisé (principes de sécurité des pipelines).
Première étape : définir un pool indépendant et un compte limité
Un Mac destiné à Azure Pipelines ne devrait pas être ajouté directement au pool général de l’organisation. Commencez par créer un Agent Pool consacré aux builds Apple, puis accordez à ce pool uniquement les autorisations nécessaires au projet concerné. Cette séparation facilite la rotation des machines et empêche qu’un pipeline sans rapport sélectionne par erreur le nœud qui contient l’environnement de signature.
Sur macOS, créez un compte système dédié, sans usage personnel quotidien. Le compte doit pouvoir exécuter les outils de construction, accéder au répertoire de travail et utiliser, lorsque c’est strictement nécessaire, les éléments de signature autorisés. Il ne doit pas servir à la navigation, à la messagerie ou à l’administration générale du serveur. Les connexions SSH et VNC peuvent rester réservées aux personnes chargées de l’exploitation.
Préparez ensuite un répertoire de travail séparé du répertoire personnel utilisé pour l’administration. Dans les exemples ci-dessous, les valeurs entre chevrons sont volontairement des espaces réservés :
mkdir -p <CHEMIN_TRAVAIL_AGENT>
cd <DOSSIER_AGENT>
./config.sh \
--url https://dev.azure.com/<ORGANISATION> \
--auth <METHODE_AUTHENTIFICATION> \
--pool "<POOL_MAC_DEDIE>" \
--agent "<NOM_AGENT>" \
--work "<DOSSIER_TRAVAIL>"
La commande exacte, la méthode d’authentification et les options proposées doivent être reprises depuis la console Azure DevOps au moment de l’inscription. Il ne faut pas copier dans une documentation interne un jeton temporaire ni supposer qu’une option d’authentification restera identique. Les possibilités prises en charge sont détaillées dans la documentation officielle sur l’authentification des agents (options d’authentification d’un agent auto-hébergé).
Comment ajouter un agent macOS auto-hébergé sans donner trop de droits ?
Il faut associer le Mac à un pool indépendant, utiliser un compte de service dédié, limiter les permissions du projet et conserver les droits d’administration hors du compte qui exécute les tâches. La première preuve attendue est l’apparition de l’agent dans le bon pool, avec son nom, sa version et ses capacités visibles ; ce n’est pas encore une validation de production.
Cochez les éléments suivants avant de poursuivre :
- [ ] Le pool ne contient que des nœuds destinés aux projets Apple.
- [ ] Le compte de service n’est pas utilisé pour les tâches personnelles.
- [ ] Le dossier de travail n’est pas partagé avec un autre compte ou un autre outil.
- [ ] Le jeton ou secret d’inscription n’est pas conservé dans le dépôt.
- [ ] Les autorisations du projet ont été testées avec un pipeline minimal.
Faire fonctionner l’agent sans dépendre d’une session SSH
Un build en ligne de commande et un test qui ouvre le Simulator n’ont pas les mêmes contraintes. Une compilation exécutée par xcodebuild peut généralement fonctionner sous un service d’agent, alors qu’un test d’interface, une capture vidéo, une validation graphique ou un scénario audio peut exiger une session utilisateur macOS ouverte. La différence doit être documentée avant de choisir le mode de démarrage.
Pour un agent macOS, le mécanisme de service prévu par la documentation s’appuie sur launchd. Après l’installation, vérifiez l’état avec le script fourni par l’agent :
cd <DOSSIER_AGENT>
./svc.sh status
La documentation macOS d’Azure Pipelines décrit l’installation et le fonctionnement du service (configuration du service d’agent sur macOS). Une tâche qui réussit après une connexion SSH ne prouve pas que le service est correctement configuré : le shell SSH peut avoir fourni des variables, un trousseau déverrouillé ou une session graphique absente lors d’un démarrage normal.
La validation doit donc comporter plusieurs interruptions contrôlées :
- lancer une tâche pendant une connexion d’administration, puis fermer cette connexion ;
- déconnecter la session distante sans arrêter le Mac ;
- redémarrer le système et vérifier que le service revient sans intervention manuelle ;
- exécuter une compilation après le redémarrage ;
- vérifier séparément un test Simulator ou une tâche graphique si le projet en dépend.
Pourquoi un agent macOS ne revient-il pas automatiquement en ligne après un redémarrage ?
Les causes fréquentes sont un service non installé, un compte de service qui n’ouvre pas la session attendue, un accès réseau indisponible au démarrage ou une tâche graphique lancée sans session utilisateur. Le statut svc.sh et un pipeline réel après redémarrage fournissent une preuve plus utile que l’icône « Online » dans la console.
Pour les scénarios graphiques, launchd doit être considéré avec ses limites : un service peut démarrer correctement sans fournir l’état de session dont le Simulator ou une application graphique a besoin. Si le test exige une session ouverte, définissez explicitement cette exigence, limitez l’accès VNC et prévoyez un contrôle après chaque mise à jour de macOS.
Attention : ne validez jamais un nœud uniquement parce qu’il est joignable en SSH. Un nœud de production doit recevoir une tâche sans session d’administration active, survivre à un redémarrage et laisser un état de travail propre après un échec.
Router les tâches vers le bon environnement Xcode
L’agent doit exposer les capacités attendues par Azure Pipelines. Une tâche peut rester bloquée ou être attribuée au mauvais nœud si le pipeline demande une capacité absente, si plusieurs versions de Xcode coexistent sans convention claire ou si le nom de la capacité ne correspond pas à la demande. Le moteur de pipeline utilise les exigences et les capacités pour sélectionner un agent compatible (fonctionnement des demandes d’agent et de l’exécution des pipelines).
Commencez par inspecter la sélection active de Xcode :
xcode-select -p
xcodebuild -version
Ces commandes doivent être exécutées dans le même contexte que celui du service, et non uniquement dans le terminal d’un administrateur. Les composants et les commandes disponibles doivent être comparés à la référence Apple sur les outils en ligne de commande Xcode (référence Apple des outils de ligne de commande Xcode).
Ajoutez ensuite un projet de test réduit, avec un schéma partagé et une cible suffisamment représentative. Il doit vérifier la compilation, les tests, la génération du résultat de test et la présence de l’artefact attendu. La tâche Xcode du pipeline doit être configurée avec des entrées explicites, notamment le projet ou l’espace de travail, le schéma, la configuration et la destination ; la documentation officielle décrit les tâches Xcode et leurs paramètres à contrôler (tâche Xcode pour Azure Pipelines).
Que faire lorsque Azure Pipelines ne trouve pas d’agent possédant la capacité Xcode ?
Vérifiez d’abord que Xcode est installé et sélectionné pour le compte qui exécute l’agent. Contrôlez ensuite les capacités publiées, le nom exact utilisé dans demands et l’état du service. Après l’installation ou le changement de Xcode, redémarrez l’agent afin qu’il republie ses capacités, puis relancez une tâche minimale.
Un exemple de routage doit rester lisible et spécifique :
pool:
name: <POOL_MAC_DEDIE>
demands:
- <CAPACITE_XCODE> -equals <VALEUR_ATTENDUE>
Il est préférable de distinguer les pools ou les capacités pour les versions de Xcode incompatibles, plutôt que de masquer la différence dans un script. Un pipeline qui sélectionne implicitement le premier Mac disponible devient difficile à reproduire, surtout lorsque plusieurs projets partagent le même nœud.
Pour un build iOS complet, testez dans cet ordre logique : compilation sans signature, exécution des tests, production d’un artefact, puis archivage signé. Cette séparation permet de savoir si un échec vient de Xcode, du projet, du Simulator ou des identifiants Apple.
Isoler les certificats avant l’archivage et la publication
La signature ne doit pas être le premier test effectué sur un agent nouvellement inscrit. Une compilation sans signature confirme d’abord que le projet, Xcode, les dépendances et le routage fonctionnent. Ensuite seulement, l’équipe peut introduire le certificat, le profil de provisioning et les autorisations de publication dans une étape contrôlée.
Les certificats et profils doivent être stockés comme fichiers sécurisés, avec des permissions de bibliothèque limitées au pipeline qui en a besoin. Les Secure Files sont conçus pour contrôler l’accès aux fichiers sensibles et leur utilisation dans les tâches autorisées (documentation officielle des Secure Files). La procédure de signature Apple doit également suivre une séparation claire entre installation des identifiants, archivage et nettoyage (guide officiel de signature des applications Apple dans Azure Pipelines).
Le dépôt ne doit contenir ni certificat exporté, ni profil de provisioning permanent, ni mot de passe de trousseau. Les variables ordinaires ne remplacent pas un stockage sécurisé, surtout lorsqu’elles sont visibles dans les journaux ou accessibles à plusieurs pipelines. Si plusieurs projets utilisent le même Mac, séparez au minimum les pools sensibles et non sensibles ; pour des équipes ou des niveaux de confiance différents, des nœuds distincts sont souvent plus simples à auditer.
La recette de validation comprend les contrôles suivants :
- [ ] Un build sans signature réussit avec le compte de service.
- [ ] Un fichier sécurisé n’est téléchargeable que par le pipeline autorisé.
- [ ] L’archivage signé utilise le profil attendu et la bonne identité.
- [ ] Les journaux ne révèlent ni secret, ni mot de passe, ni contenu de certificat.
- [ ] Les fichiers temporaires et identifiants sont supprimés après le job.
- [ ] Un job sans permission de signature échoue proprement.
Comment utiliser un certificat iOS sans le placer dans le dépôt ?
Conservez le certificat et le profil dans les Secure Files, limitez leur autorisation au pipeline nécessaire et installez-les seulement pendant l’étape de signature. Le contrôle final consiste à vérifier les journaux, l’état du trousseau et le disque après l’exécution, y compris lorsque le build échoue.
Valider la continuité d’un nœud partagé
Un Mac distant utilisé par plusieurs projets doit être traité comme une petite plateforme, et non comme un simple ordinateur allumé. Les caches peuvent accélérer les tâches, mais ils peuvent aussi conserver une dépendance, un fichier généré ou une configuration d’un projet précédent. Le pipeline doit donc définir ce qui peut être réutilisé et ce qui doit être supprimé.
Contrôlez le nettoyage du répertoire de travail après une réussite et après un échec. Mesurez la croissance du disque avec une règle d’alerte interne, puis documentez la personne responsable des mises à jour de l’agent, de macOS, de Xcode et des dépendances. Une mise à niveau non testée peut modifier la capacité publiée, le comportement du Simulator ou la compatibilité des scripts de signature.
Le fonctionnement durable doit être vérifié par une série de scénarios, sans dépendre d’une seule exécution :
- tâches consécutives de projets différents ;
- échec volontaire suivi d’une nouvelle tentative ;
- interruption du système puis reprise automatique ;
- mise à jour de l’agent suivie d’une compilation réelle ;
- exécution simultanée si le nœud est autorisé à traiter plusieurs tâches ;
- inspection du disque et du répertoire de travail après chaque scénario.
La documentation des agents hébergés rappelle que l’environnement fourni est contrôlé différemment d’un agent auto-hébergé (fonctionnement des agents macOS hébergés). Cette différence doit entrer dans la décision : la persistance est utile pour une chaîne fixe, mais elle impose une hygiène et une responsabilité opérationnelle supplémentaires.
Choisir une trajectoire avant la mise en production
La décision ne dépend pas seulement de la présence d’un Mac disponible. Elle dépend du niveau de contrôle recherché et de la capacité de l’équipe à maintenir ce contrôle dans le temps.
- Si le projet accepte une image macOS standard, ne conserve pas de cache critique et exécute du code externe, choisissez l’agent hébergé.
- Si le projet exige une version fixe de Xcode, un cache durable ou une ressource interne accessible depuis le réseau, choisissez un Mac distant auto-hébergé, avec un pool dédié.
- Si les tests utilisent le Simulator ou une interface graphique, ajoutez une validation de session macOS avant de promettre une disponibilité continue.
- Si le pipeline signe ou publie une application, isolez le pool sensible, les Secure Files et le compte de service avant tout déploiement.
- Si le nœud échoue après redémarrage, conserve des fichiers d’un autre projet ou publie des capacités incohérentes, revenez à l’agent hébergé ou isolez ce Mac jusqu’à correction.
- Si plusieurs équipes de confiance différente partagent les mêmes identifiants, ne mutualisez pas le nœud : séparez les pools ou les machines.
Le tableau suivant résume le choix sans remplacer les tests de validation :
| Besoin de l’équipe | Agent macOS hébergé | Mac distant auto-hébergé |
|---|---|---|
| Image standard et tâches reproductibles | Choix prioritaire | Inutilement administré |
| Version Xcode fixe ou environnement durable | À vérifier selon l’image disponible | Adapté après validation |
| Cache persistant | Limité par la nature de l’environnement | Possible, avec nettoyage contrôlé |
| Accès à un réseau interne | Généralement inadapté | Adapté si le réseau et les droits sont maîtrisés |
| Code externe non approuvé | Choix plus prudent grâce à l’isolation documentée | À éviter sans isolation supplémentaire |
| Certificats et profils sensibles | Gestion centralisée à contrôler | Possible avec pool, compte et fichiers séparés |
| Tests graphiques ou Simulator | À vérifier dans l’image utilisée | Session macOS à tester explicitement |
| Maintenance de l’agent et du système | Principalement déléguée | Entièrement à la charge de l’équipe |
Un Mac distant loué peut constituer une alternative plus souple à l’achat d’un Mac dédié lorsque le besoin porte sur une période de migration, une version particulière de Xcode ou un nœud de CI à maintenir en ligne sans immobiliser immédiatement un budget matériel. Avant de choisir, l’équipe peut comparer les options de location d’un Mac distant et examiner les durées de location disponibles, puis appliquer la même procédure d’acceptation que pour une machine interne.
Ce que l’équipe doit accepter avant de louer un Mac distant
L’agent hébergé conserve l’avantage d’une responsabilité matérielle et système réduite, tandis qu’un poste local peut offrir une interaction graphique plus directe et un accès physique aux appareils de test. En revanche, un poste local laissé allumé dépend de l’alimentation, de la connexion du bureau et des interventions d’une personne ; un Mac distant auto-hébergé ajoute une latence d’accès, une gestion des sessions et une responsabilité de nettoyage, mais permet de disposer d’un nœud séparé du poste de développement.
Pour une équipe qui doit uniquement compiler occasionnellement, un achat matériel ou une administration permanente peut être disproportionné. Pour une charge lourde et stable, avec besoin de périphériques physiques, d’un accès USB direct ou d’un contrôle matériel particulier, la location distante n’est pas toujours le meilleur choix. Le bon usage se situe plutôt dans le besoin temporaire de compilation Apple, le test d’une chaîne Xcode, la création d’un pool dédié ou l’exploitation d’un nœud accessible à plusieurs fuseaux horaires.
Une fois le pipeline minimal validé, RUVCLOUD peut être envisagé si les critères sont réunis : version Xcode à maintenir, Mac disponible en continu, compte d’exploitation indépendant et séparation stricte des autorisations. Les informations de configuration et de durée doivent être confrontées aux exigences réelles du projet avant de créer le pool définitif ; la décision devient alors une décision d’exploitation documentée, et non une simple réaction à un agent marqué « Online ».