Problème
Pour les projets de grande envergure et techniquement complexes, sur lesquels en règle générale de nombreuses équipes réparties travaillent simultanément, il existe un problème bien connu de développement de logiciels versionnés, que différentes sociétés résolvent différemment.
Actuellement, un certain nombre de nos clients et partenaires livrent les dernières versions (CI / CD) à la production manuellement en installant les versions les plus récentes / actuelles de leur logiciel, après l'avoir testé avec le reste de l'environnement. Par exemple, en fournissant des versions d'applications iOS, Android, etc. si nous parlons de logiciel client, ou en mettant à jour des images docker dans un environnement docker si nous parlons de backend. Pour les projets importants et importants où la décision de publier une nouvelle version dans Production à chaque fois est prise par le chef de projet, une telle décision est justifiée et pas trop coûteuse, surtout si les versions ne sont pas souvent publiées. Cependant, pour l'environnement de développement de test (environnement Dev / Stage), l'utilisation d'outils «manuels» conduit à la complexité du projet, à une éventuelle perturbation des impressions pour le Client, etc. Il peut y avoir plusieurs raisons à cela, notamment des incohérences dans les versions de divers conteneurs sur les logiciels intermédiaires ou l'absence d'un historique détaillé des versions.
Nous devions nous en assurer personnellement et rencontrer de nombreuses difficultés sur un grand projet, dans lequel 6-8 nouvelles versions de logiciels sur le backend et 2-3 versions de logiciels sur le frontend dans le système CI étaient publiées quotidiennement, où les ingénieurs de test ne pouvaient pas objectivement faire face à la charge et il y avait un manque constant de compréhension de la version du logiciel sur le frontend / backend qui était considérée comme stable pour le moment.
Notre expérience
Notre entreprise utilise divers systèmes CI / CD dans son travail, dont le choix est souvent déterminé par les exigences du client. Par exemple, nos spécialistes rencontrent souvent des systèmes CI / CD tels que Jenkins, TeamCity, Travis CI, Circle CI, Gitlab CI, Atlassian Bamboo, où parfois nous travaillons entièrement sur l'infrastructure du client. En conséquence, avec cette approche, le problème de la solution de versionnage incombe entièrement au client.
Lors du développement de solutions pour les clients, lorsque nous avons la possibilité de le faire sur notre propre infrastructure, nous utilisons TFS version 2018 comme base pour le système d'intégration continue / livraison continue. Cela nous permet de résoudre la tâche principale de créer un cycle de développement logiciel complet, à savoir:
- Énoncé des tâches (problèmes, bogues, tâches) basé sur l'approche du développement logiciel utilisée dans le projet actuel;
- Stockage du code source du projet;
- Déploiement de l'infrastructure des build-agents pour les assemblys pour différents OS (Windows, Linux, MacOS);
- Assemblage de projets en mode "manuel" et CI;
- Déploiement de projets en mode "manuel" et CD;
- Projets d'essai;
- Formation de données concernant le temps passé par les employés sur le projet et un certain nombre de fonctions supplémentaires que nous avons implémentées à l'aide d'extensions TFS de notre propre conception et en ajoutant des statistiques à WIT (sous cette forme, TFS a remplacé notre entreprise Redmine et simplifié la collecte de statistiques, de rapports, etc., dans le contexte de projets )
Dans ce cas, il serait logique d'affecter la solution au problème de versioning à TFS, finalisant la fonctionnalité TFS pour nos tâches et les souhaits du Client. En conséquence, la tâche de construire un système de versioning pour les projets d'architecture de microservice a été résolue par les outils TFS en personnalisant divers scripts de construction et en organisant des environnements de test / version.
La solution: utiliser TFS et des outils tiers
Nous avons donc besoin d'un système de gestion des versions pour les projets d'architecture de microservices afin d'organiser les environnements de test et les versions.
En tant que données initiales, nous avons:
- Orchestration - nous utilisons l'essaimage Docker principalement pour réduire l'utilisation d'autres outils tiers. Dans le même temps, il existe des convertisseurs pour convertir les configurations - par exemple, l'utilitaire Kompose , qui vous permettra d'utiliser Kubernetes si nécessaire.
- Agents de build - VM basée sur des serveurs Linux.
- Référentiel source - Git basé sur TFS.
- Stockage d'images - Registre Docker sur VM.
A la question du nom des builds
- Il sera logique d'utiliser des normes de dénomination existantes, par exemple, telles que la spécification de version sémantique .
- Nous suivons ce nom lorsque nous démarrons manuellement le processus de génération de la version finale, car sinon vous ne pourrez pas obtenir le nom correct automatiquement (à moins que vous ne le mettiez manuellement dans le code, qui a encore peu de rapport avec l'idéologie CI).
- En mode CI pour les versions de logiciel de «débogage», nous utilisons les noms suivants sur différents projets:
- Extensions TFS intégrées
- Numérotation basée sur la date actuelle et le numéro de build ce jour-là;
- Numéro de la validation qui a commencé la génération.
Une solution spécifique, par exemple, peut être consultée sur la base d'un exemple du service
Calculatrice , réalisé en Javascript, et de plusieurs projets accessibles au public.
Algorithme de décision
1. Dans TFS2018, créez un projet appelé SibEDGE Semver et importez le référentiel dans le référentiel local
Figure 1 - Projet SibEDGE Semver dans le référentiel à TFS 20182. Créez un fichier Dockerfile avec la description de l'assembly node.js pour nos besoins (
lien ).
FROM node:7 WORKDIR /usr/src/app COPY package.json app.js LICENSE /usr/src/app/ COPY lib /usr/src/app/lib/ LABEL license MIT COPY tests tests ENV NODE_ENV dev RUN npm config set strict-ssl false RUN npm update && \ npm install -g mocha CMD ["mocha", "tests/test.js", "--reporter", "spec"]
Script 1 - Dockerfile pour construire une build
3. Sur le banc de test (avec docker installé), où nous prévoyons de déployer notre environnement, créez un cluster swarm. Dans notre cas, il sera composé d'un seul serveur.
$ docker swarm init
4. Créez un fichier yml avec une description des microservices pour nos besoins (
lien ).
Notez que
vm-docker-registry.development.com:5000
est le référentiel interne de ce projet, que nous avons préparé à l'avance. Pour que le banc d'essai puisse utiliser ce référentiel, il est nécessaire d'enregistrer le certificat SSL sur le peuplement dans le dossier /etc/docker/certs.d/ <nom du référentiel> /ca.crt
version: '3.6' services: #--- # Portainer for manage Docker #--- portainer: image: portainer/portainer:1.15.3 command: --templates http://templates/templates.json -d /data -H unix:///var/run/docker.sock networks: - semver-network ports: - 9000:9000 volumes: - /var/run/docker.sock:/var/run/docker.sock #--- #----Service Calculator Test# #--- semver-calc: image: vm-docker-registry.development.com:5000/calculator:latest networks: - semver-network #--- #----Pminder - Nginx# #--- nginx: image: nginx:1.9.6 depends_on: - mysql ports: - "8888:80" - "6443:443" networks: - semver-network # #----------------------------- # START NoSQL - Redis. #--- redis: image: redis:4.0 networks: - semver-network ports: - "8379:6379" # # END NoSQL - Redis. #--- #----Pminder - DB# #--- mysql: image: mysql:5.7 ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: 'ODdsX0xcN5A9a6q' MYSQL_DATABASE: 'semver' MYSQL_USER: 'user' MYSQL_PASSWORD: 'uXcgTQS8XUm1RzR' networks: - semver-network #--- #----PhpMyAdmin # #--- phpmyadmin: image: phpmyadmin/phpmyadmin depends_on: - mysql environment: PMA_HOST: 'mysql' PMA_USER: 'user' PMA_PASSWORD: 'uXcgTQS8XUm1RzR' ports: - "8500:80" - "8600:9000" networks: - semver-network #--- networks: semver-network:
Le script 2 est le contenu du fichier semver.yml, qui est le fichier de projet docker-compose.
5. Créez une description de build dans TFS2018 (définition de build).
6. La première action de notre script est de construire l'image du conteneur docker:
Figure 2 - Création d'une image pour notre build dans TFS 20187. Envoyez l'image du conteneur Docker créée sur la machine de génération au référentiel interne pour ce projet:
Figure 3 - Enregistrement de l'image docker pour notre assemblage dans le référentiel TFS 20188. Pour l'ensemble de l'environnement sur le banc de test dans le fichier de description des microservices, remplacez le nom de l'image par un nouveau:
Figure 4 - Remplacement du nom de l'image dans le script de build pour notre build dans TFS 20189. Sur le banc de test, copiez l'image du conteneur Docker créée à partir du référentiel interne et mettez à jour le service dans Docker Swarm:
Figure 5 - Déploiement du conteneur Docker avec le script de génération pour notre génération à partir de l'image dans TFS 2018Par conséquent, lorsque nous quittons le référentiel TFS, nous avons un fichier yml avec les versions des images Docker, qui à leur tour a un nom de version pour l'ensemble du projet.
10. Allons au banc de test et vérifions le travail des services et vérifions que le service Calculatrice a été mis à jour et utilise la nouvelle version de l'assemblage.
$ docker service ls
Figure 6 - Mise à jour du service Calculatrice et vérification de sa version actuelle sur notre banc d'essaiAinsi, dans notre stockage d'images du registre Docker, nous avons un ensemble d'images de différentes versions de microservices (dans ce cas particulier, la version d'un seul microservice est modifiée). En lançant un processus de déploiement séparé (via un script qui modifie le fichier de description yml), vous pouvez à tout moment obtenir l'environnement dont vous avez besoin pour les tests sur un banc de test et transférer cette configuration à la division QA. Après les tests (régression, chargement, etc.), nous obtenons des informations selon lesquelles le microservice d'une certaine version fonctionne de manière stable sur un banc de test avec les versions de publication d'autres microservices de telle ou telle version, et la décision finale est déjà prise sur ce qui peut ou non être mis à jour stand de sortie à la nouvelle version.
Résumé - ce que vous avez obtenu à la sortie
Grâce à l'implémentation de la gestion des versions dans des projets avec une architecture de microservices, le résultat suivant a été obtenu:
- la quantité de chaos dans les versions a diminué;
- la vitesse de déploiement d'un nouvel environnement dans les projets a augmenté;
- la qualité des assemblages s'est améliorée et leur niveau d'erreurs a diminué;
- transparence accrue du développement pour les chefs de projet et le client;
- l'interaction entre les ministères s'est améliorée;
- Il y a de nouvelles directions dans le travail de DevOps.
PS Merci à mon collègue Kirill B. de m'avoir aidé à écrire cet article.