.NET Core sous Linux, DevOps à cheval

Nous avons développé DevOps comme nous le pouvions. Nous étions 8 et Vasya était la plus cool de Windows. Soudain, Vasya est partie, et j'ai eu la tâche de sortir un nouveau projet qui fournit le développement Windows. Lorsque j'ai versé toute la pile de développement Windows sur la table, j'ai réalisé que la situation était pénible ...

Ainsi commence l'histoire d' Alexander Sinchinov à DevOpsConf . Lorsque le principal spécialiste de Windows a quitté l'entreprise, Alexander s'est demandé quoi faire maintenant. Passez à Linux, bien sûr! Alexander racontera comment il a réussi à créer un précédent et à transférer une partie du développement de Windows vers Linux en utilisant l'exemple d'un projet achevé pour 100 000 utilisateurs finaux.



Comment livrer facilement et sans effort un projet à RPM en utilisant TFS, Puppet, Linux .NET core? Comment maintenir le versioning de la base de données du projet si le développement entend d'abord les mots Postgres et Flyway, et la date limite après-demain? Comment intégrer avec Docker? Comment motiver les développeurs .NET à abandonner Windows et smoothies au profit de Puppet et Linux? Comment résoudre les conflits idéologiques, s'il n'y a pas de forces, pas de désir, pas de ressources pour servir Windows en production? À ce sujet, ainsi qu'à propos de Web Deploy, des tests, de CI, des pratiques d'utilisation de TFS dans les projets existants et, bien sûr, des béquilles cassées et des solutions de travail, lors du décodage du rapport d'Alexander.


Alors, Vasya est parti, la tâche est pour moi, les développeurs attendent avec impatience une fourche . Quand j'ai finalement réalisé que Vasya ne pouvait pas être renvoyée, je me suis mis au travail. Pour commencer, j'ai estimé le pourcentage de Win VM dans notre parc. Le score n'était pas en faveur de Windows.



Puisque nous développons activement DevOps, j'ai réalisé que quelque chose doit être changé dans l'approche de la sortie d'une nouvelle application. La solution en était une - si possible, transférez tout vers Linux. Google m'a aidé - à cette époque .Net était déjà porté sur Linux, et j'ai réalisé que cette solution!

Pourquoi le noyau .NET est-il fourni avec Linux?


Il y avait plusieurs raisons à cela. Entre "payer de l'argent" et "ne pas payer", la majorité choisira la seconde - comme moi. Une licence pour MSDB coûte environ 1000 $; la maintenance d'un parc de machines virtuelles Windows coûte des centaines de dollars. Pour une grande entreprise, c'est une grosse dépense. Par conséquent, l' épargne est la première raison . Pas le plus important, mais l'un des plus importants.

Les machines virtuelles Windows occupent plus de ressources que leurs frères Linux - elles sont lourdes . Compte tenu de la taille d'une grande entreprise, nous avons choisi Linux.

Le système est simplement intégré au CI existant . Nous nous considérons comme des DevOps progressifs, nous utilisons Bamboo, Jenkins et GitLab CI, donc la plupart de notre travail est sous Linux.

La dernière raison est une escorte pratique. Nous avons dû abaisser le seuil d'entrée pour les «escortes» - des gars qui comprennent la partie technique, assurent un fonctionnement et des services de service ininterrompus depuis la deuxième ligne. Ils connaissaient déjà la pile Linux, il leur est donc beaucoup plus facile de comprendre, de maintenir et de maintenir le nouveau produit que de dépenser des ressources supplémentaires pour gérer les fonctionnalités similaires du logiciel pour la plate-forme Windows.

Prérequis


Tout d'abord, la commodité d'une nouvelle solution pour les développeurs . Tous n'étaient pas prêts pour le changement, surtout après la parole parlée Linux. Les développeurs veulent leur Visual Studio bien-aimé, TFS avec des tests de construction et des smoothies. Comment la livraison a lieu en production - ils s'en moquent. Par conséquent, nous avons décidé de ne pas modifier le processus habituel et de tout laisser inchangé pour le développement de Windows.

Le nouveau projet doit être intégré au CI existant . Les rails étaient déjà là et tout le travail devait être fait en tenant compte des paramètres du système de gestion de la configuration, des normes de livraison acceptées et des systèmes de surveillance.

Simplicité dans le support et le fonctionnement , comme condition d'un seuil d'entrée minimum pour tous les nouveaux participants de différents départements et service de support.

