Comment construire un développement interne à part entière en utilisant DevOps - Expérience VTB

Les pratiques DevOps fonctionnent. Nous en étions nous-mêmes convaincus en réduisant de 10 fois le temps d'installation de la version. Dans le système FIS Profile, que nous utilisons chez VTB, l'installation prend désormais 90 minutes au lieu de 10. Le temps de construction de la version est passé de deux semaines à deux jours. Le nombre de défauts de mise en œuvre persistants est presque tombé au minimum. Pour sortir du « travail manuel » et éliminer la dépendance à l’égard du fournisseur, nous avons dû travailler avec des béquilles et trouver des solutions inattendues. Sous la coupe se trouve une histoire détaillée sur la façon dont nous avons construit un développement interne à part entière.

Comment construire un développement interne à part entière en utilisant DevOps - Expérience VTB
 

Prologue : DevOps est une philosophie

Au cours de la dernière année, nous avons fait beaucoup de travail pour organiser le développement interne et la mise en œuvre des pratiques DevOps chez VTB :

  • Nous avons construit des processus de développement internes pour 12 systèmes ;
  • Nous avons lancé 15 pipelines, dont quatre ont été mis en production ;
  • 1445 scénarios de tests automatisés ;
  • Nous avons mis en œuvre avec succès un certain nombre de versions préparées par des équipes internes.

L'un des plus difficiles à organiser le développement et la mise en œuvre en interne des pratiques DevSecOps s'est avéré être le système FIS Profile - un processeur de produits de vente au détail sur un SGBD non relationnel. Néanmoins, nous avons pu construire le développement, lancer le pipeline, installer des packages individuels non publiés sur le produit et apprendre à assembler les versions. La tâche n'était pas facile, mais intéressante et sans restrictions évidentes de mise en œuvre : voici le système - vous devez construire un développement interne. La seule condition est d'utiliser le CD dans un environnement productif.

Au début, l'algorithme de mise en œuvre semblait simple et clair :

  • Nous développons une expertise de développement initiale et atteignons un niveau de qualité acceptable de la part de l'équipe de code sans défauts grossiers ;
  • Nous nous intégrons autant que possible aux processus existants ;
  • Pour transférer du code entre des étapes évidentes, nous coupons un pipeline et poussons l'une de ses extrémités dans la suite.

Pendant ce temps, l'équipe de développement de la taille requise doit développer ses compétences et augmenter la part de sa contribution aux versions à un niveau acceptable. Et voilà, nous pouvons considérer la tâche accomplie.

Il semblerait qu'il s'agisse d'un chemin totalement économe en énergie vers le résultat requis : voici DevOps, voici les mesures de performance de l'équipe, voici l'expertise accumulée... Mais en pratique, nous avons reçu une autre confirmation que DevOps est toujours une question de philosophie , et non « attaché au processus gitlab, ansible, nexus et plus loin dans la liste ».

Après avoir à nouveau analysé le plan d'action, nous avons réalisé que nous construisions en nous une sorte de fournisseur d'externalisation. Par conséquent, la réingénierie des processus a été ajoutée à l'algorithme décrit ci-dessus, ainsi que le développement d'une expertise tout au long du parcours de développement pour jouer un rôle de premier plan dans ce processus. Ce n’est pas l’option la plus simple, mais c’est la voie d’un développement idéologiquement correct.
 

Où commence le développement interne ? 

Ce n’était pas le système le plus convivial avec lequel travailler. Sur le plan architectural, il s'agissait d'un grand SGBD non relationnel, composé de nombreux objets exécutables distincts (scripts, procédures, lots, etc.), qui étaient appelés selon les besoins, et fonctionnait sur le principe d'une boîte noire : il reçoit une requête et émet une réponse. D’autres difficultés méritent d’être notées :

  • Langue exotique (MUMPS);
  • Interface console ;
  • Manque d'intégration avec les outils et frameworks d'automatisation populaires ;
  • Volume de données en dizaines de téraoctets ;
  • Charge de plus de 2 millions d'opérations par heure ;
  • Importance – Critique pour l’entreprise.

