Share via


DevOps

Conseil

Ce contenu est un extrait du livre électronique, Cloud Native .NET apps for Azure (Architecture d’applications .NET natives cloud pour Azure), disponible dans la documentation .NET ou au format PDF à télécharger gratuitement pour le lire hors connexion.

Cloud Native .NET apps for Azure eBook cover thumbnail.

La réponse consacrée des consultants logiciels est « Cela dépend », quelle que soit la question posée. Ce n’est pas parce que les consultants logiciels adorent ne pas prendre position. C’est parce qu’il n’y a pas qu’une seule réponse à chaque question en matière de logiciel. Ce n’est pas tout l’un ou tout l’autre, mais plutôt un équilibre entre les deux.

Prenons, par exemple, les deux principales écoles de développement d’applications web : applications monopages (SPA) ou applications côté serveur. D’un côté, l’expérience utilisateur tend à être meilleure avec les applications monopages et la quantité de trafic vers le serveur web peut être réduite, ce qui permet de les héberger sur quelque chose d’aussi simple qu’un hébergement statique. D’un autre côté, les applications monopages ont tendance à être plus longues à développer et plus difficiles à tester. Quel est le bon choix ? Cela dépend de votre situation.

Les applications natives cloud ne sont pas épargnées par cette même dichotomie. Elles ont des avantages clairs en termes de vitesse de développement, de stabilité et de scalabilité, mais leur gestion peut être un peu plus difficile.

Il y a quelques années, il n’était pas rare que le processus de faire passer une application du développement en production prenne un mois, voire plus. Les entreprises publiaient les logiciels tous les 6 mois ou même tous les ans. Inutile d’aller chercher plus loin que Microsoft Windows pour avoir une idée de la cadence des versions qui étaient acceptables avant l’ère, toujours d’actualité, de Windows 10. Cinq ans se sont écoulés entre Windows XP et Vista, trois autres entre Vista et Windows 7.

Il est maintenant plutôt bien établi qu’être en mesure de publier rapidement des logiciels donne aux entreprises très réactives un énorme avantage sur le marché par rapport à leurs concurrents plus lents. C’est pour cette raison que les principales mises à jour de Windows 10 ont maintenant lieu tous les six mois environ.

Les modèles et pratiques qui permettent d’avoir des versions plus rapides et plus fiables pour apporter de la valeur à l’entreprise répondent au nom de DevOps. Il englobe un large éventail de concepts couvrant l’ensemble du cycle de vie du développement logiciel, de la spécification d’une application jusqu’à sa livraison et à son exploitation.

DevOps est apparu avant les microservices et il est probable que le passage à des services plus petits et plus adaptés n’aurait pas été possible sans DevOps qui a rendu la publication et l’exploitation plus facile pas seulement d’une, mais de nombreuses applications en production.

Figure 10-1 Search trends show that the growth in microservices doesn't start until after DevOps is a fairly well-established idea.

Figure 10-1 - DevOps et microservices.

Grâce aux bonnes pratiques de DevOps, il est possible de tirer parti des avantages des applications natives cloud sans suffoquer sous une montagne de travail qui permet de faire fonctionner les applications.

Avec DevOps, il n’y pas de loi du marteau. Personne ne peut vendre une solution complète et globale pour la publication et l’exploitation d’applications de haute qualité. C’est parce que toutes les applications sont très différentes les unes des autres. Toutefois, il existe des outils qui peuvent faire de DevOps une proposition beaucoup moins intimidante. L’un de ces outils s’appelle Azure DevOps.

Azure DevOps

Azure DevOps remonte à loin. Il trouve ses racines lorsque Team Foundation Server a été publié en ligne pour la première fois, et depuis renommé plusieurs fois : Visual Studio Online, puis Visual Studio Team Services. Au fil des ans toutefois, il est devenu bien plus que ses prédécesseurs.

Azure DevOps s’articule autour de cinq principaux composants :