Date limite - hier .

Win Development Group


Avec quoi l'équipe Windows a-t-elle travaillé à l'époque?



Maintenant, je peux dire en toute confiance que IdentityServer4 est une alternative gratuite à ADFS avec des capacités similaires, ou que Entity Framework Core est un paradis pour les développeurs où vous ne pouvez pas vous embêter à écrire des scripts SQL, mais décrire les requêtes dans la base de données en termes de POO. Mais ensuite, en discutant du plan d'action, j'ai regardé cette pile comme une écriture cunéiforme sumérienne reconnaissant uniquement PostgreSQL et Git.

À cette époque, nous utilisions activement Puppet comme système de gestion de configuration. Dans la plupart de nos projets, nous avons utilisé GitLab CI , Elastic , des services équilibrés hautement chargés utilisant HAProxy, tout surveillé avec Zabbix , un tas de Grafana et Prometheus , Jaeger , et tout cela tournait sur du matériel HP avec ESXi sur VMware . Tout le monde le sait - un classique du genre.



Regardons et essayons de comprendre ce qui s'est passé avant de commencer toutes ces interventions.

Quel était


TFS est un système assez puissant qui fournit non seulement du code du développeur à la machine de production finale, mais également un ensemble pour une intégration très flexible avec divers services - pour fournir CI au niveau multiplateforme.


Auparavant, ces fenêtres étaient solides. TFS a utilisé plusieurs agents Build, qui ont rassemblé de nombreux projets. Chaque agent a 3-4 travailleurs-a afin de paralléliser les tâches et d'optimiser le processus. En outre, selon les plans de publication, TFS a livré la version fraîchement préparée au serveur d'applications Windows.

Ce à quoi nous voulions venir


Pour la livraison et le développement, nous utilisons TFS, et nous lançons l'application sur le serveur d'applications Linux, et il y a une sorte de magie entre eux. Cette boîte magique est le sel du travail à venir. Avant de le démonter en partie, je vais faire un pas de côté et dire deux mots sur l'application.

Projet


L'application fournit des fonctionnalités pour gérer les cartes prépayées.



Client


Il y avait deux types d'utilisateurs. Le premier a eu accès en se connectant avec le certificat SSL SHA-2. Le second avait accès par login et mot de passe.

HAProxy


De plus, la demande du client est tombée dans HAProxy, qui a résolu les tâches suivantes:

  • autorisation principale;
  • Terminaison SSL
  • réglage des requêtes HTTP;
  • demandes de diffusion.

La vérification du certificat client est passée par la chaîne. Nous sommes l' autorité et nous pouvons nous le permettre, car nous émettons nous-mêmes des certificats pour servir les clients.

Faites attention au troisième point, un peu plus tard nous y reviendrons.

Backend


Ils prévoyaient de faire un backend sur Linux. Le backend interagit avec la base de données, charge la liste des privilèges nécessaires, puis, selon les privilèges dont dispose l'utilisateur autorisé, donne accès à la signature des documents financiers et à leur envoi pour exécution, ou à la génération d'une sorte de rapport.

Enregistrer avec HAProxy


En plus des deux contextes que chaque client avait l'habitude de traverser, il y avait aussi un contexte identitaire. IdentityServer4 vous permet simplement de vous connecter, c'est un analogue gratuit et puissant pour ADFS - Active Directory Federation Services .

La demande d'identité a été traitée en plusieurs étapes. La première étape - le client est tombé dans le backend , qui a échangé des données avec ce serveur et vérifié la présence d'un jeton pour le client. Si je ne l'ai pas trouvé, la demande est revenue dans le contexte d'où elle venait, mais avec une redirection, et avec une redirection est allée à l'identité.

La deuxième étape - la demande est allée à la page d'authentification dans IdentityServer, où le client était enregistré, et le jeton très attendu est apparu dans la base de données IdentityServer.

La troisième étape - le client est redirigé vers le contexte dont il est issu.



IdentityServer4 a une particularité: il renvoie la réponse à la demande de retour via HTTP . Peu importe comment nous avons eu des difficultés avec la configuration du serveur, peu importe comment nous avons été éclairés par la documentation, chaque fois que nous recevions une demande initiale du client avec une URL via HTTPS, et IdentityServer renvoyait le même contexte, mais avec HTTP. Nous étions sous le choc! Et tout cela a été transféré via le contexte d'identité à HAProxy, et dans les en-têtes, nous avons dû modifier le protocole HTTP en HTTPS.