En même temps, il n’y avait pas de référentiel de code source de notre côté. Du tout. Il y avait de la documentation, mais toutes les connaissances et compétences clés se trouvaient du côté d'une organisation externe.
Nous avons commencé à maîtriser le développement du système presque à partir de zéro, en tenant compte de ses fonctionnalités et de sa faible diffusion. Commencé en octobre 2018 :

  • Étudié la documentation et les bases de la génération de code ;
  • Nous avons étudié le cours de courte durée sur le développement reçu du fournisseur ;
  • Compétences de développement initial maîtrisées ;
  • Nous avons compilé un manuel de formation pour les nouveaux membres de l'équipe ;
  • Nous avons convenu d'inclure l'équipe en mode « combat » ;
  • Résolution du problème avec le contrôle de la qualité du code ;
  • Nous avons organisé un stand pour le développement.

Nous avons passé trois mois à développer notre expertise et à nous immerger dans le système, et dès le début de l'année 2019, le développement interne a entamé son mouvement vers un avenir radieux, parfois avec difficulté, mais avec confiance et détermination.

Migration du référentiel et autotests

La première tâche DevOps est le référentiel. Nous nous sommes rapidement mis d'accord sur la fourniture d'accès, mais il a fallu migrer du SVN actuel à une branche tronc vers notre Git cible avec le passage à un modèle à plusieurs branches et le développement de Git Flow. Nous disposons également de 2 équipes disposant de leur propre infrastructure, plus une partie de l’équipe du vendeur à l’étranger. Je devais vivre avec deux Gits et assurer la synchronisation. Dans une telle situation, c’était le moindre mal.

La migration du référentiel a été reportée à plusieurs reprises et n'a été achevée qu'en avril, avec l'aide de collègues de première ligne. Avec Git Flow, nous avons décidé de garder les choses simples pour commencer et avons opté pour le schéma classique avec correctif, développement et publication. Ils ont décidé d'abandonner master (alias prod-like). Nous expliquerons ci-dessous pourquoi cette option s'est avérée optimale pour nous. Un référentiel externe appartenant à l'éditeur, commun à deux équipes, a été utilisé comme worker. Il s'est synchronisé avec le référentiel interne selon un planning. Désormais, avec Git et Gitlab, il était possible d'automatiser les processus.

Le problème des autotests a été résolu étonnamment facilement - nous disposions d'un cadre prêt à l'emploi. Compte tenu des particularités du système, l'appel d'une opération distincte était une partie compréhensible du processus métier et servait en même temps de test unitaire. Il ne restait plus qu'à préparer les données de test et à définir l'ordre souhaité d'appel des scripts et d'évaluation des résultats. Au fur et à mesure que la liste des scénarios, constituée sur la base des statistiques d'exploitation, de la criticité des processus et de la méthodologie de régression existante, se complétait, des tests automatiques ont commencé à apparaître. Nous pourrions maintenant commencer à construire le pipeline.

Comment c'était : le modèle avant l'automatisation

Le modèle existant du processus de mise en œuvre est une autre histoire. Chaque modification a été transférée manuellement sous forme de package d'installation incrémentielle distinct. Vint ensuite l'enregistrement manuel dans Jira et l'installation manuelle sur les environnements. Pour les packages individuels, tout semblait clair, mais avec la préparation de la sortie, les choses étaient plus compliquées.

Le montage s'effectuait au niveau des livraisons individuelles, qui étaient des objets indépendants. Tout changement est une nouvelle livraison. Entre autres choses, 60 à 70 versions techniques ont été ajoutées aux 10 à 15 packages de la composition principale de la version - des versions obtenues lors de l'ajout ou de l'exclusion de quelque chose de la version et reflétant les changements dans les ventes en dehors des versions.

Les objets des livraisons se chevauchaient, en particulier dans le code exécutable, qui était à moitié unique. Il y avait de nombreuses dépendances à la fois sur le code déjà installé et sur celui dont l'installation venait d'être planifiée. 

Pour obtenir la version requise du code, il était nécessaire de suivre strictement l'ordre d'installation, au cours duquel les objets étaient physiquement réécrits plusieurs fois, environ 10 à 12 fois.

Après avoir installé un lot de packages, j'ai dû suivre manuellement les instructions pour initialiser les paramètres. La version a été assemblée et installée par le fournisseur. La composition de la version a été clarifiée presque avant le moment de la mise en œuvre, ce qui a entraîné la création de packages de « découplage ». En conséquence, une partie importante des approvisionnements s'est déplacée d'une version à l'autre avec sa propre queue de « découplages ».

