Introduction à l’intégration continue, à la livraison et au déploiement

introduction

Le développement et la publication de logiciels peuvent être un processus compliqué, d’autant plus que la complexité des applications, des équipes et du déploiement augmente elle aussi. Les défis deviennent souvent plus prononcés à mesure que les projets se développent. Pour développer, tester et publier des logiciels de manière rapide et cohérente, les développeurs et les entreprises ont créé trois stratégies liées, mais distinctes, pour gérer et automatiser ces processus.

L’intégration continue se concentre sur l’intégration du travail de développeurs individuels dans un référentiel principal plusieurs fois par jour pour détecter les bogues d’intégration à un stade précoce et accélérer le développement collaboratif. La livraison continue vise à réduire les frictions dans le processus de déploiement ou de publication, en automatisant les étapes requises pour déployer une génération afin que le code puisse être publié en toute sécurité à tout moment. Le déploiement continu va encore plus loin en déployant automatiquement chaque changement de code.

Dans ce guide, nous discuterons de chacune de ces stratégies, de leurs liens mutuels et de la manière dont leur intégration au cycle de vie de votre application peut transformer vos pratiques de développement et de publication de logiciels. Pour avoir une meilleure idée des différences entre les différents projets de CI / CD open source, consultez notre https://www.digitalocean.com/community/tutorials/ci-cd-tools-comparison-jenkins-gitlab-ci-buildbot -drone-and-concourse [Comparaison d’outils CI / CD].

Qu’est-ce que l’intégration continue et pourquoi est-ce utile?

L’intégration continue est une pratique qui encourage les développeurs à intégrer leur code dans une branche principale d’un référentiel partagé tôt et souvent. Au lieu de créer des fonctionnalités isolément et de les intégrer à la fin d’un cycle de développement, le code est intégré au référentiel partagé par chaque développeur plusieurs fois par jour.

L’idée est de minimiser les coûts d’intégration en les intégrant rapidement. Les développeurs peuvent découvrir rapidement les conflits aux frontières entre le code nouveau et le code existant, alors que les conflits sont encore relativement faciles à concilier. Une fois le conflit résolu, vous pouvez continuer à travailler avec la certitude que le nouveau code répond aux exigences de la base de code existante.

L’intégration de code n’offre souvent aucune garantie quant à la qualité du nouveau code ou des nouvelles fonctionnalités. Dans de nombreuses organisations, l’intégration est coûteuse, car des processus manuels sont utilisés pour s’assurer que le code est conforme aux normes, ne crée pas de bogues et ne rompt pas les fonctionnalités existantes. Une intégration fréquente peut créer des frictions lorsque le niveau d’automatisation ne correspond pas aux mesures d’assurance qualité mises en place.

Pour remédier à cette friction dans le processus d’intégration, l’intégration continue s’appuie en pratique sur des suites de tests robustes et sur un système automatisé pour exécuter ces tests. Lorsqu’un développeur fusionne du code dans le référentiel principal, des processus automatisés lancent la construction du nouveau code. Ensuite, les suites de tests sont exécutées sur la nouvelle version pour vérifier si des problèmes d’intégration ont été introduits. Si la phase de construction ou la phase de test échoue, l’équipe est alertée afin qu’elle puisse réparer la construction.

Le but ultime de l’intégration continue est de faire de l’intégration un processus simple et reproductible faisant partie du flux de travail de développement quotidien, afin de réduire les coûts d’intégration et de réagir rapidement aux défauts. Travailler pour que le système soit robuste, automatisé et rapide tout en cultivant une culture d’équipe qui encourage les itérations fréquentes et la réactivité nécessaire pour résoudre les problèmes est essentiel au succès de la stratégie.

Qu’est-ce qu’une livraison continue et pourquoi est-ce utile?

  • La livraison continue * est une extension de l’intégration continue. Il se concentre sur l’automatisation du processus de livraison des logiciels afin que les équipes puissent déployer leur code en production facilement et en toute confiance, à tout moment. En s’assurant que la base de code est toujours dans un état déployable, la publication du logiciel devient un événement banal sans rituel compliqué. Les équipes peuvent être certaines de pouvoir se libérer chaque fois qu’elles en ont besoin sans coordination complexe ni tests ultérieurs. Comme pour l’intégration continue, la livraison continue est une pratique qui nécessite un mélange d’améliorations techniques et organisationnelles pour être efficace.

