.NET Core sous Linux, DevOps à cheval

Nous avons développé DevOps du mieux que nous pouvions. Nous étions 8 et Vasya était le plus cool de Windows. Soudain, Vasya est parti et j'ai eu pour tâche de lancer un nouveau projet fourni par le développement Windows. Lorsque j'ai jeté toute la pile de développement Windows sur la table, j'ai réalisé que la situation était pénible...

C'est ainsi que commence l'histoire Alexandra Sinchinova sur Conférence DevOps. Lorsque le principal spécialiste de Windows a quitté l'entreprise, Alexander s'est demandé quoi faire maintenant. Passez à Linux, bien sûr ! Alexander vous expliquera comment il a réussi à créer un précédent et à transférer une partie du développement Windows vers Linux en utilisant l'exemple d'un projet réalisé pour 100 000 utilisateurs finaux.

.NET Core sous Linux, DevOps à cheval

Comment livrer facilement et sans effort un projet sur RPM en utilisant TFS, Puppet, Linux .NET core ? Comment prendre en charge le versionnage d'une base de données de projet si l'équipe de développement entend les mots Postgres et Flyway pour la première fois et que la date limite est après-demain ? Comment intégrer avec Docker ? Comment motiver les développeurs .NET à abandonner Windows et les smoothies au profit de Puppet et Linux ? Comment résoudre les conflits idéologiques s'il n'y a ni la force, ni l'envie, ni les ressources pour maintenir Windows en production ? À ce sujet, ainsi que sur Web Deploy, les tests, CI, sur les pratiques d'utilisation de TFS dans les projets existants et, bien sûr, sur les béquilles cassées et les solutions de travail, dans la transcription du rapport d'Alexandre.


Alors Vasya est parti, la tâche m'incombe, les développeurs attendent avec impatience avec des fourches. Quand j'ai finalement réalisé que Vasya ne pouvait pas être renvoyé, je me suis mis au travail. Pour commencer, j'ai évalué le pourcentage de VM Win dans notre flotte. Le score n'est pas en faveur de Windows.

.NET Core sous Linux, DevOps à cheval

Puisque nous développons activement DevOps, j'ai réalisé que quelque chose devait être changé dans l'approche de livraison d'une nouvelle application. Il n'y avait qu'une seule solution : si possible, tout transférer sous Linux. Google m'a aidé - à cette époque, .Net était déjà porté sous Linux, et j'ai réalisé que c'était la solution !

Pourquoi le noyau .NET en conjonction 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 1 000 dollars ; la maintenance d'un parc de machines virtuelles Windows coûte des centaines de dollars. Pour une grande entreprise, cela représente une dépense importante. C'est pourquoi épargnes - première raison. Ce n’est pas le plus important, mais l’un des plus significatifs.

Les machines virtuelles Windows consomment plus de ressources que leurs frères Linux - ils sont lourds. Compte tenu de la taille de la grande entreprise, nous avons choisi Linux.

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

La dernière raison est accompagnement pratique. Nous devions abaisser la barrière à l’entrée pour les « escortes », ces gars qui comprennent la partie technique, assurent un service ininterrompu et maintiennent les services depuis la deuxième ligne. Ils connaissaient déjà la pile Linux, il leur est donc beaucoup plus facile de comprendre, de prendre en charge et de maintenir un nouveau produit que de dépenser des ressources supplémentaires pour comprendre les mêmes fonctionnalités d'un logiciel pour la plate-forme Windows.

Exigences

Tout d'abord - commodité de la nouvelle solution pour les développeurs. Tous n’étaient pas prêts au changement, surtout après que le mot Linux ait été prononcé. Les développeurs veulent leur Visual Studio préféré, TFS, avec des autotests pour les assemblages et les smoothies. La façon dont s’effectue la livraison à la production n’est pas importante pour eux. Par conséquent, nous avons décidé de ne pas modifier le processus habituel et de tout laisser inchangé pour le développement Windows.

