Mise à jour du processus CI / CD: préparation et planification

image

En 2020, il est probablement assez difficile de trouver un projet dans une description de pile qui n'aurait pas l'un des mots suivants: IaC, microservices, kubernetes, docker, aws / azure / gcloud, blockchain, ML, VR et ainsi de suite. Et c'est super! Le progrès ne s'arrête pas. Nous grandissons, nos projets grandissent avec nous, des outils plus pratiques et fonctionnels apparaissent qui résolvent les problèmes modernes.

Bonjour. Je voulais donc commencer cet article. Mais j'ai ensuite passé en revue certaines choses, parlé avec mes collègues et réalisé que je me trompais. Il y a encore des projets qui ont déjà plus de 15 ans, avec des gestionnaires et des participants qui sont de vieux croyants, et en conséquence, ces projets ont une pile technologique ancienne qui est assez difficile à maintenir dans un zoo existant. Et pour une raison quelconque, ce projet ne peut pas être mis à jour globalement (le client est une starover, il n'y a pas d'évaluation, le projet est très important et la migration est retardée, ou tout le monde est satisfait de tout), et vous devez le soutenir. Encore plus désagréable quand un projet similaire est toujours activement développé. C'est comme une boule de neige. Le client et le public ont besoin de fonctionnalités, le code doit être livré, les serveurs nécessitent de l'attention et des soins ... Mais le bitpack - donc en général, a cessé de prendre en charge le mercure. Un tel cas est proposé pour examen.

Ce qui sera envisagé: conversion de mercurial-git, déplacement de CI de CruiseControl.NET vers TeamCity, de git-deployment à Octopus avec une petite description de l'ensemble du processus.

Le texte s'est avéré beaucoup, il sera donc divisé en parties séparées pour faciliter la perception. Il y aura une table des matières.
Partie 1: ce qui est, pourquoi ce n'est pas comme, la planification, un petit coup bash. J'appellerais cette partie presque technique.
Partie 2: teamcity.
Partie 3: déploiement de poulpe.
Partie 4: dans les coulisses. Moments désagréables, plans pour l'avenir, éventuellement FAQ. Très probablement, il peut également être qualifié de quasi-technique.

Je n'appellerais pas cela un guide de répétition pour de nombreuses raisons: une immersion insuffisante dans les processus du projet en raison du manque de temps, une pratique insuffisante de ces choses, un énorme monolithe dans lequel tous les sous-projets sont étroitement entrelacés, et un tas d'autres nuances qui vous font brûler, vous étonner, les supporter. , mais en aucun cas ne plaît pas. Et aussi, en raison des caractéristiques du projet (il est assez unique), certaines étapes seront conçues exclusivement pour ce cas.

Introduction classique


Nous avions un référentiel mercurial, 300+ (ouverts!) Brunches, ccnet, un autre ccnet + git (pour les déploiements), et une multitude de modules de projet avec nos propres configurations et clients individuels, quatre environnements et une multitude de pools dans IIS, ainsi que cmd scripts, SQL, plus de cinq cents domaines, deux douzaines de builds et développement actif en plus. Non pas que tout cela était nécessaire, mais cela a fonctionné, et c'était gênant et long. La seule chose qui m'a inquiété était la présence d'autres projets nécessitant mon attention. Rien dans le processus de travail avec des tâches de cette ampleur n'est plus dangereux que le manque de concentration et d'interruption.

Je savais que, tôt ou tard, je devrais prêter attention à d'autres tâches, et c'est pourquoi j'ai passé énormément de temps à étudier les infrastructures existantes afin qu'au moins, par la suite, il n'y ait pas de problèmes non résolus.

Malheureusement, je ne peux pas donner une description complète du projet, en raison de la NDA, donc des points techniques généraux seront pris en compte. Tous les noms liés au projet seront également peints. Je m'excuse pour le maculage noir sur les captures d'écran.

L'une des principales caractéristiques du projet est qu'il comporte un certain nombre de modules qui ont un cœur, mais dont les configurations diffèrent. Il existe également des modules avec une approche «spéciale», conçus pour les revendeurs et surtout les gros clients. Un module peut servir plus d'un client. Un client doit être compris comme une organisation distincte ou un groupe de personnes ayant accès à un module spécifique. Chaque client a accès à son propre domaine, a sa propre conception et ses propres paramètres par défaut uniques. Le client est identifié par le domaine qu'il utilise.

Le schéma général de cette partie du projet peut être représenté comme suit:


Comme vous pouvez le voir, le noyau est utilisé de la même manière partout, et cela peut être utilisé.

