Votre pipeline iOS attend, les certificats sont exposés et le Runner disparaît après un redémarrage : vous avez probablement déployé un Mac partagé comme un serveur généraliste.

La solution la plus rapide consiste à utiliser un GitLab Runner macOS dédié aux projets de confiance, à commencer par un seul nœud pilote, puis à augmenter la capacité selon la file d’attente, la concurrence et les résultats de reprise.

01

À qui s’adresse ce guide ?

Vous préparez la migration d’un projet iOS vers GitLab CI/CD et devez ajouter un Runner macOS exploitable par une équipe plateforme.

Vous devez aussi encadrer les certificats de signature, l’accès réseau et les droits locaux, tout en arbitrant entre Mac acheté, Mac loué ou configuration hybride.

02

Le périmètre du nœud

Un GitLab Runner macOS n’est pas un simple agent interchangeable. Il exécute des scripts contrôlés par les dépôts qui lui sont accessibles. Avec le Shell executor, ces scripts s’exécutent directement sur le système hôte et avec les droits du compte du Runner. GitLab considère donc ce mode comme présentant un risque élevé et recommande de le réserver aux builds de confiance. (documentation GitLab sur la sécurité des Runners)

Avant toute installation, classez vos projets dans trois catégories :

  • Projets de confiance : dépôts internes, contrôlés par votre équipe et soumis à une revue des modifications CI.
  • Projets de test : branches expérimentales, dépendances externes ou scripts encore instables.
  • Projets de publication : pipelines capables d’utiliser des certificats de distribution, des profils de provisioning ou des secrets de livraison.

Le premier nœud doit uniquement accepter la première catégorie. Les tâches de publication doivent ensuite être placées sur un nœud séparé, protégé par des branches et des étiquettes protégées. Cette séparation est plus importante que le nombre de développeurs : deux équipes peuvent partager un nœud de test, mais un nœud contenant les identités de signature ne devrait pas être ouvert à tous les dépôts.

Achat, location ou configuration hybride

La décision dépend surtout de la stabilité de la charge et de votre capacité à intervenir physiquement sur le matériel. GitLab Runner est disponible sur Mac Intel et Apple Silicon ; le choix de l’architecture doit donc suivre vos versions de Xcode, vos dépendances et vos contraintes de compatibilité, pas uniquement la puissance théorique du processeur. (installation officielle de GitLab Runner sur macOS)

Option Pertinente si Limites à prévoir
Mac acheté sur site Charge stable, exigences de contrôle physique, présence d’une équipe locale Immobilisation, remplacement matériel, espace, réseau et maintenance
Mac distant loué Pilote rapide, charge irrégulière, équipe distribuée ou besoin d’un nœud supplémentaire Dépendance à la connectivité, validation du support et du processus de récupération
Configuration hybride Nœud permanent pour les publications et capacité distante pour les pics Gouvernance plus complexe, plusieurs profils de sécurité et de supervision

Pour estimer le coût total de possession, utilisez une formule qui sépare clairement les variables :

TCO annuel = acquisition ou loyers + maintenance + administration + stockage + réseau + temps d’intervention + coût des interruptions.

Ne remplissez pas cette formule avec un prix théorique. Utilisez vos factures, le temps moyen passé sur les incidents et le nombre réel de builds. Une solution de Mac distant pour les équipes techniques peut servir de capacité pilote, mais elle doit être comparée avec le coût complet d’un Mac acheté, et non avec son seul prix d’achat.

03

La préparation macOS

Le compte d’exécution

Créez un compte macOS dédié au Runner. Il ne doit pas être le compte administrateur utilisé pour les opérations quotidiennes. En revanche, il doit disposer de la session utilisateur nécessaire à l’exécution d’un simulateur iOS et à l’accès contrôlé au trousseau de clés.

Sur macOS, GitLab Runner fonctionne comme un LaunchAgent en mode utilisateur, et non comme un LaunchDaemon système. Il démarre lorsque l’utilisateur se connecte et s’arrête lorsqu’il se déconnecte. GitLab indique également que la session utilisateur est nécessaire pour accéder au trousseau et à l’interface utilisée par le simulateur et la signature. (conditions d’exécution macOS documentées par GitLab)

