Comment Microsoft développe avec DevOps

Microsoft s’efforce d’utiliser One Engineering System pour créer et déployer tous les produits Microsoft avec un processus DevOps solide centré sur un flux de branchement et de pubication Git. Cet article souligne l’implémentation pratique, la façon dont le système évolue des petits services aux besoins de développement de plateformes massives et les leçons tirées de l’utilisation du système au sein de diverses équipes Microsoft.

L’adoption d’un processus de développement standardisé est un engagement ambitieux. Les exigences des différentes organisations Microsoft varient considérablement, et les exigences des différentes équipes au sein des organisations évoluent avec la taille et la complexité. Pour répondre à ces besoins variés, Microsoft utilise une stratégie de branchement basée sur les jonctions pour aider à développer rapidement des produits, à les déployer régulièrement et à livrer des modifications en toute sécurité à la production.

Microsoft utilise également les principes d’ingénierie de plateforme dans le cadre de son One Engineering System.

Flux de publication Microsoft

Chaque organisation doit adopter un processus de publication de code standard pour assurer la cohérence entre les équipes. Le flux de publication Microsoft intègre les processus DevOps du développement à la publication. Les étapes de base du flux de publication comprennent le branchement, l’envoi, la demande de tirage et la fusion.

Branche

Pour résoudre un bogue ou mettre en œuvre une fonctionnalité, un développeur crée une branche à partir de la branche d’intégration principale. Le modèle de branchement léger Git crée ces branches de rubrique de courte durée pour chaque contribution de code. Les développeurs valident tôt et évitent les branches de fonctionnalités de longue durée en utilisant des indicateurs de fonctionnalité.

Envoi

Lorsque le développeur est prêt à intégrer et à expédier des modifications au reste de l’équipe, il envoie sa branche locale à une branche sur le serveur et ouvre une demande de tirage. Les dépôts comptant plusieurs centaines de développeurs travaillant dans de nombreuses branches utilisent une convention de dénomination pour les branches de serveur afin d'éviter la confusion et la prolifération des branches. Les développeurs créent généralement des branches nommées users/<username>/feature, où <username> est le nom de leur compte.

Demande de tirage

Les demandes de tirage contrôlent les fusions de branchement rubrique dans la branche principale et s'assurent que les stratégies de branche sont satisfaites. Le processus de demande de tirage génère les modifications proposées et exécute une réussite de test rapide. Les suites de tests de premier et deuxième niveau exécutent environ 60 000 tests en moins de cinq minutes. Il ne s'agit pas de la matrice de test Microsoft complète, mais elle est suffisante pour donner rapidement confiance dans les demandes de tirage.

Ensuite, d’autres membres de l’équipe passent en revue le code et approuvent les modifications. La revue du code reprend là où les tests automatisés se sont arrêtés et est particulièrement utile pour détecter les problèmes architecturaux. Les revues de code manuelles garantissent que les autres ingénieurs de l’équipe ont une visibilité sur les modifications et que la qualité du code reste élevée.

Fusionner (Merge)

Une fois que la demande de tirage satisfait à toutes les stratégies de génération et que les réviseurs sont d'accord, la branche rubrique se fusionne dans la branche d’intégration principale et la demande de tirage est terminée.

Après la fusion, d’autres tests d’acceptation s’exécutent qui prennent plus de temps à être terminés. Ces tests post-enregistrement traditionnels effectuent une validation plus approfondie. Ce processus de test fournit un bon équilibre entre avoir des tests rapides pendant la révision des demandes de tirage et avoir une couverture complète des tests avant la publication.

Différences par rapport à GitHub Flow

GitHub Flow est un flux de publication de développement populaire basé sur des jonctions pour les organisations afin de mettre en œuvre une approche évolutive de Git. Cependant, certaines organisations constatent qu’à mesure que leurs besoins augmentent, elles doivent s'écarter de certaines parties du flux GitHub.

Par exemple, une partie souvent négligée de GitHub Flow est que les demandes de tirage doivent être déployées en production pour être testées avant de pouvoir fusionner vers la branche principale. Ce processus signifie que toutes les demandes de tirage attendent dans la file d’attente de déploiement pour la fusion.

Certaines équipes comptent plusieurs centaines de développeurs travaillant en permanence dans un dépôt unique, qui peuvent effectuer plus de 200 demandes de tirage dans la branche principale par jour. Si chaque demande de tirage nécessite un déploiement sur plusieurs centres de données Azure à travers le monde à des fins de test, les développeurs passent du temps à attendre que les branches fusionnent, au lieu d’écrire des logiciels.