Raisons pour lesquelles la tâche s'est posée d'examiner et de mettre à jour les processus CI / CD:

  1. CruiseControl.NET a été utilisé comme système de génération. Travailler avec lui est en principe un plaisir douteux. Configurations XML sur plusieurs écrans, un tas de dépendances et de liens entre les configurations, manque de solutions modernes aux problèmes modernes.
  2. Certains développeurs (principalement des leads) sur le projet doivent avoir accès à des serveurs de build, et ils aiment parfois changer les configurations ccnet qui ne doivent pas être modifiées. Devinez ce qui se passe ensuite. Vous devez avoir une gestion simple et pratique des droits dans le système CI, sans retirer aux développeurs l'accès au serveur. Autrement dit, il n'y a pas de configuration de texte - il n'y a nulle part où grimper avec des mains ludiques.
  3. - … CCNET, git. (. ).
  4. , . , . 
  5. - , — ( ) .
  6. . ? ? ? .
  7. Utilisation sous-optimale des ressources et processus obsolète de création et de livraison de code.

Figure au paragraphe 3:


Au stade de la planification, il a été décidé d'utiliser Teamcity comme système de construction et Octopus comme système de déploiement. L’infrastructure «de fer» du client est restée inchangée: des serveurs dédiés séparés pour le développement, le test, la mise en place et la production, ainsi que des serveurs revendeurs (principalement des environnements de production).

Le client a reçu une preuve de concept sur l'exemple d'un des modules, un plan d'action a été rédigé, des travaux préparatoires ont été effectués (installation, configuration, etc.). Cela n'a probablement aucun sens de décrire cela. Comment installer Team City peut être lu sur le site officiel. Je m'attarderai séparément sur certaines exigences formulées pour le nouveau système:

  1. Maintenance facile avec toutes les conséquences (sauvegardes, mises à jour, résolution de problèmes, le cas échéant).
  2. Universalité. Idéalement, développez un schéma général selon lequel tous les modules sont assemblés et livrés, et utilisez-le comme modèle.
  3. Minimisez le temps pour ajouter de nouvelles configurations de construction et de maintenance. Les clients sont ajoutés / supprimés. Parfois, il devient nécessaire de faire de nouvelles configurations. Il est nécessaire que lors de la création d'un nouveau module il n'y ait pas de retard dans la configuration de sa livraison.

À peu près à ce stade, nous nous sommes souvenus de l'arrêt du support des référentiels mercurial avec un bitbucket, et l'exigence a été ajoutée de transférer le référentiel vers git tout en préservant les branches et l'historique des validations.

Préparation: conversion du référentiel


Il semblerait que quelqu'un ait clairement résolu ce problème devant nous et au lieu de nous. Il vous suffit de trouver une solution de travail prête à l'emploi. L'exportation rapide s'est avérée moins rapide. De plus, cela n'a pas fonctionné. Malheureusement, il n'y a plus de journaux ni de captures d'écran. Le fait est qu'il ne pouvait pas. Bitbucket ne fournit pas son propre convertisseur (mais pourrait). Quelques méthodes googlé plus, et aussi par. J'ai décidé d'écrire mes propres scripts, de toute façon ce n'est pas le seul dépôt mercuriel, il sera utile à l'avenir. Les premiers développements seront présentés ici (car ils restent toujours sous la même forme). La logique du travail ressemble à ceci:

  1. Nous prenons l'extension mercurial hggit comme base. 
  2. Nous obtenons une liste de toutes les branches du référentiel mercurial. 
  3. Nous convertissons les noms de branches (merci à mercurial et aux développeurs pour les espaces dans les noms de branches, merci spécialement pour les trémas et autres personnages qui ajoutent de la joie à la vie).
  4. Créez des signets (hg bookmark) et poussez dans le référentiel intermédiaire. Pourquoi? Parce que bitbucket et parce que vous ne pouvez pas créer un signet avec le même nom que le nom de la branche (par exemple, transfert). 
  5. Dans le nouveau référentiel (déjà git), supprimez le suffixe du nom de la branche et migrez hgignore vers gitignore. 
  6. Poussez vers le référentiel principal.