Cela crée une contrainte souvent oubliée : un redémarrage ne suffit pas à garantir le retour du Runner. Vous devez tester la connexion automatique du compte, le démarrage de la session graphique et la présence du Runner dans GitLab après le redémarrage.

Le réseau et les accès d’administration

Préparez ensuite :

  1. Une sortie réseau vers votre instance GitLab et vers les dépôts nécessaires.
  2. Une règle limitant les connexions entrantes au chemin d’administration retenu.
  3. Un accès de secours documenté, par exemple via VNC, SSH ou une console distante.
  4. Un journal des changements de configuration.
  5. Une procédure de révocation du jeton d’authentification du Runner.

GitLab recommande de segmenter le réseau des Runners, de limiter les accès SSH depuis Internet et de filtrer les communications entre nœuds lorsque cela est possible. Un Runner doit pouvoir récupérer le code et les dépendances, mais il ne devrait pas avoir une visibilité inutile sur les systèmes internes.

Chiffrement et socle logiciel

Activez FileVault et conservez la clé de récupération dans un emplacement distinct du disque chiffré. Apple précise que FileVault protège les données du volume et que la récupération doit être planifiée séparément ; pour les Mac Apple Silicon récents, Apple recommande notamment l’usage d’une clé de récupération personnelle plutôt qu’une ancienne clé institutionnelle. (documentation Apple sur la gestion de FileVault)

Installez ensuite les outils dans un ordre reproductible :

  1. Vérifiez la version de macOS et l’architecture du Mac.
  2. Installez le binaire GitLab Runner correspondant à Apple Silicon ou Intel.
  3. Installez Xcode et les outils de ligne de commande.
  4. Exécutez l’initialisation nécessaire avec xcodebuild.
  5. Fixez les versions de Ruby, Swift Package Manager, CocoaPods ou autres dépendances utilisées par vos projets.
  6. Exportez un inventaire de référence avant de lancer le premier pipeline.

La procédure macOS de GitLab couvre notamment la préparation du shell, les dépendances, Xcode, l’enregistrement du Runner et sa configuration.

04

L’enregistrement du Runner

Portée et routage

Lors de l’enregistrement, choisissez la portée la plus étroite compatible avec votre organisation :

  • Runner de projet pour un premier pilote ou un dépôt sensible.
  • Runner de groupe lorsque plusieurs projets d’une même équipe partagent le même niveau de confiance.
  • Runner d’instance uniquement si vous maîtrisez tous les projets susceptibles de l’utiliser.

GitLab distingue ces trois portées et utilise les étiquettes pour orienter les jobs vers les environnements appropriés. (modèle officiel de portée et d’enregistrement des Runners)

Un profil de départ peut utiliser des étiquettes comme :

tags:
  - macos
  - apple-silicon
  - xcode-release

Le nom des étiquettes doit décrire une capacité vérifiable. Évitez les termes vagues comme fast ou default. Une étiquette telle que xcode-release doit correspondre à un nœud qui possède réellement la version de Xcode, les certificats et les contrôles nécessaires à la publication.

Le choix de l’executor

Pour un build iOS ou macOS natif, le Shell executor est le choix opérationnel habituel sur un Mac, car il permet d’appeler directement xcodebuild, le simulateur et les outils du système. La documentation macOS de GitLab le présente comme adapté aux builds iOS et macOS.

Son avantage est aussi sa limite : il n’existe pas de barrière forte entre deux jobs exécutés sur le même hôte. Un script peut lire des fichiers résiduels, modifier l’environnement ou exploiter les droits du compte Runner. Le Shell executor doit donc rester réservé à des dépôts fiables, avec répertoires de travail nettoyés et projets soigneusement séparés.

05

Le premier pipeline

Commencez par une pipeline volontairement courte. Son objectif n’est pas encore de reproduire toute la publication, mais de valider le chemin complet.