Au lieu de cela, les équipes Microsoft continuent de développer dans la branche principale et de regrouper les déploiements en versions chronométrées, généralement alignées sur une cadence de sprint de trois semaines.

Informations d’implémentation

Voici quelques détails d’implémentation clés du flux de publication de Microsoft :

Stratégie de dépôt Git

Différentes équipes ont des stratégies différentes pour gérer leurs dépôts Git. Certaines équipes conservent la majorité de leur code dans un dépôt Git. Le code est divisé en composants, chacun dans son propre dossier de niveau racine. Les composants volumineux, en particulier les composants plus anciens, peuvent avoir plusieurs sous-composants qui ont des sous-dossiers distincts au sein du composant parent.

Screenshot showing a Git repository structure.

Dépôts auxiliaires

Certaines équipes gèrent également les dépôts auxiliaires. Par exemple, les agents de génération et de mise en production et les tâches, l'extension VS Code, et les projets open source sont développés sur GitHub. Les modifications de configuration s’archivent dans un dépôt distinct. D’autres packages dont dépend l’équipe proviennent d’autres endroits et sont consommés via NuGet.

Mono repo ou multi-repo

Bien que certaines équipes choisissent d’avoir un dépôt monolithique unique, les autresproduits Microsoft utilisent une approche multi-repo. Skype, par exemple, a des centaines de petits référentiels qui se rassemblent dans différentes combinaisons pour créer de nombreux clients, services et outils différents. En particulier pour les équipes qui adoptent les microservices, le multi-repo peut être la bonne approche. En règle générale, les produits plus anciens qui ont commencé comme monolithes trouvent une approche mono-dépôt pour être la transition la plus simple vers Git, et leur organisation de code reflète cela.

Branches de publication

Le flux de mise en production de Microsoft conserve la branche principale comme pouvant être générée à tout moment. Les développeurs travaillent dans des branches de rubriques de courte durée qui se fusionnent vers main. Lorsqu’une équipe est prête à être livrée, qu’elle soit à la fin d’un sprint ou pour une mise à jour majeure, elle démarre une nouvelle branche de mise en production hors de la branche principale. Les branches de mise en production ne se fusionnent jamais vers la branche principale, de sorte qu’elles peuvent nécessiter le picorage de modifications importantes.

Le diagramme suivant montre les branches de courte durée en bleu et les branches de production en noir. Une branche avec une validation qui a besoin de picorage apparaît en rouge.

Diagram showing Git release branch structure.

Stratégies et autorisations de branche

Les stratégies de branche Git aident à appliquer la structure de branche de mise en production et à garder la branche principale nette. Par exemple, les stratégies de branche peuvent empêcher les envois directs vers la branche principale.

Pour conserver la hiérarchie des branches, les équipes utilisent des autorisations pour bloquer la création de branche au niveau racine de la hiérarchie. Dans l’exemple suivant, tout le monde peut créer des branches dans des dossiers tels que des utilisateurs/, des fonctionnalités/, et des équipes/. Seuls les gestionnaires de versions ont l’autorisation de créer des branches sous versions/, et certains outils d’automatisation ont l’autorisation d’accéder au dossier/ intégrations.

Screenshot that shows branches.

Flux de travail du dépôt Git

Dans le dépôt et la structure de branche, les développeurs effectuent leur travail quotidien. Les environnements de travail varient considérablement par équipe et par individu. Certains développeurs préfèrent la ligne de commande, d’autres aiment Visual Studio et d’autres travaillent sur différentes plateformes. Les structures et les stratégies en place sur les dépôts Microsoft garantissent une base solide et cohérente.

Un flux de travail classique implique les tâches courantes suivantes :

Créer une nouvelle fonctionnalité

La création d’une nouvelle fonctionnalité est la base du travail d’un développeur de logiciels. Les parties non Git du processus incluent l’analyse des données de télémétrie, la conception et une spécification, et l’écriture du code réel. Ensuite, le développeur commence à utiliser le dépôt en se synchronisant avec la dernière validation sur main. La branche principale est toujours constructible, donc elle est garantie d’être un bon point de départ. Le développeur extrait une nouvelle branche de fonctionnalité, apporte des modifications de code, valide, envoie au serveur et démarre une nouvelle demande de tirage.