Nouveau projet nécessaire intégrer dans le CI existant. Les rails étaient déjà là et tout le travail devait être effectué en tenant compte des paramètres du système de gestion de configuration, des normes de livraison acceptées et des systèmes de surveillance.

Facilité de support et de fonctionnement, comme condition du seuil d'entrée minimum pour tous les nouveaux participants des différentes divisions et du service de support.

Date limite - hier.

Gagner le groupe de développement

Sur quoi travaillait alors l’équipe Windows ?

.NET Core sous Linux, DevOps à cheval

Maintenant, je peux le dire avec confiance Serveur d'identité4 est une alternative gratuite et intéressante à ADFS avec des capacités similaires, ou quoi Noyau du cadre d'entité - un paradis pour un développeur, où vous n'avez pas à vous soucier d'écrire des scripts SQL, mais de décrire les requêtes dans la base de données en termes de POO. Mais ensuite, lors de la discussion sur le plan d'action, j'ai regardé cette pile comme s'il s'agissait d'un cunéiforme sumérien, ne reconnaissant que PostgreSQL et Git.

A cette époque, nous utilisions activement Fantoche en tant que système de gestion de configuration. Dans la plupart de nos projets, nous avons utilisé CI GitLab, Élastique, services à charge élevée équilibrés utilisant HAProxy tout surveillé avec Zabbix, ligaments grafana и Prométhée, Jaeger, et tout cela tournait sur des morceaux de fer HPESXi sur VMware. Tout le monde le sait, un classique du genre.

.NET Core sous Linux, DevOps à cheval

Regardons et essayons de comprendre ce qui se passait avant de commencer toutes ces interventions.

Quel était

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

.NET Core sous Linux, DevOps à cheval
Auparavant, il s'agissait de fenêtres pleines. TFS a utilisé plusieurs agents Build, qui ont été utilisés pour assembler de nombreux projets. Chaque agent dispose de 3 à 4 travailleurs pour paralléliser les tâches et optimiser le processus. Ensuite, conformément aux plans de publication, TFS a livré la nouvelle version au serveur d'applications Windows.

Que voulions-nous réaliser ?

Nous utilisons TFS pour la livraison et le développement, et exécutons l'application sur un serveur d'applications Linux, et il y a une sorte de magie entre eux. Ce boite magique et voilà le sel du travail qui nous attend. Avant de le démonter, je vais faire un pas de côté et dire quelques mots sur l'application.

Projet

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

.NET Core sous Linux, DevOps à cheval

Client

Il y avait deux types d'utilisateurs. Premier obtenu l'accès en vous connectant à l'aide d'un certificat SSL SHA-2. U second il y avait un accès à l'aide d'un identifiant et d'un mot de passe.

HAProxy

Ensuite, la demande du client est allée à HAProxy, qui a résolu les problèmes suivants :

  • autorisation primaire ;
  • Résiliation SSL ;
  • réglage des requêtes HTTP ;
  • demandes de diffusion.

Le certificat client a été vérifié tout au long de la chaîne. Nous - autorité et nous pouvons nous le permettre, puisque nous délivrons nous-mêmes des certificats pour servir nos clients.

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

backend

Ils prévoyaient de créer le backend sous Linux. Le backend interagit avec la base de données, charge la liste de privilèges nécessaire puis, en fonction des privilèges dont dispose l'utilisateur autorisé, donne accès à la signature des documents financiers et à leur envoi pour exécution, ou génère une sorte de rapport.

Économies avec HAProxy

En plus des deux contextes dans lesquels chaque client a navigué, il y avait également un contexte identitaire. Serveur d'identité4 vous permet simplement de vous connecter, il s'agit d'un analogue gratuit et puissant pour ADFS - Services de fédération Active Directory.

La demande d'identité a été traitée en plusieurs étapes. Premier pas - client je suis entré dans le backend, qui a communiqué avec ce serveur et vérifié la présence d'un token pour le client. Si elle n'était pas trouvée, la demande était renvoyée au contexte d'où elle provenait, mais avec une redirection, et avec la redirection, elle était dirigée vers l'identité.