Sur le plan technologique, la livraison continue s’appuie fortement sur les pipelines de déploiement pour automatiser les processus de test et de déploiement. Un * pipeline de déploiement * est un système automatisé qui exécute des suites de tests de plus en plus rigoureuses par rapport à une compilation sous forme d’une série d’étapes séquentielles. Cela reprend là où l’intégration continue s’interrompt. Une configuration d’intégration continue fiable est donc une condition préalable à la mise en œuvre de la livraison continue.

A chaque étape, la construction échoue aux tests qui alertent l’équipe ou réussit les tests, ce qui entraîne une promotion automatique à l’étape suivante. Au fur et à mesure que la construction avance dans le pipeline, les étapes suivantes la déploient dans des environnements qui reflètent l’environnement de production le plus fidèlement possible. De cette façon, la construction, le processus de déploiement et l’environnement peuvent être testés en tandem. Le pipeline se termine par une construction pouvant être déployée en production à tout moment en une seule étape.

Les aspects organisationnels de la distribution continue incitent à donner la priorité à la «déployabilité» en tant que préoccupation principale. Cela a un impact sur la manière dont les fonctionnalités sont construites et connectées au reste de la base de code. Il faut réfléchir à la conception du code afin que les fonctionnalités puissent être déployées en toute sécurité en production à tout moment, même lorsqu’elles sont incomplètes. Un lien: # additionnel-terminologie [nombre de techniques] ont émergé pour aider dans ce domaine.

La diffusion continue est intéressante, car elle automatise les étapes entre la vérification du code dans le référentiel et le choix de la publication de versions fonctionnelles et bien testées dans votre infrastructure de production. Les étapes permettant d’affirmer la qualité et l’exactitude du code sont automatisées, mais la décision finale quant aux informations à publier est laissée à l’organisation pour une flexibilité maximale.

Qu’est-ce qu’un déploiement continu et pourquoi est-il utile?

  • Le déploiement continu * est une extension de la livraison continue qui déploie automatiquement chaque version qui passe le cycle de test complet. Au lieu d’attendre qu’un portier humain décide quoi et quand déployer en production, un système de déploiement continu déploie tout ce qui a traversé avec succès le pipeline de déploiement. Gardez à l’esprit que, si le nouveau code est automatiquement déployé, il existe des techniques pour activer les nouvelles fonctionnalités ultérieurement ou pour un sous-ensemble d’utilisateurs. Le déploiement insiste automatiquement sur les fonctionnalités et les correctifs pour les clients, encourage les modifications plus petites avec une portée limitée et évite la confusion sur ce qui est actuellement déployé en production.

Ce cycle de déploiement entièrement automatisé peut être une source d’inquiétude pour les organisations qui craignent de perdre le contrôle de leur système d’automatisation sur ce qui est publié. Le compromis offert par les déploiements automatisés est parfois jugé trop dangereux pour le gain qu’ils procurent.

D’autres groupes s’appuient sur la promesse de la publication automatique pour s’assurer que les meilleures pratiques sont toujours suivies et pour étendre le processus de test dans un environnement de production limité. Sans une vérification manuelle finale avant de déployer une partie de code, les développeurs doivent s’assurer que leur code est bien conçu et que les suites de tests sont à jour. Cela réduit la décision de ce qui et de quand s’engager dans le référentiel principal et de ce qui et de quand lancer la production en un point unique qui est fermement entre les mains de l’équipe de développement.

Le déploiement continu permet également aux organisations de bénéficier d’un retour d’information rapide et cohérent. Les fonctionnalités peuvent être immédiatement mises à la disposition des utilisateurs et les défauts ou les implémentations inutiles peuvent être détectés rapidement avant que l’équipe ne consacre des efforts considérables à une direction non productive. Obtenir un retour rapide d’information selon lequel une fonctionnalité n’est pas utile permet à l’équipe de se concentrer plutôt que de consacrer plus d’énergie à une zone avec un impact minimal.