Figure 10-2 The five major areas of Azure DevOps

Figure 10-2 - Azure DevOps.

Azure Repos - Gestion du code source qui prend en charge le vénérable TFVC (Team Foundation Version Control) et le favori du secteur Git. Les demandes de tirage offrent un moyen d’activer le codage social en encourageant des discussions sur les modifications à mesure qu’elles sont apportées.

Azure Boards - Offre un outil de suivi des problèmes et des éléments de travail qui s’efforce de permettre aux utilisateurs de choisir les workflows qui fonctionnent le mieux pour eux. Il est fourni avec un certain nombre de modèles préconfigurés, notamment ceux qui prennent en charge les styles de développement SCRUM et Kanban.

Azure Pipelines - Système de gestion de build et de mise en production qui prend en charge une intégration étroite avec Azure. Les builds peuvent être exécutées sur différentes plateformes de Windows à Linux et à macOS. Les agents de build peuvent être provisionnés dans le cloud ou localement.

Azure Test Plans - Aucune personne responsable de l’assurance qualité n’est laissée pour compte avec la gestion des tests et la prise en charge des tests exploratoires qu’offre la fonctionnalité Test Plans.

Azure Artifacts - Flux d’artefacts qui permet aux entreprises de créer leurs propres versions internes de NuGet, npm et autres. Il sert un double objectif de faire office de cache de packages en amont en cas de défaillance d’un dépôt centralisé.

L’unité d’organisation de niveau supérieur dans Azure DevOps est appelée Projet. Dans chaque projet, les différents composants comme Azure Artifacts peuvent être activés et désactivés. Chacun de ces composants offre différents avantages pour les applications natives cloud. Les trois plus utiles sont les dépôts, les tableaux et les pipelines. Si les utilisateurs souhaitent gérer leur code source dans une autre pile de dépôts comme GitHub tout en tirant quand même parti d’Azure Pipelines et d’autres composants, c’est parfaitement possible.

Heureusement, les équipes de développement disposent de nombreuses options lorsqu’elles sélectionnent un dépôt. L’un d’eux est GitHub.

GitHub Actions

Fondé en 2009, GitHub est un dépôt web très répandu pour héberger des projets, de la documentation et du code. Nombreuses sont les grandes entreprises technologiques, comme Apple, Amazon, Google et autres grandes entreprises connues, qui utilisent GitHub. GitHub utilise le système de gestion de versions distribué open source Git comme base. Par-dessus, il ajoute ensuite son propre ensemble de fonctionnalités, notamment le suivi des défauts, les demandes de fonctionnalité et de tirage, la gestion des tâches et les wikis pour chaque codebase.

À mesure que GitHub évolue, il ajoute également des fonctionnalités DevOps. Par exemple, GitHub a son propre pipeline d’intégration continue/livraison continue (CI/CD), appelé GitHub Actions. GitHub Actions est un outil d’automatisation de workflow alimenté par la communauté. Il permet aux équipes DevOps d’intégrer leurs outils existants, de mélanger et d’associer de nouveaux produits, et d’accéder à leur cycle de vie logiciel, notamment aux partenaires CI/CD existants.

GitHub compte plus de 40 millions d’utilisateurs, ce qui en fait le plus grand hébergeur de code source au monde. En octobre 2018, Microsoft a fait l’acquisition de GitHub. Microsoft s’est engagé à ce que GitHub reste une plateforme ouverte que tout développeur peut utiliser et étendre. Il continue de fonctionner en tant que société indépendante. GitHub propose les forfaits Entreprise, Équipe et Gratuit.

Contrôle de code source

L’organisation du code pour une application native cloud peut être difficile. Au lieu d’être une seule application gigantesque, les applications natives cloud tendent à être constituées d’applications web plus petites qui communiquent entre elles. Comme pour tout en informatique, la meilleure organisation du code reste une question ouverte. Il existe des exemples d’applications réussies qui utilisent différents types de présentations, mais deux variantes semblent se détacher du lot.