Deuxième étape : la demande a été reçue à la page d'autorisation dans IdentityServer, où le client s'est enregistré et ce jeton tant attendu est apparu dans la base de données IdentityServer.

Troisième étape - le client a été redirigé au contexte dont il est issu.

.NET Core sous Linux, DevOps à cheval

IdentityServer4 a une fonctionnalité : il renvoie la réponse à la demande de retour via HTTP. Peu importe à quel point nous avons eu du mal à configurer le serveur, peu importe à quel point nous nous sommes éclairés sur la documentation, chaque fois que nous recevions une demande initiale du client avec une URL provenant via HTTPS, IdentityServer renvoyait le même contexte, mais avec HTTP. Nous avons été choqués ! Et nous avons transféré tout cela via le contexte d'identité vers HAProxy, et dans les en-têtes, nous avons dû modifier le protocole HTTP en HTTPS.

Quelle est l’amélioration et où avez-vous économisé ?

Nous avons économisé de l'argent en utilisant une solution gratuite pour autoriser un groupe d'utilisateurs et de ressources, car nous n'avons pas placé IdentityServer4 en tant que nœud distinct dans un segment séparé, mais l'avons utilisé avec le backend sur le même serveur où le backend de l'application s'exécute. .

Comment devrait-il fonctionner

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

.NET Core sous Linux, DevOps à cheval

La marionnette se manifeste. Pour fournir et gérer la configuration des services et des applications, des recettes intéressantes ont dû être écrites. Un rouleau de crayon montre avec éloquence avec quelle rapidité et efficacité cela a été fait.

Méthode de livraison. La norme est RPM. Tout le monde comprend que sous Linux, on ne peut pas s'en passer, mais le projet lui-même, après assemblage, était un ensemble de fichiers DLL exécutables. Ils étaient environ 150, le projet était assez difficile. La seule solution harmonieuse consiste à empaqueter ce binaire dans RPM et à déployer l'application à partir de celui-ci.

Gestion des versions. Nous devions publier très souvent et nous devions décider comment former le nom du package. C'est une question de niveau d'intégration avec TFS. Nous avions un agent de build sous Linux. Lorsque TFS envoie une tâche à un gestionnaire - un travailleur - à l'agent Build, il lui transmet également un ensemble de variables qui se retrouvent dans l'environnement du processus du gestionnaire. Ces variables d'environnement contiennent le nom de la build, le nom de la version et d'autres variables. Pour en savoir plus, consultez la section « Création d'un package RPM ».

Configuration de TFS se résumait à la création de Pipeline. Auparavant, nous collections tous les projets Windows sur des agents Windows, mais maintenant un agent Linux apparaît - un agent Build, qui doit être inclus dans le groupe de build, enrichi de quelques artefacts et indiqué quel type de projets sera construit sur cet agent Build. , et modifiez d'une manière ou d'une autre le Pipeline.

Serveur d'identité. ADFS n'est pas notre voie, nous optons pour l'Open Source.

Passons en revue les composants.

boite magique

Se compose de quatre parties.

.NET Core sous Linux, DevOps à cheval

Agent de build Linux. Linux, parce que nous construisons pour cela, c'est logique. Cette partie s'est déroulée en trois étapes.

  • Configurer les travailleurs et pas seul, puisqu'un travail distribué sur le projet était attendu.
  • Installer .NET Core 1.x. Pourquoi 1.x alors que la 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 la 1.09, et il a été décidé de réaliser le projet sur cette base.
  • Git 2.x.

Référentiel 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 disponible pour tous les hôtes Linux. C'est ce qu'ils ont fait. Le serveur de référentiel est configuré Webhook 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 ici n'est pas utilisé 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 stocker la recette - tous les manifestes Puppet.

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

Nous commençons à plonger. Comment fonctionne la livraison des DLL vers RPM ?

Livraison DDL vers RPM

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

.NET Core sous Linux, DevOps à cheval

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

L'agent Build reçoit les sources et télécharge les éléments nécessaires dépendances à partir du référentiel .NET, npm, etc. et après avoir construit l'application elle-même et l'empaquetage ultérieur, envoie le package RPM au référentiel RPM.