Concepts et pratiques clés pour les processus continus

Bien que l’intégration, la livraison et le déploiement continus varient dans la portée de leur implication, certains concepts et pratiques sont fondamentaux pour le succès de chacun.

Petits changements itératifs

L’une des pratiques les plus importantes lors de l’adoption de l’intégration continue consiste à encourager de petits changements. Les développeurs doivent s’entraîner à diviser les gros travaux en petits morceaux et à les engager tôt. Des techniques spéciales telles que la branche par abstraction et les indicateurs de fonctionnalité (voir ci-dessous) aident à protéger la fonctionnalité de la branche principale des modifications de code en cours.

De petits changements minimisent la possibilité et l’impact des problèmes d’intégration. En s’engageant le plus tôt possible dans la branche partagée, puis continuellement tout au long du développement, le coût de l’intégration est réduit et le travail non lié est synchronisé régulièrement.

Développement basé sur le tronc

Avec le développement basé sur une ligne réseau, le travail est effectué dans la branche principale du référentiel ou fusionné dans le référentiel partagé à des intervalles fréquents. Les branches de caractéristiques de courte durée sont permises dans la mesure où elles représentent de petits changements et sont fusionnées dès que possible.

L’idée derrière le développement basé sur le tronc est d’éviter les grands commits qui violent le concept de petits changements itératifs discutés ci-dessus. Le code est disponible tôt pour que les conflits puissent être résolus lorsque leur portée est réduite.

Les libérations sont effectuées à partir de la branche principale ou d’une branche de version créée spécialement à cet effet à partir du tronc. Aucun développement ne se produit sur les branches de publication afin de rester concentré sur la branche principale en tant que source unique de vérité.

Gardez les phases de construction et de test rapides

Chacun des processus repose sur la création et les tests automatisés pour valider leur exactitude. Étant donné que les étapes de construction et de test doivent être effectuées fréquemment, il est essentiel de rationaliser ces processus afin de minimiser le temps passé sur ces étapes.

L’augmentation du temps de compilation doit être traitée comme un problème majeur car l’impact est aggravé par le fait que chaque commit lance une construction. Étant donné que les processus continus obligent les développeurs à s’engager quotidiennement dans ces activités, il est utile de réduire les frictions dans ces domaines.

Lorsque cela est possible, l’exécution de différentes sections de la suite de tests en parallèle peut permettre de déplacer plus rapidement la construction dans le pipeline. Il faut également veiller à ce que la proportion de chaque type de test ait un sens. Les tests unitaires sont généralement très rapides et ne nécessitent que très peu d’entretien. En revanche, les tests automatisés des systèmes ou des tests d’acceptation sont souvent complexes et susceptibles de se briser. Pour en tenir compte, il est souvent judicieux de s’appuyer fortement sur les tests unitaires, de réaliser un nombre important de tests d’intégration, puis de revenir au nombre de tests ultérieurs, plus complexes.

Cohérence tout au long du pipeline de déploiement

Dans la mesure où une implémentation de déploiement continu ou de déploiement est supposée tester la validité des versions, il est essentiel de maintenir la cohérence à chaque étape du processus: la création elle-même, les environnements de déploiement et le processus de déploiement lui-même:

  • * Le code doit être construit une fois au début du pipeline *: le logiciel résultant doit être stocké et accessible aux processus ultérieurs sans être reconstruit. En utilisant exactement le même artefact à chaque phase, vous pouvez être certain de ne pas introduire d’incohérences à la suite de différents outils de génération.

  • * Les environnements de déploiement doivent être cohérents *: un système de gestion de la configuration peut contrôler les différents environnements, et les modifications environnementales peuvent être intégrées dans le pipeline de déploiement lui-même pour garantir leur exactitude et leur cohérence. Des environnements de déploiement propres doivent être configurés à chaque cycle de test pour éviter que des conditions héritées ne compromettent l’intégrité des tests. Les environnements de transfert doivent correspondre à l’environnement de production aussi étroitement que possible afin de réduire les facteurs inconnus présents lors de la promotion de la génération.

  • * Des processus cohérents doivent être utilisés pour déployer la construction dans chaque environnement *: chaque déploiement doit être automatisé et chaque déploiement doit utiliser les mêmes outils et procédures centralisés. Les déploiements ad hoc doivent être éliminés au profit de déployer uniquement avec les outils de pipeline.