Avant de « plonger » dans le contrôle de code source proprement dit, il est probablement judicieux de décider du nombre de projets appropriés. Au sein d’un seul projet, plusieurs dépôts et pipelines de build sont pris en charge. Les tableaux sont un peu plus compliqués, mais ici aussi, les tâches peuvent facilement être assignées à plusieurs équipes au sein d’un même projet. Il est possible de prendre en charge des centaines, voire des milliers de développeurs, d’un seul projet Azure DevOps. C’est probablement la meilleure approche, car elle fournit un emplacement unique où travaillent tous les développeurs et réduit la confusion de rechercher une application en particulier lorsque les développeurs ne sont pas sûrs du projet dans lequel elle réside.

Le découpage du code pour les microservices au sein du projet Azure DevOps peut être légèrement plus délicat.

Figure 10-3 Single versus Multiple Repositories

Figure 10-3 - Un versus plusieurs dépôts.

Dépôt par microservice

À première vue, cette approche semble être l’approche la plus logique pour découper le code source pour les microservices. Chaque dépôt peut contenir le code nécessaire pour créer le microservice. Les avantages de cette approche sont tout de suite visibles :

  1. Des instructions pour la création et la maintenance de l’application peuvent être ajoutées à un fichier README à la racine de chaque dépôt. Lorsque vous parcourez les dépôts, il est facile de trouver ces instructions, ce qui réduit le temps de défilement pour les développeurs.
  2. Chaque service se trouve dans un emplacement logique, qu’il est facile de trouver si vous connaissez le nom du service.
  3. Les builds peuvent facilement être configurées afin qu’elles soient déclenchées uniquement lorsqu’une modification est apportée au dépôt propriétaire.
  4. Le nombre de modifications apportées à un dépôt est limité au petit nombre de développeurs travaillant sur le projet.
  5. La sécurité est facile à configurer en limitant les dépôts pour lesquels les développeurs ont des autorisations de lecture et d’écriture.
  6. Les paramètres au niveau du dépôt peuvent être modifiés par l’équipe propriétaire avec un minimum de discussions avec d’autres personnes.

L’une des idées clés derrière les microservices est que les services doivent être cloisonnés et séparés les uns des autres. Lorsque vous utilisez une conception pilotée par le domaine pour décider des limites des services, les services font office de limites transactionnelles. Les mises à jour de base de données ne doivent pas englober plusieurs services. Cette collection de données associées est appelée contexte délimité. Cette idée se traduit par l’isolement des données du microservice dans une base de données distincte et autonome du reste des services. Il est vraiment très judicieux de porter cette idée jusqu’au code source.

Toutefois, cette approche n’est pas sans problèmes. L’un des plus épineux problèmes de développement de notre temps est la gestion des dépendances. Pensez au nombre de fichiers qui composent le répertoire node_modules moyen. Une nouvelle installation de quelque chose comme create-react-app est susceptible d’apporter avec lui des milliers de packages. La question de la gestion de ces dépendances fait partie des questions difficiles.

Si une dépendance est mise à jour, les packages en aval doivent également mettre à jour cette dépendance. Malheureusement, cela demande du travail de développement donc, invariablement, le répertoire node_modules se retrouve avec plusieurs versions d’un seul package, chacune étant une dépendance d’un autre package qui est versionné à une cadence légèrement différente. Lors du déploiement d’une application, quelle version d’une dépendance doit être utilisée ? La version qui est actuellement en production ? La version qui est actuellement en version bêta, mais qui est susceptible d’être en production avant que le consommateur ne la mette en production ? Problèmes difficiles qui ne sont pas résolus juste en utilisant des microservices.

Il existe des bibliothèques qui dépendent d’un large choix de projets. En divisant les microservices avec un dans chaque dépôt, les dépendances internes peuvent être le mieux résolues en utilisant le dépôt interne, Azure Artifacts. Les builds pour les bibliothèques poussent leurs dernières versions dans Azure Artifacts pour une consommation interne. Le projet en aval doit quand même être mis à jour manuellement pour prendre une dépendance sur les packages nouvellement mis à jour.