Utiliser des stratégies de branche et des vérifications

Lors de la création d’une demande de tirage, les systèmes automatisés vérifient que le nouveau code est généré, n’interrompt rien et ne viole aucune stratégie de sécurité ou de conformité. Ce processus ne empêche pas d’autres tâches de se produire en parallèle.

Les stratégies de branche et les vérifications peuvent nécessiter un build réussi, y compris les tests réussis, la signature des propriétaires de n’importe quel code touché et plusieurs vérifications externes pour vérifier les stratégies d’entreprise avant qu’une demande de tirage puisse être effectuée.

Screenshot showing the checks on a pull request.

Intégration avec Microsoft Teams

De nombreuses équipes configurent l’intégration à Microsoft Teams, qui annonce la nouvelle demande de tirage aux collègues des développeurs. Les propriétaires de tout code touché sont automatiquement ajoutés en tant que réviseurs. Les équipes Microsoft utilisent souvent des réviseurs facultatifs pour le code que de nombreuses personnes touchent, comme la génération de clients REST et les contrôles partagés, pour obtenir des yeux d’experts sur ces modifications.

Screenshot showing Teams integration.

Screenshot showing Teams notification of a pull request.

Déployer avec des indicateurs de fonctionnalité

Une fois que les réviseurs, les propriétaires de code et l’automatisation sont satisfaits, le développeur peut terminer la demande de tirage. S’il existe un conflit de fusion, le développeur obtient des instructions sur la façon de synchroniser le conflit, de le corriger et d'envoyer à nouveau les modifications. L’automatisation s’exécute à nouveau sur le code fixe, mais les humains n’ont pas à approuver de nouveau.

La branche se fusionne dans main, et le nouveau code se déploie dans le sprint ou la version majeure suivante. Cela ne signifie pas que la nouvelle fonctionnalité s’affiche immédiatement. Microsoft dissocie le déploiement et l’exposition de nouvelles fonctionnalités à l’aide d’indicateurs de fonctionnalité.

Même si la fonctionnalité a besoin d’un peu plus de travail avant qu’elle ne soit prête à s’afficher, il peut être testé en toute sécurité main si le produit génère et déploie. Une fois dans main, le code fait partie d’une build officielle, où il est à nouveau testé, confirmé pour répondre à la stratégie et signé numériquement.

Déplacer vers la gauche pour détecter les problèmes tôt

Ce flux de travail Git offre plusieurs avantages. Tout d’abord, l’utilisation d’une seule branche principale élimine virtuellement la dette de fusion. Deuxièmement, le flux de demande de tirage fournit un point commun pour appliquer les tests, la révision du code et la détection des erreurs au début du pipeline. Cette stratégie de décalage gauche permet de raccourcir le cycle de commentaires aux développeurs, car il peut détecter les erreurs en minutes, pas en heures ou en jours. Cette stratégie donne également confiance en la refactorisation, car toutes les modifications sont testées constamment.

Actuellement, un produit avec des demandes de tirage de 200+ peut produire 300 builds d’intégration continue par jour, ce qui représente 500 exécutions de tests toutes les 24 heures. Ce niveau de test serait impossible sans le flux de travail de branchement et de mise en production basés sur la jonction.

Mise en production lors des étapes de sprint

À la fin de chaque sprint, l’équipe crée une branche de mise en production à partir de la branche principale. Par exemple, à la fin du sprint 129, l’équipe crée une nouvelle branche releases/M129. L’équipe place ensuite la branche sprint 129 en production.

Après la branche de la version branche, la branche principale reste ouverte aux développeurs pour fusionner les modifications. Ces modifications seront déployées trois semaines plus tard dans le prochain déploiement sprint.

Illustration of the release branch at sprint 129.

Version de correctifs logiciels

Parfois, les modifications doivent passer rapidement en production. Microsoft n’ajoute généralement pas de nouvelles fonctionnalités au milieu d’un sprint, mais souhaite parfois apporter rapidement un correctif de bogue pour débloquer les utilisateurs. Les problèmes peuvent être mineurs, tels que les fautes de frappe ou suffisamment volumineuses pour provoquer un problème de disponibilité ou un incident de site en direct.

La correction de ces problèmes commence par le flux de travail normal. Un développeur crée une branche à partir de main, obtient l'examen du code, et termine la demande de tirage pour la fusionner. Le processus commence toujours par apporter la modification en main d'abord. Cela permet de créer rapidement et de valider le correctif localement sans avoir à basculer vers la branche de mise en production.