Découplage du déploiement et de la libération

Séparer le déploiement du code de sa version pour les utilisateurs est un élément extrêmement puissant de la distribution et du déploiement continus. Le code peut être déployé en production sans l’activer initialement ou le rendre accessible aux utilisateurs. Ensuite, l’organisation décide quand publier de nouvelles fonctionnalités ou fonctionnalités indépendamment du déploiement.

Cela donne aux entreprises une grande flexibilité en séparant les décisions commerciales des processus techniques. Si le code est déjà sur les serveurs, le déploiement n’est plus un élément délicat du processus de publication, ce qui minimise le nombre d’individus et la quantité de travail requise au moment de la publication.

Un certain nombre de techniques aident les équipes à déployer le code responsable d’une fonctionnalité sans la libérer. Les indicateurs de fonctionnalité définissent une logique conditionnelle pour vérifier si le code doit être exécuté en fonction de la valeur d’une variable d’environnement. Branche par abstraction permet aux développeurs de remplacer les implémentations en plaçant une couche d’abstraction entre consommateurs et fournisseurs de ressources. Une planification minutieuse pour incorporer ces techniques vous permet de dissocier ces deux processus.

Types d’essais

L’intégration, la livraison et le déploiement continus reposent tous largement sur des tests automatisés pour déterminer l’efficacité et l’exactitude de chaque changement de code. Différents types de tests sont nécessaires tout au long de ces processus pour gagner la confiance en une solution donnée.

Bien que les catégories ci-dessous ne représentent en aucun cas une liste exhaustive, et bien qu’il existe un désaccord sur la définition exacte de chaque type, ces grandes catégories de tests représentent une variété de façons d’évaluer le code dans différents contextes.

Test de fumée

Les tests de fumée constituent un type spécial de contrôles initiaux conçus pour garantir une fonctionnalité très basique ainsi que certaines hypothèses de base de mise en œuvre et environnementales. Les tests de fumée sont généralement exécutés au tout début de chaque cycle de test pour vérifier l’intégrité avant d’exécuter une suite de tests plus complète.

L’idée de ce type de test est d’aider à détecter de gros drapeaux rouges dans une implémentation et à attirer l’attention sur des problèmes qui pourraient indiquer que des tests supplémentaires sont impossibles ou inutiles. Les tests de fumée ne sont pas très étendus, mais devraient être extrêmement rapides. Si un changement échoue à un test de fumée, c’est un signe précoce que les assertions principales ont été brisées et que vous ne devriez plus consacrer de temps au test tant que le problème n’est pas résolu.

Des tests de fumée spécifiques au contexte peuvent être utilisés au début de toute nouvelle phase de tests pour affirmer que les hypothèses et les exigences de base sont respectées. Par exemple, les tests de fumée peuvent être utilisés avant les tests d’intégration ou de déploiement sur des serveurs de transfert, mais les conditions à tester varient dans chaque cas.

Tests unitaires

Les tests unitaires sont chargés de tester des éléments de code individuels de manière isolée et très ciblée. Les fonctionnalités des fonctions et des classes individuelles sont testées par elles-mêmes. Toutes les dépendances externes sont remplacées par des implémentations stub ou mock afin de centrer le test complètement sur le code en question.

Les tests unitaires sont essentiels pour vérifier l’exactitude des composants de code individuels en termes de cohérence interne et d’exactitude avant de les placer dans des contextes plus complexes. L’étendue limitée des tests et la suppression des dépendances facilitent la recherche de la cause des défauts. C’est également le meilleur moment pour tester diverses entrées et branches de code sur lesquelles il sera peut-être difficile de s’appuyer ultérieurement. Souvent, après les tests de détection de fumée, les tests unitaires sont les premiers tests effectués lorsque des modifications sont apportées.