Un autre inconvénient se présente lorsque le code passe d’un service à l’autre. Même si ce serait bien commode de penser que le premier découpage d’une application en microservices est correcte à 100 %, la réalité est que nous sommes rarement clairvoyants au point de ne commettre aucune erreur dans le découpage. Par conséquent, les fonctionnalités et le code qui les pilote doivent passer d’un service à l’autre : d’un dépôt à l’autre. Lorsque vous sautez d’un dépôt à un autre, le code perd son historique. Nombreux sont les cas, en particulier en cas d’audit, où l’historique complet d’un élément de code est inestimable.

Le dernier inconvénient et le plus important est la coordination des changements. Dans une véritable application de microservices, il ne doit y avoir aucune dépendance de déploiement entre les services. Il doit être possible de déployer les services A, B et C dans n’importe quel ordre, car ils ont un couplage faible. Toutefois, il est parfois souhaitable d’apporter une modification qui traverse plusieurs dépôts en même temps. Parmi les exemples, citons la mise à jour d’une bibliothèque pour fermer une faille de sécurité ou le changement d’un protocole de communication utilisé par tous les services.

Pour apporter un changement inter-dépôts, un commit doit être effectué sur chaque dépôt à la suite. Chaque changement dans chaque dépôt doit faire l’objet d’une demande de tirage et d’une révision séparément. Cette activité peut être difficile à coordonner.

Une alternative à l’utilisation d’un grand nombre de dépôts consiste à regrouper tout le code source dans un seul dépôt géant omniscient.

Dépôt unique

Dans cette approche, parfois appelée monodépôt, tout le code source de chaque service est placé dans le même dépôt. Au premier abord, cette approche semble être une très mauvaise idée susceptible de rendre la gestion du code source peu commode. Il y a cependant quelques nets avantages à travailler de cette façon.

Le premier avantage est qu’il est plus facile de gérer les dépendances entre les projets. Au lieu de s’appuyer sur un flux d’artefacts externe, les projets peuvent s’importer directement les uns les autres. Cela signifie que les mises à jour sont instantanées et que les versions en conflit sont susceptibles d’être détectées au moment de la compilation sur la station de travail du développeur. Cela a pour effet de déplacer certains tests d’intégration vers la gauche.

Lorsque vous déplacez du code entre projets, il est maintenant plus facile de conserver l’historique, car les fichiers sont détectés comme ayant été déplacés plutôt que réécrits.

Un autre avantage est que les changements de grande envergure qui dépassent les limites d’un service peuvent être apportés dans un seul commit. Cette activité réduit la surcharge d’avoir potentiellement des dizaines de changements à réviser un par un.

De nombreux outils peuvent effectuer une analyse statique du code pour détecter des pratiques de programmation non sécurisées ou une utilisation problématique des API. Dans un univers multidépôt, chaque dépôt doit être itéré pour trouver les problèmes qu’il rencontre. Avec un dépôt unique, vous exécutez l’analyse à un seul et même endroit.

Il existe également de nombreux inconvénients à l’approche du dépôt unique. L’un des plus inquiétants est que le fait d’avoir un dépôt unique soulève des problèmes de sécurité. Si le contenu d’un dépôt fuit dans un dépôt par modèle de service, la quantité de code perdue est minime. Avec un dépôt unique, tout ce que possède l’entreprise peut être perdu. Les exemples qui ont anéanti tous les efforts de développement de jeux sont nombreux. Le fait d’avoir plusieurs dépôts expose moins de surface d’exposition, ce qui est une caractéristique souhaitable dans la plupart des pratiques de sécurité.

La taille du dépôt unique est susceptible de devenir rapidement ingérable. Cela présente des implications intéressantes en matière de performances. Il peut se révéler nécessaire d’utiliser des outils spécialisés, tels que Virtual File System pour Git qui a été conçu au départ pour améliorer l’expérience des développeurs de l’équipe Windows.