stages:
  - verification
  - construction

variables:
  LC_ALL: "en_US.UTF-8"

verification:
  stage: verification
  tags:
    - macos
  script:
    - whoami
    - sw_vers
    - xcodebuild -version
    - xcode-select -p

construction:
  stage: construction
  tags:
    - macos
  script:
    - bundle exec pod install
    - xcodebuild -scheme "VotreScheme" -configuration Release build
  artifacts:
    when: always
    paths:
      - build/

Adaptez les commandes à votre dépôt. Le point important est de produire une preuve sur chaque étape :

  • le code est récupéré par le Runner ;
  • les dépendances sont installées dans un environnement connu ;
  • Xcode répond avec la version attendue ;
  • la compilation se termine ;
  • les tests et les journaux sont conservés ;
  • les artefacts sont accessibles depuis GitLab.

Ajoutez ensuite le cache avec prudence. Le cache peut accélérer les dépendances, mais un cache partagé entre projets peut révéler des fichiers ou introduire des états difficiles à reproduire. Pour un premier pilote, préférez un cache lié au projet et au fichier de verrouillage. Si vous utilisez fetch ou un répertoire de travail persistant, documentez précisément ce qui est supprimé après chaque job.

GitLab recommande également le nettoyage du répertoire de build sur les hôtes statiques afin de limiter les résidus entre pipelines. (recommandations GitLab pour les hôtes Shell)

06

La signature iOS

Séparer construction et publication

Ne placez pas automatiquement les certificats de distribution sur le premier Runner. Un nœud de compilation ordinaire peut construire, tester et générer un artefact non signé ou signé avec des identités limitées. Le nœud de publication doit être plus restreint, avec une portée GitLab réduite et des jobs déclenchés uniquement par une branche ou une étiquette protégée.

Apple définit le profil de provisioning comme un mécanisme qui lie notamment l’identité de signature, l’application, la destination et les droits autorisés. Un certificat seul ne constitue donc pas une stratégie complète de contrôle. (note technique Apple sur les profils de provisioning)

Injecter puis supprimer les secrets

Pour une signature automatisée :

  1. Stockez les secrets dans les variables CI/CD protégées et masquées.
  2. Importez temporairement le certificat dans un trousseau dédié.
  3. Déverrouillez ce trousseau uniquement pendant le job concerné.
  4. Installez le profil de provisioning dans le répertoire attendu par Xcode.
  5. Lancez xcodebuild avec une configuration explicitement sélectionnée.
  6. Supprimez le trousseau temporaire, le profil et les fichiers intermédiaires.
  7. Vérifiez que les journaux ne contiennent ni mot de passe ni contenu de certificat.

Apple documente l’import d’une identité de signature dans le trousseau de l’utilisateur et la nécessité de disposer du certificat ainsi que de la clé privée correspondante.

Ne transmettez jamais une identité de signature dans un artefact de build. Si plusieurs équipes utilisent le même Mac, la séparation par répertoire ne suffit pas à elle seule : le compte, les étiquettes, les branches protégées et la suppression des secrets doivent fonctionner ensemble.

07

La première semaine d’exploitation

Le redémarrage sans intervention

Planifiez un test qui simule une maintenance réelle :

  1. Arrêtez les jobs en cours.
  2. Redémarrez le Mac.
  3. Vérifiez le déverrouillage du volume selon votre procédure.
  4. Contrôlez la connexion automatique du compte dédié.
  5. Vérifiez que le LaunchAgent est chargé.
  6. Lancez un pipeline de diagnostic.
  7. Lancez ensuite un build complet avec signature de test.
  8. Documentez le délai et chaque intervention nécessaire.

La commande gitlab-runner install crée le fichier ~/Library/LaunchAgents/gitlab-runner.plist, tandis que la configuration se trouve dans ~/.gitlab-runner/config.toml. Les journaux standard sont également placés dans le répertoire de journaux de l’utilisateur.