D'un autre côté, ce qui suit se produit. L'ingénieur du service exploitation est directement impliqué dans le déploiement du projet : il change les versions des packages dans Hiéra dans le référentiel où est stockée la recette de l'application, après quoi Puppet se déclenche Miam, récupère le nouveau package dans le référentiel et la nouvelle version de l'application est prête à être utilisée.

.NET Core sous Linux, DevOps à cheval

Tout est simple en mots, mais que se passe-t-il à l'intérieur de l'agent Build lui-même ?

RPM des DLL d’empaquetage

Reçu les sources du projet et la tâche de construction de TFS. Agent de construction commence à construire le projet lui-même à partir de sources. Le projet assemblé est disponible sous forme d'ensemble Fichiers DLL, qui sont regroupé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 exécute RPM-build. Une fois la construction terminée, le package est publié sur référentiel local, qui se trouve sur l'agent Build.

Ensuite, de l'agent Build au serveur dans le référentiel RPM La requête JSON est envoyée indiquant le nom de la version et du build. Webhook, dont j'ai parlé plus tôt, télécharge ce même package à partir du référentiel local sur l'agent Build et rend le nouvel assembly disponible pour l'installation.

.NET Core sous Linux, DevOps à cheval

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

Versionnement de la base de données

Lors d'une consultation avec l'équipe de développement, il s'est avéré que les gars étaient plus proches de MS SQL, mais dans la plupart des projets non Windows, nous utilisions déjà PostgreSQL de toutes nos forces. Comme nous avions déjà décidé d'abandonner tout ce qui était payant, nous avons également commencé à utiliser PostgreSQL ici.

.NET Core sous Linux, DevOps à cheval

Dans cette partie, je veux vous expliquer comment nous avons versionné la base de données et comment nous avons choisi entre Flyway et Entity Framework Core. Examinons leurs avantages et leurs inconvénients.

Moins

La voie de migration ne va que dans un sens, nous nous ne pouvons pas revenir en arrière - c'est un inconvénient important. Vous pouvez le comparer avec Entity Framework Core d'autres manières - en termes de commodité pour les développeurs. Vous vous souvenez que nous avons mis cela au premier plan, et que le critère principal était de ne rien changer au développement Windows.

Pour Flyway nous il fallait une sorte d'emballagepour que les gars n'écrivent pas Requêtes SQL. Ils sont beaucoup plus proches du fonctionnement en termes de POO. Nous avons écrit des instructions pour travailler avec des objets de base de données, généré une requête SQL et l'avons exécutée. La nouvelle version de la base de données est prête, testée - tout va bien, tout fonctionne.

Entity Framework Core a un inconvénient - sous de lourdes charges, il construit des requêtes SQL sous-optimales, et la réduction de la base de données peut être importante. Mais comme nous n'avons pas de service à forte charge, nous ne calculons pas la charge en centaines de RPS, nous avons accepté ces risques et avons délégué le problème à nous-mêmes.

Avantages

Noyau du cadre d'entité fonctionne immédiatement et est facile à développeret voie de migration S'intègre facilement dans le CI existant. Mais nous le rendons pratique pour les développeurs :)

Procédure de roll-up

Puppet voit qu'un changement de version du package est à venir, y compris celui qui est responsable de la migration. Tout d’abord, il installe un package contenant 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 lancées est décrit dans le manifeste Puppet.

Les applications utilisent des données sensibles, telles que des jetons, des mots de passe de base de données, tout cela est extrait dans la configuration de 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é d'examiner ce qui se passait avec les assemblages dans TFS dans leur ensemble pour le département de développement de Win sur d'autres projets - si nous construisions/publiions rapidement ou non, et découvert des problèmes importants de vitesse.

L'un des projets principaux prend 12 à 15 minutes à assembler - c'est long, on ne peut pas vivre comme ça. Une analyse rapide a montré une baisse terrible des E/S, et cela concernait les baies.