Souvent, l’argument pour utiliser un dépôt unique se résume à dire que Facebook ou Google utilise cette méthode pour l’organisation du code source. Si l’approche est assez bonne pour ces entreprises, alors c’est sûrement la bonne approche pour toutes les entreprises. La vérité est que peu d’entreprises fonctionnent à l’échelle de Facebook ou Google. Les problèmes qui se produisent à ces échelles sont différents de ceux auxquels la plupart des développeurs sont confrontés. Ce qui est bon pour l’un est bon pour l’autre.

Au final, l’une ou l’autre solution peut être utilisée pour héberger le code source des microservices. Toutefois, dans la plupart des cas, les maigres avantages de l’utilisation d’un dépôt unique ne compensent pas la surcharge au niveau de la gestion et de l’ingénierie. La répartition du code sur plusieurs dépôts favorise une meilleure répartition des problèmes et encourage l’autonomie entre les équipes de développement.

Structure des répertoires standard

Quelle que soit l’issue du débat dépôt unique/dépôts multiples, chaque service aura son propre répertoire. L’une des meilleures optimisations pour permettre aux développeurs de passer rapidement d’un projet à l’autre consiste à maintenir une structure de répertoires standard.

Figure 10-4 A standard directory structure for both the email and sign-in services

Figure 10-4 - Structure de répertoires standard.

Chaque fois qu’un projet est créé, un modèle qui met en place la structure appropriée doit être utilisé. Ce modèle peut également inclure des éléments utiles comme le squelette d’un fichier README et un azure-pipelines.yml. Dans toute architecture de microservice, de nombreuses variantes entre les projets rendent les opérations en bloc sur les services plus difficiles.

Il existe de nombreux outils qui peuvent fournir des modèles pour un répertoire entier, contenant plusieurs répertoires de code source. Yeoman est connu dans l’univers JavaScript et GitHub a récemment publié des modèles de répertoire qui fournissent plus ou moins les mêmes fonctionnalités.

Gestion des tâches

La gestion des tâches dans n’importe quel projet peut être difficile. Au préalable, vous devez répondre à d’innombrables questions sur le type de workflow à mettre en place pour garantir une productivité optimale des développeurs.

Les applications natives cloud ont tendance à être plus petites que les produits logiciels traditionnels, ou sont tout du moins divisées en services plus petits. Le suivi des problèmes ou des tâches liés à ces services demeure aussi important qu’avec tout autre projet logiciel. Personne ne veut perdre le fil d’un élément de travail ou expliquer à un client que son problème n’a pas été correctement journalisé. Les tableaux sont configurés au niveau du projet, mais dans chaque projet, des domaines peuvent être définis. Cela permet de décomposer les problèmes parmi plusieurs composants. L’avantage de conserver tout le travail pour l’application toute entière dans un seul endroit est qu’il est facile de déplacer des éléments de travail d’une équipe à une autre, car ils sont mieux compris.

Azure DevOps vient avec un certain nombre de modèles connus préconfigurés. Dans la configuration la plus basique, tout ce qu’il est nécessaire de savoir c’est ce qui se trouve dans le backlog, sur quoi les gens travaillent et ce qui est fait. Il est important d’avoir cette visibilité sur le processus de création de logiciels, afin que le travail puisse être priorisé et les tâches terminées signalées au client. Bien sûr, peu de projets logiciels collent à un processus aussi simple que to do, doing et done. Il ne faut pas longtemps avant que les utilisateurs ne commencent à ajouter des étapes telles que QA ou Detailed Specification au processus.

L’une des parties les plus importantes des méthodologies Agile est l’auto-introspection à intervalles réguliers. Ces révisions sont destinées à fournir des informations sur les problèmes auxquels l’équipe est confrontée et sur la façon dont ils peuvent être résolus. Souvent, cela signifie changer le flux des problèmes et des fonctionnalités par le biais du processus de développement. Il est donc parfaitement sain d’étendre les présentations des tableaux avec des phases supplémentaires.