Quelle est l'amélioration et où ont-ils enregistré?

Nous avons économisé de l'argent en utilisant une solution gratuite pour autoriser un groupe d'utilisateurs, des ressources, car nous n'avons pas pris IdentityServer4 comme une note distincte dans un segment distinct, mais l'avons utilisé avec un backend sur le même serveur où le backend de l'application tourne.

Comment ça devrait fonctionner


Donc, comme je l'ai promis - Magic Box. Nous comprenons déjà que nous sommes assurés de passer à Linux. Formulons des tâches spécifiques nécessitant des solutions.



Les marionnettes se manifestent. Pour livrer et gérer la configuration du service et de l'application, il fallait écrire des recettes sympas. Un rouleau de crayon montre avec éloquence la rapidité et l'efficacité de cette opération.

Mode de livraison. La norme est RPM. Tout le monde comprend que sous Linux, il n'y a aucun moyen sans cela, mais le projet lui-même après l'assemblage était un ensemble de fichiers DLL exécutables. Il y en avait environ 150, le projet est assez difficile. La seule solution harmonieuse consiste à compresser ces fichiers binaires dans RPM et à déployer l'application à partir de celui-ci.

Versioning Nous avons dû libérer très souvent, et nous avons dû décider comment former le nom du paquet. C'est une question de niveau d'intégration TFS. Nous avions un agent de build sous Linux. Lorsque TFS envoie la tâche au gestionnaire - travailleur - à l'agent de génération, il lui envoie également un tas de variables qui tombent dans l'environnement du processus de gestionnaire. Ces variables d'environnement reçoivent le nom Build, le nom de la version et d'autres variables. En savoir plus à ce sujet dans la section «Assemblage d'un package RPM».

La configuration de TFS se résumait à la configuration de Pipeline. Auparavant, nous avions collecté tous les projets Windows sur les agents Windows, et maintenant il y a un agent Linux - un agent Build, qui doit être inclus dans le groupe d'assemblage, enrichi de quelques artefacts, pour dire quel type de projets sera construit sur cet agent Build, et en quelque sorte modifier Pipeline.

IdentityServer. ADFS n'est pas notre chemin, nous nous noyons pour l'Open Source.

Passons en revue les composants.

Boîte magique


Se compose de quatre parties.



Agent de build Linux. Linux, parce que nous le compilons, est logique. Cette partie s'est déroulée en trois étapes.

  • Configurez les travailleurs et plus d'un, car il était supposé répartir le travail sur le projet.
  • Installez .NET Core 1.x. Pourquoi 1.x alors que 2.0 est déjà disponible dans le référentiel standard? Parce que lorsque nous avons commencé le développement, la version stable était 1.09, et il a été décidé de faire le projet pour cela.
  • Git 2.x.

Dépôt RPM. Les packages RPM devaient être stockés quelque part. Il était supposé que nous utiliserions le même référentiel RPM d'entreprise qui est disponible pour tous les hôtes Linux. Et c'est ce qu'ils firent. Un webhook est configuré sur le serveur de référentiel qui a téléchargé le package RPM requis à partir de l'emplacement spécifié. La version du package a été signalée au webhook par l'agent Build.

Gitlab Attention! GitLab n'est pas utilisé ici par les développeurs, mais par le service des opérations pour contrôler les versions des applications, les versions des packages, surveiller l'état de toutes les machines Linux et il stocke la recette - tous les manifestes Puppet.

Puppet - résout tous les problèmes controversés et fournit exactement la configuration que nous voulons de Gitlab.

Nous commençons à plonger. Comment la DLL est-elle fournie dans RPM?

Livraison DDL à RPM


Disons que nous avons une rock star pour le développement .NET. Il utilise Visual Studio et crée une branche de publication. Après cela, il le charge dans Git, et Git ici est une entité TFS, c'est-à-dire, c'est le référentiel d'applications avec lequel le développeur travaille.



Après quoi, TFS voit qu'un nouveau commit est arrivé. Quelle application? Dans les paramètres TFS, il y a une étiquette sur les ressources dont dispose un agent Build particulier. Dans ce cas, il voit que nous construisons un projet .NET Core et sélectionnons un agent de génération Linux dans le pool.

L'agent de build reçoit les sources, télécharge les dépendances nécessaires depuis le .NET, le référentiel npm, etc. et après avoir créé l'application elle-même et l'empaquetage suivant, il envoie le package RPM au référentiel RPM.