Liste des commandes en fonction des points:

  1. $ cd /path/to/hg/repo
    $ cat << EOF >> ./.hg/hgrc
    [extensions]
    hggit=
    EOF
    
  2. $ hg branches > ../branches
    
  3. #!/usr/bin/env bash
    hgBranchList="./branches"
    sed -i 's/:.*//g' ${hgBranchList}
    symbolsToDelete=$(awk '{print $NF}' FS=" " ${hgBranchList} > sym_to_del.tmp)
     
    i=0
    while read hgBranch; do
      hgBranches[$i]=${hgBranch}
      i=$((i+1))
    done <${hgBranchList}
     
    i=0
    while read str; do
      strToDel[$i]=${str}
      i=$((i+1))
    done < ./sym_to_del.tmp
     
    for i in ${!strToDel[@]}
    do
      echo ${hgBranches[$i]} | sed "s/${strToDel[$i]}//" >> result.tmp
    done
     
    sed -i 's/[ \t]*$//' result.tmp
    sed 's/^/"/g' result.tmp > branches_hg
    sed -i 's/$/"/g' branches_hg
    sed 's/ /-/g' result.tmp > branches_git
    sed -i 's/-\/-/\//g' branches_git
    sed -i 's/-\//\//g' branches_git
    sed -i 's/\/-/\//g' branches_git
    sed -i 's/---/-/g' branches_git
    sed -i 's/--/-/g' branches_git
    rm sym_to_del.tmp
    rm result.tmp
    
  4. #!/usr/bin/env bash
    gitBranchList="./branches_git"
    hgBranchList="./branches_hg"
    hgRepo="/repos/reponame"
     
    i=0
    while read hgBranch; do
      hgBranches[$i]=${hgBranch}
      i=$((i+1))
    done <${hgBranchList}
     
    i=0
    while read gitBranch; do
      gitBranches[$i]=${gitBranch}
      i=$((i+1))
    done <${gitBranchList}
     
    cd ${hgRepo}
    for i in ${!gitBranches[@]}
    do
      hg bookmark -r "${hgBranches[$i]}" "${gitBranches[$i]}-cnv"
    done
     
    hg push git+ssh://git@bitbucket.org:username/reponame-temp.git
    echo "Done."
    
  5. #!/bin/bash
    # clone repo, run git branch -a, delete remotes/origin words to leave only branch names, delete -cnv postfix, delete default branch string because we can't delete it
    repo="/repos/repo"
    gitBranchList="./branches_git"
    defaultBranch="default-cnv"
    while read gitBranch; do   gitBranches[$i]=${gitBranch};   i=$((i+1)); done < $gitBranchList
    cd $repo
    for i in ${!gitBranches[@]}; do git checkout ${gitBranches[$i]}-cnv; done
    git checkout $defaultBranch
    for i in ${!gitBranches[@]}; do
        git branch -m ${gitBranches[$i]}-cnv ${gitBranches[$i]}
        git push origin :${gitBranches[$i]}-cnv ${gitBranches[$i]}
        git push origin -u ${gitBranches[$i]}
    done
    
  6. #!/bin/bash
    # clone repo, run git branch -a, delete remotes/origin words to leave only branch names, delete -cnv postfix, delete default branch string because we can't delete it
    repo="/repos/repo"
    gitBranchList="./branches_git"
    defaultBranch="default"
    while read gitBranch; do   gitBranches[$i]=${gitBranch};   i=$((i+1)); done < $gitBranchList
    cd $repo
    for i in ${!gitBranches[@]}; do
        git checkout ${gitBranches[$i]}
        sed -i '1d' .hgignore
        mv .hgignore .gitignore
        git add .
        git commit -m "Migrated ignore file"
    done
    

Je vais essayer d'expliquer la signification de certaines actions, à savoir l'utilisation d'un référentiel intermédiaire. Initialement, dans le référentiel après la conversion, les noms de branche contiennent le suffixe «-cnv». Cela est dû à la fonction de signet hg. Vous devez supprimer ce suffixe et créer des fichiers gitignore au lieu de hgignore. Tout cela ajoute de l'historique et augmente donc la taille du référentiel (et de manière déraisonnable). Comme autre exemple, je peux citer ce qui suit: essayez de créer un référentiel et poussez le premier commit à 300M avec le code dedans. Ajoutez-le ensuite à gitignore et poussez-le sans lui. Il restera dans l'histoire. Essayez maintenant de le supprimer de l'historique (git filter-branch). Avec un certain nombre de validations, la taille du référentiel résultant ne diminuera pas, mais augmentera. Ceci est résolu par l'optimisation, mais il ne peut pas être lancé sur bitbucket.Elle n'est effectuée que lors de l'importation du référentiel. Par conséquent, toutes les opérations brutes sont effectuées avec un intermédiaire, puis l'importation dans un nouveau est effectuée. La taille du dépôt intermédiaire dans la finale était de 1,15 G, et la taille du 350 M résultant. 

Conclusion


L'ensemble du processus de migration a été divisé en plusieurs étapes, à savoir:

  • préparation (démonstration au client en utilisant un exemple de build, installation de logiciel, conversion de référentiel, mise à jour des configurations ccnet existantes);
  • Configuration CI / CD pour l'environnement de développement et ses tests (l'ancien système continue de fonctionner en parallèle);
  • Paramètres CI / CD pour les environnements restants (en parallèle avec le "bon" existant) et tests;
  • dev migration, staging et test;
  • Migration de la production et transfert de domaines des anciennes instances IIS vers les nouvelles.

La description de la phase préparatoire achevée avec succès est en cours de finalisation. Un succès grandiose n'a pas été atteint ici, sauf que le système existant n'est pas tombé en panne et que le référentiel mercurial dans git a été migré. Cependant, sans une description de ces processus, il n'y aura pas de contexte pour des pièces plus techniques. La partie suivante décrira le processus de mise en place d'un système CI basé sur teamcity.

All Articles