Les phases des tableaux ne constituent pas le seul outil organisationnel. Selon la configuration du tableau, il existe une hiérarchie des éléments de travail. L’élément le plus affiné qui peut apparaître sur un tableau est une tâche. Une tâche prête à l’emploi contient des champs pour un titre, une description, une priorité, une estimation de la quantité du travail restant et la possibilité de lier d’autres éléments de travail ou éléments de développement (branches, commits, demandes de tirage, builds, etc.). Les éléments de travail peuvent être classifiés dans différents domaines de l’application et différentes itérations (sprints) pour faciliter leur recherche.

Figure 10-5 An example task in Azure DevOps

Figure 10-5 - Tâche dans Azure DevOps.

Le champ Description prend en charge les styles normaux attendus (gras, italique, trait de soulignement et barré) et la possibilité d’insérer des images. Cela en fait un outil puissant à utiliser lors de la spécification du travail ou des bogues.

Les tâches peuvent être regroupées dans des fonctionnalités qui définissent une unité de travail plus grande. Les fonctionnalités, à leur tour, peuvent être regroupées dans des épopées. La classification des tâches dans cette hiérarchie permet de comprendre beaucoup plus facilement si une grande fonctionnalité est sur le point d’être lancée.

Figure 10-6 Work item types configured by default in the Basic process template

Figure 10-6 - Élément de travail dans Azure DevOps.

Il existe différents types de vues des problèmes dans Azure Boards. Les éléments qui ne sont pas encore planifiés apparaissent dans le backlog. De là, ils peuvent être affectés à un sprint. Un sprint est un bloc de temps pendant lequel il est prévu qu’une certaine quantité de travail soit effectuée. Ce travail peut inclure des tâches, mais également la résolution des tickets. Une fois là, l’ensemble du sprint peut être géré à partir de la section du tableau Sprint. Cette vue montre comment le travail progresse et inclut un graphique d’avancement pour donner une estimation toujours à jour sur les chances de réussite du sprint.

Figure 10-7 A board with a sprint defined

Figure 10-7 - Tableau dans Azure DevOps.

Il devrait maintenant vous paraître évident que les tableaux dans Azure DevOps sont très puissants. Pour les développeurs, des vues permettent de voir facilement ce qui est en cours. Pour les chefs de projet, des vues pour le travail à venir, ainsi qu’une vue d’ensemble du travail existant. Pour les managers, il existe de nombreux rapports sur les ressources et la capacité. Malheureusement, il n’y a pas de miracle concernant les applications natives cloud pour éliminer le besoin de suivre le travail. Toutefois, si vous êtes obligé de suivre le travail, il existe quelques options où l’expérience est meilleure que dans Azure DevOps.

Pipelines CI/CD

Presque aucun changement dans le cycle de vie du développement logiciel n’a été aussi révolutionnaire que l’avènement de l’intégration continue (CI) et de la livraison continue (CD). La génération et l’exécution de tests automatisés sur le code source d’un projet dès qu’une modification est archivée permettent de repérer les erreurs tôt. Avant l’avènement des builds d’intégration continue, il n’était pas rare de tirer du code du dépôt et de constater qu’il n’avait pas réussi les tests ou qu’il n’avait même pas pu être généré. Vous deviez alors rechercher la source du problème.

Jusqu’ici, la livraison de logiciels à l’environnement de production nécessitait une documentation complète et une liste d’étapes. Chacune de ces étapes devait être effectuée manuellement dans un processus très sujet aux erreurs.

Figure 10-8 A checklist

Figure 10-8 - Check-list.