Un Runner affiché comme « en ligne » dans GitLab ne suffit pas comme preuve de reprise. Vous devez confirmer l’accès à Xcode, au trousseau, au simulateur, au dépôt et aux dépendances.

La liste de décisions

Utilisez les conditions suivantes avant de passer en production :

  • Si le Runner accepte uniquement des dépôts de confiance, alors vous pouvez conserver le Shell executor ; sinon, revenez à une architecture séparant les projets sensibles et non sensibles.
  • Si le compte utilisateur se reconnecte et que le Runner revient après redémarrage, alors poursuivez le pilote ; sinon, bloquez la mise en production et corrigez le LaunchAgent ou le parcours de déverrouillage.
  • Si les certificats de publication sont absents du nœud de test, alors vous pouvez l’ouvrir à un groupe plus large ; sinon, créez un nœud de publication séparé.
  • Si les files d’attente augmentent pendant plusieurs cycles de mesure, alors ajoutez un nœud ou une capacité temporaire ; sinon, n’achetez pas de matériel supplémentaire par anticipation.
  • Si plusieurs versions de Xcode doivent coexister, alors regroupez les Runners par version validée ; sinon, limitez le nœud à une version de référence.
  • Si votre équipe ne peut pas assurer le dépannage physique ou la récupération après redémarrage, alors privilégiez un Mac distant avec accès d’administration documenté.
08

L’extension de capacité

Le nombre de Mac nécessaires ne se déduit pas directement du nombre de développeurs. Mesurez plutôt :

  • le temps d’attente avant prise en charge ;
  • la durée médiane et la durée maximale des builds ;
  • le nombre de jobs simultanés ;
  • le taux d’échec par version de Xcode ;
  • la croissance du stockage ;
  • le temps d’indisponibilité lors d’une mise à jour ;
  • la fréquence des publications.

Créez ensuite des groupes de nœuds selon trois axes : version de Xcode, niveau de sensibilité et capacité de publication. Un seul grand pool paraît simple, mais il recrée rapidement le risque qu’un job ordinaire arrive sur un hôte contenant des secrets.

La location périodique d’un Mac distant devient intéressante lorsque les pics sont liés à une campagne de publication, à une migration Xcode ou à une montée temporaire de l’activité. Une capacité permanente achetée est plus cohérente si la charge est stable, si le réseau local est mieux maîtrisé et si vous disposez d’un processus de remplacement matériel.

Pour explorer un nœud Apple Silicon distant sans engager immédiatement tout votre parc, vous pouvez examiner les options de Mac mini Apple Silicon.

Votre coût de comparaison doit inclure le temps de configuration, les certificats, le stockage, l’administration, la supervision et la récupération après panne. Une solution moins chère sur le papier peut devenir plus coûteuse si chaque incident exige une intervention manuelle.

09

Le choix de production

Après le pilote, conservez les preuves suivantes :

  • un build réussi avec tests et artefacts ;
  • une signature de test reproductible ;
  • une publication limitée à une branche protégée ;
  • un nettoyage confirmé après job ;
  • un redémarrage réussi sans intervention non documentée ;
  • une procédure de révocation du jeton Runner ;
  • une estimation de capacité fondée sur la file d’attente ;
  • une procédure de retour arrière pour Xcode et les dépendances.

Si votre environnement actuel repose sur des Mac personnels, vous supportez généralement des versions divergentes de Xcode, des trousseaux difficiles à auditer et des interruptions liées aux absences. Si vous achetez toute la capacité dès le départ, vous immobilisez du matériel avant de connaître la charge réelle et vous ajoutez la maintenance locale.

Une location de Mac distant via KVMNODE peut offrir un meilleur compromis pour un pilote, une période de surcharge ou une équipe sans capacité d’intervention sur site, à condition de valider la sécurité, la récupération et la durée d’accès dans votre propre pipeline.

La bonne décision n’est donc pas de choisir définitivement entre achat et location avant le premier test. Lancez un pilote sur un nœud dédié, mesurez la file d’attente et le redémarrage, puis ajustez le nombre de Mac et la durée de location selon vos données réelles.