D'un autre côté, les événements suivants se produisent. L'ingénieur de maintenance est directement impliqué dans le déploiement du projet: il modifie la version des packages dans Hiera dans le référentiel où la recette de l'application est stockée, après quoi Puppet déclenche Yum , récupère le nouveau package dans le référentiel et la nouvelle version de l'application est prête à l'emploi.



En d'autres termes, tout est simple, mais que se passe-t-il à l'intérieur de l'agent de construction lui-même?

Empaqueter la DLL RPM


Les sources du projet et la tâche de construction de TFS ont été reçues. L'agent de génération commence à générer le projet à partir de la source . Le projet assemblé est disponible sous la forme de nombreux fichiers DLL qui sont empaquetés dans une archive zip pour réduire la charge sur le système de fichiers.

L'archive ZIP est jetée dans le répertoire de construction du package RPM. Ensuite, le script Bash initialise les variables d'environnement, recherche la version de build, la version du projet, le chemin d'accès au répertoire de build et lance la construction de RPM. À la fin de l'assembly, le package est publié dans le référentiel local , qui se trouve sur l'agent de génération.

En outre, une demande JSON est envoyée de l'agent de génération au serveur dans le référentiel RPM avec le nom et la version de la version. Webhook, dont j'ai parlé plus tôt, télécharge ce même package à partir du référentiel local sur l'agent de génération et rend le nouvel assemblage disponible pour l'installation.



Pourquoi un tel schéma de livraison d'un package à un référentiel RPM? Pourquoi ne puis-je pas envoyer immédiatement le package assemblé au référentiel? Le fait est que c'est une condition de sécurité. Ce scénario limite la possibilité de téléchargement non autorisé de packages RPM par des tiers sur un serveur accessible à toutes les machines Linux.

Contrôle de version DB


Lors de la consultation avec le développement, il s'est avéré que les gars sont plus proches de MS SQL, mais dans la plupart des projets non Windows, nous avons déjà utilisé PostgreSQL avec might et main. Comme nous avons déjà décidé d'abandonner tout ce qui est payé, nous avons commencé à utiliser PostgreSQL ici.



Dans cette partie, je veux parler de la façon dont nous avons mis en œuvre le versionnement de la base de données et comment choisir entre Flyway et Entity Framework Core. Considérez leurs avantages et leurs inconvénients.

Inconvénients


La voie de migration ne va que dans un sens, nous ne pouvons pas revenir en arrière - c'est un inconvénient majeur. La comparaison avec Entity Framework Core peut être effectuée en fonction d'autres paramètres - du point de vue de la commodité du développeur. Vous vous souvenez que nous avons mis cela au premier plan, et le critère principal n'était pas de changer quoi que ce soit pour le développement de Windows.

Pour Flyway, nous avions besoin d'une sorte de wrapper pour que les gars n'écrivent pas de requêtes SQL . Ils sont beaucoup plus proches de fonctionner en termes de POO. Nous avons écrit des instructions pour travailler avec des objets de base de données, formé une requête SQL et exécuté. La nouvelle version de la base de données est prête, roulée - tout va bien, tout fonctionne.

Entity Framework Core a un inconvénient - sous de fortes charges, il ne génère pas de requêtes SQL optimales , et le rabattement de la base de données peut être important. Mais comme nous n'avons pas de service à forte charge, nous ne calculons pas la charge avec des centaines de RPS, nous avons pris ces risques et délégué le problème à l'avenir.

Avantages


Entity Framework Core fonctionne dès le départ et est facile à développer , et Flyway s'intègre de manière transparente dans les CI existants . Mais nous le faisons commodément pour les développeurs :)

Procédure de cumul


Puppet constate qu'il y a un changement dans la version des packages dont celui responsable de la migration. Tout d'abord, il installe un package qui contient des scripts de migration et des fonctionnalités liées à la base de données. Après cela, l'application qui fonctionne avec la base de données est redémarrée. Vient ensuite l'installation des composants restants. L'ordre dans lequel les packages sont installés et les applications sont lancées est décrit dans le manifeste Puppet.

Les applications utilisent des données sensibles, telles que des jetons, des mots de passe pour la base de données, tout cela est tiré dans la configuration avec le Puppet master, où ils sont stockés sous forme cryptée.

Problèmes TFS


Après avoir décidé et réalisé que tout fonctionnait vraiment pour nous, j'ai décidé de voir ce qui se passait avec les assemblages dans TFS dans son ensemble pour le département de développement Win pour d'autres projets - nous allions rapidement / ne pas être prêts et publiés, et avons trouvé des problèmes de vitesse importants .