La petite sœur de l’intégration continue est la livraison continue où les packages fraîchement créés sont déployés dans un environnement. Le processus manuel ne peut pas être adapté à la vitesse de développement, donc l’automatisation devient plus importante. Les check-lists sont remplacées par des scripts qui peuvent exécuter les mêmes tâches plus rapidement et plus précisément que n’importe quel être humain.

L’environnement dans lequel la livraison continue livre peut être un environnement de test ou, comme dans le cas de nombreuses entreprises technologiques majeures, il peut s’agir de l’environnement de production. Ce dernier demande un investissement dans des tests de haute qualité capables de donner l’assurance qu’un changement ne va pas casser la production pour les utilisateurs. De la même façon que l’intégration continue intercepte tôt les problèmes dans le code, la livraison continue intercepte tôt les problèmes dans le processus de déploiement.

L’importance de l’automatisation du processus de build et de livraison est accentuée par les applications natives cloud. Les déploiements ont lieu plus fréquemment et dans plus d’environnements, donc déployer manuellement est pratiquement impossible.

Azure Builds

Azure DevOps fournit un ensemble d’outils qui facilitent comme jamais l’intégration et le déploiement continus. Ces outils se trouvent sous Azure Pipelines. Le premier d’entre eux est Azure Builds, qui est un outil permettant d’exécuter des définitions de build basées sur YAML à grande échelle. Les utilisateurs peuvent apporter leurs propres machines de build (idéal si la build nécessite un environnement méticuleusement configuré) ou se servir d’une machine d’un pool constamment actualisé de machines virtuelles hébergées par Azure. Ces agents de build hébergés sont préinstallés avec un large choix d’outils de développement pas seulement pour le développement .NET, mais pour tout, du développement Java à Python en passant par le développement iPhone.

DevOps comprend un large éventail de définitions de build prêtes à l’emploi qui peuvent être personnalisées pour n’importe quelle build. Les définitions de build sont définies dans un fichier appelé azure-pipelines.yml et archivées dans le dépôt afin de pouvoir les versionner avec le code source. Cela facilite beaucoup l’apport de modifications au pipeline de build dans une branche, car celles-ci peuvent être vérifiées juste dans cette branche. Un exemple azure-pipelines.yml pour créer une application web ASP.NET sur un framework complet est illustré dans la figure 10-9.

name: $(rev:r)

variables:
  version: 9.2.0.$(Build.BuildNumber)
  solution: Portals.sln
  artifactName: drop
  buildPlatform: any cpu
  buildConfiguration: release

pool:
  name: Hosted VisualStudio
  demands:
  - msbuild
  - visualstudio
  - vstest

steps:
- task: NuGetToolInstaller@0
  displayName: 'Use NuGet 4.4.1'
  inputs:
    versionSpec: 4.4.1

- task: NuGetCommand@2
  displayName: 'NuGet restore'
  inputs:
    restoreSolution: '$(solution)'

- task: VSBuild@1
  displayName: 'Build solution'
  inputs:
    solution: '$(solution)'
    msbuildArgs: '-p:DeployOnBuild=true -p:WebPublishMethod=Package -p:PackageAsSingleFile=true -p:SkipInvalidConfigurations=true -p:PackageLocation="$(build.artifactstagingdirectory)\\"'
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

- task: VSTest@2
  displayName: 'Test Assemblies'
  inputs:
    testAssemblyVer2: |
     **\$(buildConfiguration)\**\*test*.dll
     !**\obj\**
     !**\*testadapter.dll
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

- task: CopyFiles@2
  displayName: 'Copy UI Test Files to: $(build.artifactstagingdirectory)'
  inputs:
    SourceFolder: UITests
    TargetFolder: '$(build.artifactstagingdirectory)/uitests'

- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact'
  inputs:
    PathtoPublish: '$(build.artifactstagingdirectory)'
    ArtifactName: '$(artifactName)'
  condition: succeededOrFailed()

Figure 10-9 - Exemple d’azure-pipelines.yml