Il est désormais clair qu'avec cette approche - assembler le puzzle de la version au niveau du package - une seule branche principale n'avait aucune signification pratique. L'installation en production a nécessité entre une heure et demie à deux heures de travail manuel. Il est bon qu'au moins au niveau de l'installateur, l'ordre de traitement des objets ait été spécifié : les champs et les structures ont été saisis avant les données correspondantes et les procédures. Cependant, cela ne fonctionnait que dans un package séparé.

Le résultat logique de cette approche était les défauts d'installation obligatoires sous la forme de versions tordues d'objets, de code inutile, d'instructions manquantes et d'influences mutuelles inexpliquées d'objets, qui ont été fébrilement éliminées après la sortie. 

Premières mises à jour : validation de l'assemblage et de la livraison

L'automatisation a commencé par transmettre du code via un canal le long de cette route :

  • Récupérer la livraison terminée au stockage ;
  • Installez-le sur un environnement dédié ;
  • Exécutez des autotests ;
  • Évaluer le résultat de l'installation ;
  • Appelez le pipeline suivant du côté de la commande testing.

Le pipeline suivant doit enregistrer la tâche dans Jira et attendre que les commandes soient distribuées aux boucles de test sélectionnées, qui dépendent du calendrier de mise en œuvre de la tâche. Déclencheur - une lettre indiquant que la livraison est prête à une adresse donnée. Bien sûr, c’était une béquille évidente, mais il fallait bien commencer quelque part. En mai 2019, le transfert de code a débuté par des contrôles sur nos environnements. Le processus a commencé, il ne reste plus qu'à le remettre en état :

  • Chaque modification est effectuée dans une branche distincte, qui correspond au package d'installation et fusionne dans la branche principale cible ;
  • Le déclencheur du lancement du pipeline est l'apparition d'un nouveau commit dans la branche master via une demande de fusion, qui est fermée par les responsables de l'équipe interne ;
  • Les référentiels sont synchronisés toutes les cinq minutes ;
  • L'assemblage du package d'installation est démarré - à l'aide de l'assembleur reçu du fournisseur.

Après cela, il y avait déjà des étapes pour vérifier et transférer le code, lancer le tuyau et l'assembler de notre côté.

Cette option a été lancée en juillet. Les difficultés de la transition ont entraîné un certain mécontentement parmi le fournisseur et le personnel de première ligne, mais au cours du mois suivant, nous avons réussi à éliminer toutes les aspérités et à établir un processus entre les équipes. Nous avons maintenant l'assemblage par commit et livraison.
En août, nous avons réussi à terminer la première installation d'un package distinct en production à l'aide de notre pipeline, et depuis septembre, sans exception, toutes les installations de packages individuels non publiés ont été effectuées via notre outil CD. De plus, nous avons réussi à réaliser une part de tâches internes dans 40 % de la composition des versions avec une équipe plus petite que celle du fournisseur - c'est un succès certain. La tâche la plus sérieuse restait : assembler et installer la version.

La solution finale : les packages d'installation cumulatifs 

Nous avons parfaitement compris que scripter les instructions du fournisseur était une automatisation médiocre ; nous devions repenser le processus lui-même. La solution était évidente : collecter un approvisionnement cumulatif auprès de la branche de publication avec tous les objets des versions requises.

Nous avons commencé par une preuve de concept : nous avons assemblé à la main le package de version en fonction du contenu de l'implémentation précédente et l'avons installé sur nos environnements. Tout s'est bien passé, le concept s'est avéré viable. Ensuite, nous avons résolu le problème de la création de scripts pour les paramètres d'initialisation et de leur inclusion dans le commit. Nous avons préparé un nouveau package et l'avons testé dans des environnements de test dans le cadre de la mise à jour du contour. L'installation a été réussie, malgré de nombreux commentaires de la part de l'équipe de mise en œuvre. Mais l'essentiel est que nous avons reçu le feu vert pour entrer en production dans la version de novembre avec notre assemblage.