Les tests unitaires sont généralement exécutés par des développeurs individuels sur leur propre poste de travail avant de soumettre les modifications. Cependant, les serveurs d’intégration continue exécutent presque toujours ces tests à nouveau en toute sécurité avant de commencer les tests d’intégration.

Test d’intégration

Après les tests unitaires, les tests d’intégration sont réalisés en regroupant des composants et en les testant globalement. Alors que les tests unitaires valident la fonctionnalité du code de manière isolée, les tests d’intégration garantissent que les composants coopèrent lors de l’interfaçage. Ce type de test permet d’attraper une classe de bogues entièrement différente qui est exposée lors d’une interaction entre les composants.

En règle générale, les tests d’intégration sont effectués automatiquement lorsque le code est archivé dans un référentiel partagé. Un serveur d’intégration continue vérifie le code, effectue les étapes de génération nécessaires (généralement, effectue un test de fumée rapide pour s’assurer que la génération a abouti), puis exécute des tests unitaires et d’intégration. Les modules sont accrochés ensemble dans différentes combinaisons et testés.

Les tests d’intégration sont importants pour le travail partagé car ils protègent la santé du projet. Les modifications doivent prouver qu’elles n’empiètent pas sur les fonctionnalités existantes et qu’elles interagissent avec un autre code comme prévu. Un objectif secondaire des tests d’intégration est de vérifier que les modifications peuvent être déployées dans un environnement propre. Il s’agit souvent du premier cycle de test réalisé à partir des machines du développeur. Il est donc possible de découvrir des dépendances logicielles et environnementales inconnues au cours de ce processus. C’est généralement aussi la première fois que le nouveau code est testé sur de vraies bibliothèques, services et données externes.

Test du système

Une fois les tests d’intégration effectués, un autre niveau de test appelé test du système peut commencer. À bien des égards, les tests système agissent comme une extension des tests d’intégration. Les tests du système ont pour objectif de s’assurer que les groupes de composants fonctionnent correctement comme un tout cohérent.

Au lieu de se concentrer sur les interfaces entre les composants, les tests système évaluent généralement les fonctionnalités externes d’un logiciel complet. Cet ensemble de tests ignore les composants pour évaluer le logiciel composé en tant qu’entité unifiée. En raison de cette distinction, les tests système se concentrent généralement sur des interfaces accessibles par l’utilisateur ou de l’extérieur.

Test d’acceptation

Les tests d’acceptation sont l’un des derniers types de tests effectués sur un logiciel avant la livraison. Les tests d’acceptation servent à déterminer si un logiciel répond à toutes les exigences du point de vue de l’entreprise ou de l’utilisateur. Ces tests sont parfois construits sur la spécification d’origine et testent souvent des interfaces pour la fonctionnalité attendue et la convivialité.

Les tests d’acceptation sont souvent une phase plus complexe qui peut aller au-delà de la publication du logiciel. Les tests d’acceptation automatisés peuvent être utilisés pour s’assurer que les exigences technologiques de la conception ont été satisfaites, mais la vérification manuelle joue également un rôle.

Fréquemment, les tests d’acceptation commencent par déployer la génération dans un environnement intermédiaire qui reflète le système de production. À partir de là, les suites de tests automatisés peuvent être exécutées et les utilisateurs internes peuvent accéder au système pour vérifier s’il fonctionne comme ils en ont besoin. Après la publication ou l’offre d’un accès bêta aux clients, des tests d’acceptation supplémentaires sont réalisés en évaluant le fonctionnement réel du logiciel et en recueillant les réactions des utilisateurs.

Terminologie additionnelle