Cette définition de build utilise un certain nombre de tâches intégrées qui rendent la création de builds aussi simple que la construction d’un ensemble Lego (plus simple que le gigantesque Faucon millenium). Par exemple, la tâche NuGet restaure les packages NuGet, tandis que la tâche VSBuild appelle les outils de build Visual Studio pour effectuer la vraie compilation. Il existe des centaines de tâches différentes disponibles dans Azure DevOps, en plus des milliers d’autres qui sont gérées par la communauté. Quelles que soient les tâches de build que vous cherchez à exécuter, il est probable que quelqu’un en a déjà créé une.

Les builds peuvent être déclenchées manuellement, par un archivage, selon une planification ou par l’achèvement d’une autre build. Dans la plupart des cas, créer une build à chaque archivage est souhaitable. Les builds peuvent être filtrées afin que différentes builds s’exécutent sur différentes parties du dépôt ou sur différentes branches. Cela ouvre des scénarios tels que l’exécution de builds rapides avec des tests réduits sur les demandes de tirage et l’exécution d’une suite de régressions complète sur le tronc toutes les nuits.

Le résultat final d’une build est une collection de fichiers appelés artefacts de build. Ces artefacts peuvent être transmis à l’étape suivante du processus de build ou ajoutés à un flux Azure Artifacts, afin qu’ils puissent être consommés par d’autres builds.

Mises en production Azure DevOps

Les builds s’occupent de la compilation du logiciel dans un package livrable, mais les artefacts doivent quand même être poussés vers un environnement de test pour procéder à la livraison continue. Pour cela, Azure DevOps utilise un outil distinct appelé Releases. L’outil Releases utilise la même bibliothèque de tâches que celle qui était disponible pour la build, mais introduit un concept de « phases ». Une phase est un environnement isolé dans lequel le package est installé. Par exemple, un produit peut utiliser un développement, une assurance qualité et un environnement de production. Le code est livré en continu dans l’environnement de développement où les tests automatisés peuvent être exécutés. Une fois ces tests réussis, la mise en production passe à l’environnement d’assurance qualité pour les tests manuels. Enfin, le code est poussé en production où tout le monde peut le voir.

Figure 10-10 An example release pipeline with Develop, QA, and Production phases

Figure 10-10 - Pipeline de mise en production

Chaque phase de la build peut être déclenchée automatiquement par l’achèvement de la phase précédente. Toutefois, dans de nombreux cas, ce n’est pas souhaitable. Le déplacement du code en production peut nécessiter l’approbation d’une personne. L’outil Releases prend cela en charge en autorisant les approbateurs à chaque étape du pipeline de mise en production. Les règles peuvent être configurées de telle sorte qu’une personne ou un groupe de personnes spécifique doive valider une mise en production avant qu’elle ne soit envoyée en production. Ces portails de sécurité permettent d’avoir des contrôles qualité manuels et d’être conforme aux exigences réglementaires liées au contrôle de ce qui passe en production.

Tout le monde obtient un pipeline de build

La configuration de nombreux pipelines de build ne coûte rien, il est donc avantageux d’avoir au moins un pipeline de build par microservice. Dans l’idéal, les microservices sont déployables indépendamment dans n’importe quel environnement, donc pouvoir avoir chacun d’eux à mettre en production via son propre pipeline sans mettre en production une masse de code qui n’a rien à voir est génial. Chaque pipeline peut avoir son propre ensemble d’approbations, ce qui permet des variantes dans le processus de build de chaque service.

Versioning des mises en production

L’un des inconvénients de l’utilisation de la fonctionnalité Releases est qu’elle ne peut pas être définie dans un fichier azure-pipelines.yml archivé. Il existe de nombreuses raisons pour lesquelles vous souhaiterez probablement avoir des définitions de mise en production par branche ou inclure une mise en production squelette dans votre modèle de projet. Heureusement, nous travaillons en ce moment sur le déplacement de la prise en charge de certaines phases vers le composant Build. Cela s’appellera une build multiphase et la première version est disponible dès maintenant !