Alors qu’il ne restait qu’un peu plus d’un mois, les fournitures triées sur le volet laissaient clairement entendre que le temps était compté. Ils ont décidé de réaliser la build à partir de la branche release, mais pourquoi devrait-elle être séparée ? Nous n'avons pas de type Prod et les branches existantes ne valent rien - il y a beaucoup de code inutile. Nous devons de toute urgence supprimer les likes, et cela représente plus de trois mille commits. L’assemblage à la main n’est pas du tout une option. Nous avons esquissé un script qui parcourt le journal d'installation du produit et collecte les validations dans la branche. La troisième fois, cela a fonctionné correctement, et après avoir « fini avec un fichier », la branche était prête. 

Nous avons écrit notre propre constructeur pour le package d'installation et l'avons terminé en une semaine. Ensuite, nous avons dû modifier l'installateur à partir des fonctionnalités de base du système, puisqu'il est open-source. Après une série de vérifications et de modifications, le résultat a été considéré comme réussi. Entre-temps, la composition de la version a pris forme, pour l'installation correcte de laquelle il était nécessaire d'aligner le circuit de test avec celui de production, et un script séparé a été écrit pour cela.

Naturellement, il y a eu beaucoup de commentaires sur la première installation, mais dans l'ensemble, le code a fonctionné. Et après environ la troisième installation, tout a commencé à bien paraître. Le contrôle de la composition et le contrôle de version des objets étaient surveillés séparément en mode manuel, ce qui à ce stade était tout à fait justifié.

Un défi supplémentaire était le grand nombre de non-libérations à prendre en compte. Mais avec la branche Prod-like et Rebase, la tâche est devenue transparente.

Première fois, rapidement et sans erreurs

Nous avons abordé la sortie avec une attitude optimiste et plus d'une douzaine d'installations réussies sur différents circuits. Mais littéralement un jour avant la date limite, il s'est avéré que le fournisseur n'avait pas terminé le travail de préparation de la version pour l'installation de la manière acceptée. Si pour une raison quelconque notre build ne fonctionne pas, la version sera perturbée. De plus, grâce à nos efforts, ce qui est particulièrement désagréable. Nous n'avions aucun moyen de battre en retraite. Nous avons donc réfléchi à des options alternatives, préparé des plans d’action et commencé l’installation.

Étonnamment, l’ensemble de la version, composée de plus de 800 objets, a démarré correctement, du premier coup et en seulement 10 minutes. Nous avons passé une heure à vérifier les journaux à la recherche d’erreurs, mais nous n’en avons trouvé aucune.

Toute la journée suivante, le silence régnait dans le chat de publication : pas de problèmes d'implémentation, de versions tordues ou de code "inapproprié". C'était même quelque peu gênant. Plus tard, certains commentaires ont émergé, mais par rapport à d’autres systèmes et à l’expérience précédente, leur nombre et leur priorité étaient nettement inférieurs.

Un effet supplémentaire de l'effet cumulatif a été une augmentation de la qualité de l'assemblage et des tests. En raison de plusieurs installations de la version complète, les défauts de construction et les erreurs de déploiement ont été identifiés en temps opportun. Les tests dans des configurations de version complète ont permis en outre d'identifier des défauts d'influence mutuelle des objets qui n'apparaissaient pas lors des installations incrémentielles. Ce fut définitivement un succès, surtout compte tenu de notre contribution de 57% à la sortie.

Résultats et conclusions

En moins d'un an, nous avons réussi à :

  • Construire un développement interne à part entière en utilisant un système exotique ;
  • Éliminer la dépendance critique aux fournisseurs ;
  • Lancez CI/CD pour un héritage très hostile ;
  • Élever les processus de mise en œuvre à un nouveau niveau technique ;
  • Réduisez considérablement le temps de déploiement ;
  • Réduire considérablement le nombre d’erreurs de mise en œuvre ;
  • Déclarez-vous en toute confiance comme un expert en développement de premier plan.

Bien sûr, une grande partie de ce qui est décrit ressemble à de la pure connerie, mais ce sont les caractéristiques du système et les limitations de processus qui y existent. Pour le moment, les changements ont affecté les produits et services IS Profile (comptes principaux, cartes plastiques, comptes d'épargne, séquestre, prêts de trésorerie), mais potentiellement l'approche peut être appliquée à tout SI pour lequel la tâche de mise en œuvre des pratiques DevOps est définie. Le modèle cumulatif peut être répliqué en toute sécurité pour des implémentations ultérieures (y compris celles sans version) à partir de nombreuses livraisons.

Source: habr.com

Ajouter un commentaire