Bien que nous ayons discuté de certaines des idées plus larges ci-dessus, vous pouvez rencontrer de nombreux concepts connexes au fur et à mesure de votre apprentissage de l’intégration, de la livraison et du déploiement continus. Définissons quelques autres termes que vous êtes susceptible de voir:

  • * Déploiements Blue-Green *: Les déploiements Blue-Green constituent une stratégie de test de code dans un environnement de type production et de déploiement de code avec un temps d’indisponibilité minimal. Deux ensembles d’environnements compatibles avec la production sont maintenus et le code est déployé dans l’ensemble inactif où les tests peuvent avoir lieu. Lorsqu’il est prêt à être libéré, le trafic de production est acheminé vers les serveurs avec le nouveau code, rendant instantanément les modifications disponibles.

  • * Branche par abstraction *: Branche par abstraction est une méthode permettant d’exécuter des opérations de refactoring majeures dans un projet actif sans branches de développement de longue durée dans le référentiel de code source, ce que décourage les pratiques d’intégration continue. Une couche d’abstraction est construite et déployée entre les consommateurs et l’implémentation existante, de sorte que la nouvelle implémentation puisse être construite derrière l’abstraction en parallèle.

  • * Build (nom) *: Une construction est une version spécifique du logiciel créée à partir du code source. Selon la langue, il peut s’agir d’un code compilé ou d’un ensemble cohérent de code interprété.

  • * Communiqués Canary *: Les communiqués Canaries sont une stratégie permettant de publier les modifications apportées à un sous-ensemble limité d’utilisateurs. L’idée est de s’assurer que tout fonctionne correctement avec les charges de travail de production, tout en minimisant l’impact en cas de problèmes.

  • * Lancement sombre *: le lancement sombre consiste à déployer du code en production qui reçoit du trafic de production sans nuire à l’expérience utilisateur. Les nouvelles modifications sont déployées parallèlement aux implémentations existantes et le même trafic est souvent acheminé vers les deux sites à des fins de test. L’ancienne implémentation est toujours connectée à l’interface utilisateur, mais en coulisse, l’exactitude du nouveau code peut être évaluée à l’aide de véritables requêtes utilisateur dans l’environnement de production.

  • * Pipeline de déploiement *: un pipeline de déploiement est un ensemble de composants qui déplacent les logiciels selon des scénarios de test et de déploiement de plus en plus rigoureux pour évaluer leur état de préparation. Le pipeline se termine généralement par un déploiement automatique en production ou en offrant la possibilité de le faire manuellement.

  • * Indicateurs de fonctionnalité * ou * Fonction bascule *: les indicateurs de fonctionnalité sont une technique de déploiement de nouvelles fonctionnalités derrière une logique conditionnelle qui détermine s’il convient ou non de s’exécuter en fonction de la valeur d’une variable d’environnement. Le nouveau code peut être déployé en production sans être activé en réglant l’indicateur de manière appropriée. Pour libérer le logiciel, la valeur de la variable d’environnement est modifiée, ce qui active le nouveau chemin de code. Les indicateurs de fonctionnalité contiennent souvent une logique permettant à des sous-ensembles d’utilisateurs d’accéder à la nouvelle fonctionnalité, créant ainsi un mécanisme permettant de déployer progressivement le nouveau code.

  • * Promotion *: dans le contexte de processus continus, promouvoir signifie déplacer une version de logiciel à la prochaine étape de test.

  • * Test de trempage *: Le test de trempage implique de tester un logiciel sous une production importante ou une charge similaire à celle de la production pendant une période prolongée.

Conclusion

Dans ce guide, nous avons présenté l’intégration continue, la livraison continue et le déploiement continu, ainsi que la manière dont ils peuvent être utilisés pour créer et publier des logiciels bien testés, en toute sécurité et rapidement. Ces processus s’appuient sur une automatisation poussée et encouragent le partage constant de code afin de corriger rapidement les défauts. Bien que les techniques, les processus et les outils nécessaires à la mise en œuvre de ces solutions représentent un défi majeur, les avantages d’un système bien conçu et correctement utilisé peuvent être énormes.

Pour savoir quelle solution CI / CD convient le mieux à votre projet, consultez notre https://www.digitalocean.com/community/tutorials/ci-cd-tools-comparison-jenkins-gitlab-ci-buildbot- drone-and-concourse [guide de comparaison d’outils CI / CD] pour plus d’informations.