Le suivi de ce processus garantit également que la modification est apportée main, ce qui est essentiel. La correction d’un bogue dans la branche de publication sans ramener la modification à main signifierait que le bogue se reproduirait lors du prochain déploiement, lorsque le sprint 130 publie des branches à partir de main. Il est facile d’oublier de mettre à jour main pendant la confusion et le stress qui peuvent survenir lors d'une panne. Le fait d’apporter des modifications main au préalable signifie toujours avoir les modifications à la fois dans la branche principale et dans la branche de mise en production.

La fonctionnalité Git active ce flux de travail. Pour apporter immédiatement des modifications en production, une fois qu’un développeur fusionne une demande mainde tirage, il peut utiliser la page de demande de tirage pour sélectionner les modifications dans la branche de mise en production. Ce processus crée une nouvelle demande de tirage qui cible la branche de mise en production, en rétroportant le contenu qui vient d’être fusionné dans main.

Illustration of cherry-picking a hotfix commit into branch 129.

L’utilisation de la fonctionnalité de picorage ouvre rapidement une demande de tirage en fournissant la traçabilité et la fiabilité des stratégies de branche. Le picorage peut se produire sur le serveur, sans avoir à télécharger la branche de mise en production sur un ordinateur local. Apporter des modifications, résoudre des conflits de fusion ou apporter des modifications mineures en raison de différences entre les deux branches peuvent tous se produire sur le serveur. Les équipes peuvent modifier les modifications directement à partir de l’éditeur de texte basé sur le navigateur ou via l’extension de conflit de fusion de demande de tirage pour une expérience plus avancée.

Une fois qu’une demande de tirage cible la branche de mise en production, l’équipe de code l’examine à nouveau, évalue les stratégies de branche, teste la demande de tirage et la fusionne. Après la fusion, le correctif est déployé sur le premier anneau de serveurs en minutes. À partir de là, l’équipe déploie progressivement le correctif sur davantage de comptes à l’aide d’anneaux de déploiement. Au fur et à mesure que les modifications sont déployées auprès d’un plus grand nombre d'utilisateurs, l’équipe surveille le succès et vérifie que la modification corrige le bogue sans introduire de carences ou de ralentissements. Le correctif se déploie finalement sur tous les centres de données Azure.

Passer au sprint suivant

Au cours des trois prochaines semaines, l’équipe finit d’ajouter des fonctionnalités au sprint 130 et se prépare à déployer ces modifications. Ils créent la branche de mise en production à releases/M130 partir de mainet déploient cette branche.

À ce stade, il y a en fait deux branches en production. Avec un déploiement en anneau pour apporter des modifications en production en toute sécurité, l’anneau rapide obtient les 130 modifications sprint et les serveurs d’anneau lent restent sur sprint 129 alors que les nouvelles modifications sont validées en production.

Appliquer un correctif logiciel à une modification au milieu d’un déploiement peut nécessiter deux mises en production différentes, la version sprint 129 et la version sprint 130. L’équipe porte et déploie le correctif logiciel sur les deux branches de publication. La branche 130 se redéploie avec le correctif logiciel sur les anneaux qui ont déjà été mis à niveau. La branche 129 se redéploie avec le correctif logiciel sur les anneaux externes qui n’ont pas encore été mis à niveau vers la version du sprint suivant.

Une fois que tous les anneaux sont déployés, l’ancienne branche sprint 129 est abandonnée, car toutes les modifications apportées à la branche sprint 129 en tant que correctif logiciel ont également été apportées dans main. Ainsi, ces modifications seront également dans la releases/M130 branche.

Illustration of a release branch at sprint 130.

Résumé

Le modèle de flux de publication est au cœur de la façon dont Microsoft développe avec DevOps pour livrer des services en ligne. Ce modèle utilise une stratégie de branchement simple basée sur les jonctions. Mais au lieu de maintenir les développeurs coincés dans une file d’attente de déploiement, en attendant de fusionner leurs modifications, le flux de publication Microsoft permet aux développeurs de continuer à travailler.

Ce modèle de publication permet également de déployer de nouvelles fonctionnalités dans les centres de données Azure à un rythme régulier, malgré la taille des bases de code Microsoft et le nombre de développeurs qui y travaillent. Le modèle permet également d’introduire rapidement et efficacement des correctifs logiciels dans la production.