Après l’avoir analysé composant par composant, j’ai identifié trois foyers. D'abord - "Antivirus Kaspersky", qui analyse les sources sur tous les agents Windows Build. Deuxième - Windows Indexeur. Il n'a pas été désactivé et tout a été indexé en temps réel sur les agents Build lors du processus de déploiement.

Troisième - Installation Npm. Il s'est avéré que dans la plupart des pipelines, nous avons utilisé exactement ce scénario. Pourquoi est-il mauvais ? La procédure d'installation Npm est exécutée lorsque l'arborescence des dépendances est formée dans package-lock.json, où sont enregistrées les versions des packages qui seront utilisés pour construire le projet. L'inconvénient est que l'installation de Npm récupère à chaque fois les dernières versions des packages sur Internet, ce qui prend beaucoup de temps dans le cas d'un grand projet.

Les développeurs expérimentent parfois sur une machine locale pour tester le fonctionnement d’une partie particulière ou de l’ensemble d’un projet. Parfois, il s'est avéré que tout était cool localement, mais ils l'ont assemblé, déployé et rien n'a fonctionné. Nous commençons à comprendre quel est le problème - oui, différentes versions de packages avec dépendances.

décision

  • Sources dans les exceptions AV.
  • Désactivez l'indexation.
  • Aller à npm ci.

Les avantages de npm ci sont que nous Nous collectons l'arbre des dépendances une fois, et nous avons la possibilité de fournir au développeur liste actuelle des packages, avec lequel il peut expérimenter localement autant qu'il le souhaite. Ce gain de temps développeurs qui écrivent du code.

Configuration

Parlons maintenant un peu de la configuration du référentiel. Historiquement, nous utilisons Nexus pour la gestion des référentiels, y compris REPO interne. Ce référentiel interne contient tous les composants que nous utilisons à des fins internes, par exemple la surveillance auto-écrite.

.NET Core sous Linux, DevOps à cheval

Nous utilisons également NuGet, car il a une meilleure mise en cache par rapport aux autres gestionnaires de packages.

Résultat

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

Si l'on compte toutes les machines que nous aurions pu utiliser pour Windows, mais qui sont passées à Linux dans ce projet, nous avons économisé environ 10 000 $, et cela ne concerne que les licences, et plus si l'on prend en compte le contenu.

Plans

Pour le prochain trimestre, nous prévoyions de travailler sur l'optimisation de la livraison du code.

Passer à une image Docker pré-construite. TFS est une bonne chose avec de nombreux plugins qui vous permettent d'intégrer dans Pipeline, y compris l'assemblage basé sur des déclencheurs, par exemple, d'une image Docker. Nous voulons faire ce déclencheur pour le même package-lock.json. Si la composition des composants utilisés pour construire le projet change d'une manière ou d'une autre, nous construisons une nouvelle image Docker. Il est ensuite utilisé pour déployer le conteneur avec l'application assemblée. Ce n'est pas le cas actuellement, mais nous prévoyons de passer à une architecture de microservices dans Kubernetes, qui se développe activement dans notre entreprise et sert depuis longtemps des solutions de production.

Résumé

J'encourage tout le monde à jeter Windows, mais ce n'est pas parce que je ne sais pas le cuisiner. La raison en est que la plupart des solutions Opensource sont Pile Linux. êtes-vous d'accord économiser sur les ressources. Selon moi, l'avenir appartient aux solutions Open Source sur Linux avec une communauté puissante.

Profil de conférencier d’Alexandre Sinchinov sur GitHub.

Conférence DevOps est une conférence sur l'intégration des processus de développement, de test et d'exploitation pour les professionnels par les professionnels. C’est pourquoi le projet dont parlait Alexandre ? mis en œuvre et fonctionnel, et le jour de la représentation, il y a eu deux versions réussies. Sur Conférence DevOps au RIT++ Les 27 et 28 mai, il y aura encore plus de cas similaires de la part de praticiens. Vous pouvez toujours sauter dans le dernier wagon et envoyer un rapport ou prends ton temps réserver billet. Rencontrez-nous à Skolkovo!

Source: habr.com

Ajouter un commentaire