Un des principaux projets va prendre 12 à 15 minutes - c'est long, vous ne pouvez pas vivre comme ça. Une analyse rapide a montré un terrible affaiblissement des E / S, et c'est sur les baies.

Après avoir analysé les composants, j'ai identifié trois foyers. Le premier est l' antivirus Kaspersky , qui analyse le code source sur tous les agents Windows Build. Le second est l' indexeur Windows . Il n'était pas déconnecté et sur les agents de génération en temps réel, tout était indexé pendant le processus de déploiement.

Le troisième est l' installation de Npm. Il s'est avéré que dans la plupart des pipelines, nous avons utilisé ce scénario particulier. Pourquoi est-il mauvais? La procédure d'installation de Npm démarre lorsque l'arborescence des dépendances est formée dans package-lock.json , où les versions des packages qui seront utilisées pour générer le projet sont fixes. L'inconvénient est que l'installation de Npm extrait à chaque fois les dernières versions des packages à partir d'Internet, et c'est un temps considérable dans le cas d'un grand projet.

Les développeurs expérimentent parfois sur la machine locale pour tester le fonctionnement d'une partie individuelle ou d'un projet dans son ensemble. Parfois, il s'est avéré que localement tout était cool, mais assemblé, déployé - rien ne fonctionnait. Nous commençons à comprendre quel est le problème - oui, différentes versions des packages de dépendances.

Solution


  • Sources d'exceptions AV.
  • Désactiver l'indexation.
  • Passez à npm ci .

L'avantage de npm ci est que nous collectons une fois l'arbre de dépendance et avons l'opportunité de fournir au développeur une liste à jour des packages avec lesquels il peut expérimenter localement autant qu'il le souhaite. Cela fait gagner du temps aux développeurs qui écrivent du code.

La configuration


Maintenant, un peu sur la configuration du référentiel. Historiquement, nous avons utilisé Nexus pour gérer les référentiels, y compris le REPO interne . Tous les composants que nous utilisons à des fins internes, par exemple, la surveillance auto-écrite, sont livrés à ce référentiel interne.



Nous utilisons également NuGet , car il se cache mieux que les autres gestionnaires de packages.

Résultat


Après avoir optimisé les agents de génération, le temps de génération moyen a été réduit de 12 minutes à 7.

Si nous comptons toutes les machines que nous pourrions utiliser pour Windows, mais transférées à Linux dans ce projet, nous avons économisé environ 10 000 $. Et ce n'est que sur les licences, et en tenant compte du contenu - plus.

Plans


Le trimestre suivant, le plan prévoyait des travaux d'optimisation de la livraison du code.

Transition vers l'image Docker pré-build . TFS est une chose sympa avec beaucoup de plugins qui vous permettent d'intégrer dans le Pipeline, y compris l'assemblage en fonction du déclencheur, par exemple, une image Docker. Nous voulons faire ce déclencheur sur le même package-lock.json . Si en quelque sorte la composition des composants utilisés pour construire le projet change, nous aurons une nouvelle image Docker. Il est ensuite utilisé pour déployer le conteneur avec l'application compilée. Ce n'est plus le cas, mais nous prévoyons de passer à une architecture de microservices à Kubernetes, qui se développe activement dans notre entreprise et sert depuis longtemps des solutions de production.

Résumé


J'exhorte tout le monde à jeter Windows, mais ce n'est pas parce que je ne sais pas comment le faire cuire. La raison en est que la plupart des solutions opensource sont la pile Linux . Vous économiserez bien sur les ressources . À mon avis, l'avenir réside dans les solutions Open Source Linux avec une communauté puissante.

Profil du conférencier Alexander Sinchinov sur GitHub .

DevOps Conf est une conférence sur l'intégration des processus de développement, de test et d'exploitation pour les professionnels des professionnels. C'est pourquoi le projet dont Alexander a parlé? mis en œuvre et fonctionnel, et le jour de la représentation, deux versions réussies ont été effectuées. Sur DevOps Conf sur RIT ++ les 27 et 28 mai, il y aura encore plus de tels cas de praticiens. Vous pouvez toujours sauter dans la dernière voiture et soumettre un rapport, ou prendre votre temps pour réserver un billet. Retrouvez-moi à Skolkovo!

Source: https://habr.com/ru/post/fr448496/


All Articles