.NET Core op Linux, DevOps aan de top.

Wij hebben DevOps ontwikkeld zoals we konden. We waren met acht personen, en Vasja was de beste op Windows. Opeens vertrok Vasja, en kreeg ik de taak om een nieuw project op te zetten dat Windows-ontwikkeling levert. Toen ik al het Windows-ontwikkelingsmateriaal op tafel gooide, realiseerde ik me dat de situatie pijnlijk was...

Zo begint het verhaal Alexander Sinchinov en een werkende opdracht krijgen. DevOpsConf. Toen de hoofdexpert op Windows het bedrijf verliet, vroeg Alexander zich af wat hij nu moest doen. Overstappen naar Linux, natuurlijk! Alexander zal vertellen hoe hij erin slaagde een precedent te scheppen en een deel van de Windows-ontwikkeling naar Linux over te zetten aan de hand van een gerealiseerd project met 100.000 eindgebruikers.

.NET Core op Linux, DevOps aan de top.

Hoe lever je een project eenvoudig en ongedwongen in RPM, met behulp van TFS, Puppet, Linux .NET core? Hoe beheer je de versiebeheer van de projectdatabase als de ontwikkelaars voor het eerst horen van Postgres en Flyway, terwijl de deadline overmorgen is? Hoe integreer je met Docker? Hoe motiveer je .NET-ontwikkelaars om Windows en smoothies op te geven ten gunste van Puppet en Linux? Hoe los je ideologische conflicten op als je geen kracht, wens of middelen hebt om Windows in productie te ondersteunen? Dit, evenals Web Deploy, testen, CI, de praktijken van het gebruik van TFS in bestaande projecten, en natuurlijk over gebroken krukken en werkende oplossingen, zal aan bod komen in de presentatie van Alexander.

Video afspelen

Dus, Vasja is vertrokken, de taak ligt bij mij, en de ontwikkelaars wachten ongeduldig met hooivorken. Toen ik me realiseerde dat ik Vasja niet kon terughalen, ben ik aan de slag gegaan. Eerst heb ik het percentage Win VM's in ons park beoordeeld. De score was niet in het voordeel van Windows.

.NET Core op Linux, DevOps aan de top.

Aangezien we DevOps actief ontwikkelen, begreep ik dat we iets aan de aanpak van de uitrol van de nieuwe applicatie moesten veranderen. De oplossing was simpel: waar mogelijk alles naar Linux overzetten. Google hielp me - op dat moment was .Net al geport naar Linux, en ik begreep dat dit de oplossing was!

Waarom .NET core in combinatie met Linux?

Er waren verschillende redenen hiervoor. Tussen 'geld betalen' en 'geen geld betalen' kiest de meeste mensen voor het laatste - net als ik. Een licentie voor MSDB kost ongeveer $1.000, en het onderhoud van een park met Windows virtuele machines loopt in de honderden dollars. Voor een groot bedrijf zijn dit aanzienlijke kosten. Daarom besparing — is de eerste reden. Niet de belangrijkste, maar wel een van de zwaarwegende.

Windows virtuele machines verbruiken meer middelen dan hun Linux-broeders - ze zijn zwaar. Gezien de schaal van een groot bedrijf hebben we voor Linux gekozen.

Het systeem is eenvoudig te integreren in de bestaande CI. We beschouwen onszelf als vooruitstrevende DevOps'ers, gebruiken Bamboo, Jenkins en GitLab CI, dus het grootste deel draait op Linux.

De laatste reden is gemakkelijke ondersteuning. We moesten de instapdrempel verlagen voor de 'ondersteuners' - mensen die de technische kant begrijpen, zorgen voor continuïteit en de diensten van de tweede lijn onderhouden. Ze waren al bekend met de Linux-stack, dus het is veel gemakkelijker voor hen om het nieuwe product te begrijpen, te ondersteunen en te onderhouden, dan extra middelen te besteden aan het begrijpen van vergelijkbare functionaliteit van software voor Windows-platforms.

Vereisten

Het eerste en belangrijkste is het gemak van de nieuwe oplossing voor ontwikkelaars. Niet iedereen was bereid om te veranderen, vooral niet na het horen van het woord Linux. Ontwikkelaars willen hun vertrouwde Visual Studio, TFS met geautomatiseerde tests voor builds en smoothies. Hoe de levering naar productie gebeurt, interesseert ze niet. Daarom hebben we besloten het gebruikelijke proces niet te veranderen en alles voor Windows-ontwikkeling zonder wijzigingen te laten.

Het nieuwe project moet geïntegreerd worden in de bestaande CI. De rails waren er al en al het werk moest rekening houden met de parameters van het configuratiebeheersysteem, de afgesproken leveringsnormen en monitoringsystemen.

Eenvoud in ondersteuning en exploitatie, als voorwaarde voor de minimale instapdrempel voor alle nieuwe deelnemers vanuit verschillende afdelingen en de ondersteuningsafdeling.

Deadline was gisteren.

De Win-ontwikkelingsgroep

Waar werkte het team Windows toen mee?

.NET Core op Linux, DevOps aan de top.

Nu kan ik met zekerheid zeggen dat IdentityServer4 — het een geweldige gratis alternatieve ADFS is met vergelijkbare mogelijkheden, of dat Entity Framework Core — een paradijs voor ontwikkelaars is, waar ze zich geen zorgen hoeven te maken over het schrijven van SQL-scripts, maar hun database-query's kunnen beschrijven in termen van OOP. Maar toen, tijdens de discussie over het actieplan, zag ik deze stack als Soemerische spijkerschrift, omdat ik alleen PostgreSQL en Git kende.

Op dat moment gebruikten we actief Puppet als configuratiebeheersysteem. In de meeste van onze projecten gebruikten we GitLab CI, Elastic, balanceerden hoogbelaste diensten met behulp van HAProxy, hielden alles in de gaten met behulp van Zabbix, een set, Grafana en Prometheus, Jaeger, en dat draaide allemaal op hardware HP c ESXi en een werkende opdracht krijgen. VMware. Iedereen kent het - een klassieker.

.NET Core op Linux, DevOps aan de top.

Laten we kijken en proberen te begrijpen wat er precies gebeurde voordat we al deze ingrepen begonnen.

Wat er was

TFS is een vrij krachtig systeem dat niet alleen de code van de ontwikkelaar naar de eindproductiemachine levert, maar ook een set biedt voor zeer flexibele integratie met verschillende diensten - om CI op cross-platformniveau te waarborgen.

.NET Core op Linux, DevOps aan de top.
Vroeger waren dit alleen maar vensters. TFS gebruikte verschillende Build-agents, waarop talrijke projecten werden samengesteld. In elke agent waren 3-4 workers om taken parallel uit te voeren en het proces te optimaliseren. Vervolgens, volgens de releaseplannen, leverde TFS de versgebakken Build naar de Windows-applicatieserver.

Waar we naartoe wilden

Voor levering en ontwikkeling gebruiken we TFS, en we draaien de applicatie op een Linux Application server, en tussen hen zit een soort magie. Deze Magic Box is de essentie van het komende werk. Voordat we het in onderdelen uit elkaar halen, maak ik een stap opzij en zeg ik twee woorden over de applicatie.

Project

De applicatie biedt functionaliteit voor het beheren van prepaidkaarten.

.NET Core op Linux, DevOps aan de top.

Client

Er waren twee soorten gebruikers. Eerste kreeg toegang door zich te authentiseren met een SSL SHA-2 certificaat. Bij de tweede was er toegang met een gebruikersnaam en wachtwoord.

HAProxy

Vervolgens kwam de klantaanvraag bij HAProxy, dat de volgende taken uitvoerde:

  • eerste autorisatie;
  • terminatie van SSL;
  • tuning van HTTP-verzoeken;
  • vertalen van verzoeken.

De verificatie van het klantcertificaat verliep via de keten. Wij zijn de authority en kunnen ons dat veroorloven, omdat we zelf certificaten aan dienstklanten uitgeven.

Let op het derde punt, daar komen we later op terug.

Backend

De backend wilden we op Linux bouwen. De backend interacteert met de database, laadt de benodigde lijst met privileges en vervolgens, afhankelijk van de privileges van de geauthentiseerde gebruiker, biedt toegang voor het ondertekenen van financiële documenten en het indienen ervan voor uitvoering, of voor het genereren van een rapport.

Besparing met HAProxy

Naast de twee contexten waar elke klant mee omging, was er ook een context identity. IdentityServer4 die precies authentiseren mogelijk maakt, is een gratis en krachtige variant voor ADFS — Active Directory Federation Services.

Het verzoek in identity werd in meerdere stappen verwerkt. De eerste stap - client kwam terecht in de backend, die gegevens uitwisselde met deze server en controleerde op de aanwezigheid van een token voor de klant. Als er geen token werd gevonden, werd de aanvraag teruggestuurd naar de context waaruit deze kwam, maar met een redirect, en met de redirect ging het naar identity.

De tweede stap was dat de aanvraag aankwam op de inlogpagina van IdentityServer, waar de klant zich registreerde en de langverwachte token in de database van IdentityServer verscheen.

De derde stap was dat de klant werd teruggeleid naar de context van waaruit hij kwam.

.NET Core op Linux, DevOps aan de top.

IdentityServer4 heeft een bijzonderheid: de response op de terugvraag wordt via HTTP teruggestuurd. Hoe hard we ook probeerden de server in te stellen, hoezeer we ook door de documentatie heen gingen, we kregen telkens de oorspronkelijke aanvraag van de klant met een URL die aankwam via HTTPS, terwijl IdentityServer dezelfde context terugstuurde, maar via HTTP. We waren in shock! En we vertaalden dit alles via de identity context naar HAProxy, en moesten in de headers het protocol HTTP aanpassen naar HTTPS.

Wat is de verbetering en waar hebben we bespaard?

We hebben geld bespaard door gebruik te maken van een gratis oplossing voor de autorisatie van een groep gebruikers, en ook middelen, omdat we IdentityServer4 niet als een aparte node in een apart segment hebben geïmplementeerd, maar het gezamenlijk gebruikten met de backend op dezelfde server waar de backend van de applicatie draait.

Hoe het zou moeten werken

Dus, zoals ik beloofd had – Magic Box. We begrijpen al dat we gegarandeerd de richting van Linux opgaan. Laten we de specifieke taken formuleren die opgelost moesten worden.

.NET Core op Linux, DevOps aan de top.

Puppet-manifesten. Om de configuratie van de service en de applicatie te leveren en te beheren, moesten we geweldige recepten schrijven. Een rolletje met een potlood toont hoe snel en kwalitatief dit is gedaan.

Leveringsmethode. De standaard is RPM. Iedereen begrijpt dat het zonder deze niet gaat in Linux, maar het project bestond na de bouw uit een verzameling uitvoerbare DLL-bestanden. Er waren er ongeveer 150, het project is vrij zwaar. De enige harmonieuze oplossing is om deze binaire bestanden in een RPM te verpakken en daarvandaan de applicatie te installeren.

Versiebeheer. We had to release very frequently, and we needed to determine how to form the package name. This is a matter of integration with TFS. Our build agent was on Linux. When TFS sends a task to the handler - worker - on the build agent, it also passes a batch of variables that go into the handler process's environment. These environment variables include the Build name, version name, and other variables. More about this in the section 'building the RPM package.'

TFS Configuration boiled down to configuring the Pipeline. Previously, we built all Windows projects on Windows agents, but now a Linux agent - the Build agent - appears, which needs to be included in the build group, enriched with some artifacts, and need to specify what types of projects will be built on this Build agent, and somehow modify the Pipeline.

IdentityServer. ADFS is not our path; we're committed to Open Source.

Let's go through the components.

Magic Box

Consists of four parts.

.NET Core op Linux, DevOps aan de top.

Linux Build agent. Linux, because we are building for it - it's logical. This part was completed in three steps.

  • Configure the workers and not just one, as distributed work on the project was anticipated.
  • Install .NET Core 1.x. Why 1.x, when 2.0 is already available in the standard repository? Because when we started development, the stable version was 1.09, and it was decided to make the project for it.
  • Git 2.x.

RPM repository. RPM packages needed to be stored somewhere. It was assumed that we would use the same corporate RPM repository available to all Linux hosts. And so we proceeded. On the repository server, it is configured webhook which downloaded the required RPM package from the specified location. The version of the package was communicated to the webhook by the Build agent.

GitLab. Attention! GitLab is used here not by developers, but by the operations department to control application versions, package versions, monitor the status of all Linux machines, and store the recipes - all Puppet manifests.

Puppet — resolves all controversial issues and delivers exactly the configuration we want from GitLab.

We begin to dive in. How is DLL delivery to RPM done?

Delivery of DLL to RPM

Let's say we have a rock star developer in .NET. They use Visual Studio and create a release branch. After that, they upload it to Git, and Git here is a TFS entity, meaning it is the application's repository that the developer works with.

.NET Core op Linux, DevOps aan de top.

Daarna merkt TFS op dat er een nieuwe commit is binnengekomen. Welke applicatie? In de instellingen van TFS is er een tag die aangeeft welke bronnen beschikbaar zijn voor de betreffende Build-agent. In dit geval ziet hij dat we een .NET Core-project samenstellen en kiest hij een Linux Build-agent uit de pool.

De Build-agent ontvangt de bronnen, downloadt de benodigde dependencies uit de .NET-repository, npm, enz. en na de bouw van de applicatie en de daaropvolgende verpakking verzendt hij het RPM-pakket naar de RPM-repository.

Aan de andere kant gebeurt het volgende. De engineer van de operationele afdeling is verantwoordelijk voor de implementatie van het project: hij wijzigt de versies van de pakketten in Hiera in de repository waar de specificaties van de applicatie zijn opgeslagen, waarna Puppet triggert Yum, haalt het nieuwe pakket uit de repository en is de nieuwe versie van de applicatie klaar voor gebruik.

.NET Core op Linux, DevOps aan de top.

In theorie is het eenvoudig, maar wat gebeurt er intern op de Build-agent?

DLL RPM-verpakking

De projectbronnen zijn ontvangen en de build-opdracht van TFS. De Build-agent start de bouw van het project uit de bronnen. Het gebouwde project is beschikbaar in de vorm van verschillende DLL-bestanden, die zijn verpakt in een zip-archief om de belasting van het bestandssysteem te verminderen.

Het ZIP-archief wordt weggegooid in de directory voor het bouwen van het RPM-pakket. Vervolgens initialiseert het Bash-script de omgevingsvariabelen, zoekt het naar de Build-versie, projectversie, pad naar de build-directory en start het RPM-build. Na de bouw wordt het pakket gepubliceerd in de lokale repository, die op de Build-agent is gevestigd.

Vervolgens wordt vanaf de Build-agent naar de server in de RPM-repositories een JSON-verzoek verzonden met de naam van de versie en de build. De webhook waar ik eerder over sprak, haalt dit pakket uit de lokale repository op de Build-agent en maakt de nieuwe build beschikbaar voor installatie.

.NET Core op Linux, DevOps aan de top.

Waarom precies deze methode van pakketlevering aan de RPM-repository? Waarom kan het opgebouwde pakket niet direct naar de repository worden verzonden? Het punt is dat dit voorwaarde is voor het waarborgen van de beveiliging. Dit scenario beperkt de mogelijkheid dat ongeautoriseerde personen RPM-pakketten op de server plaatsen die toegankelijk is voor alle Linux-machines.

Versiebeheer van de database

Tijdens de vergadering met de ontwikkeling bleek dat de jongens de voorkeur geven aan MS SQL, maar in de meeste non-Windows-projecten gebruikten we al volop PostgreSQL. Aangezien we besloten hadden om afstand te doen van alle betaalde oplossingen, gingen we ook hier PostgreSQL gebruiken.

.NET Core op Linux, DevOps aan de top.

In dit gedeelte wil ik uitleggen hoe wij databaseversiebeheer hebben uitgevoerd en hoe we hebben gekozen tussen Flyway en Entity Framework Core. Laten we hun voor- en nadelen bekijken.

Nadelen

Flyway werkt alleen in één richting, we kunnen niet terugdraaien — dat is een aanzienlijk nadeel. Vergelijken met Entity Framework Core kan op andere parameters - vanuit het perspectief van ontwikkelaarsgemak. Jullie herinneren je vast dat we dat als prioriteit hebben gesteld, en het belangrijkste criterium was om niets te veranderen voor Windows-ontwikkeling.

Voor Flyway hadden we een soort wrapper nodig, zodat de jongens niet hoefden te schrijven SQL-query's. Het was voor hen veel eenvoudiger om in OOP-termen te werken. We hebben instructies geschreven voor het werken met databaseobjecten, de SQL-query werd gevormd en uitgevoerd. De nieuwe versie van de database is klaar, het heeft goed gewerkt - alles is in orde, alles werkt.

Entity Framework Core heeft een nadeel - bij hoge belasting geeft het niet-optimal SQL-query's terug, wat kan leiden tot aanzienlijke belasting van de database. Maar aangezien we geen hoogbelaste service hebben, rekenen we niet met honderden RPS, hebben we deze risico's aanvaard en het probleem voor ons toekomstige zelf gedelegeerd.

Voordelen

Entity Framework Core werkt out-of-the-box en is gebruiksvriendelijk voor ontwikkelaars, terwijl Flyway gemakkelijk integreert in de bestaande CI. Maar we willen het natuurlijk gemakkelijk maken voor de ontwikkelaars :)

De uitrolprocedure

Puppet ziet dat er een versie-update van pakketten binnenkomt, waaronder degene die verantwoordelijk is voor migratie. Eerst installeert het het pakket dat de migratiescripts en de functionaliteit die aan de database is gekoppeld, bevat. Daarna wordt de applicatie die met de database werkt opnieuw opgestart. Daarna volgt de installatie van de overige componenten. De volgorde van het installeren van pakketten en het starten van applicaties is beschreven in het Puppet-manifest.

Applicaties gebruiken gevoelige gegevens, zoals tokens, wachtwoorden voor de database, en al deze gegevens worden vanuit de configuratie met Puppet master opgehaald, waar ze in versleutelde vorm worden opgeslagen.

Problemen met TFS

Nadat we hadden vastgesteld en begrepen dat alles echt werkte, besloot ik te kijken naar wat er algemeen aan de hand was met de builds in TFS voor de afdeling Windows-ontwikkeling voor andere projecten - of we snel bouwen/releasen, en ontdekte ik aanzienlijke problemen met de snelheid.

Een van de belangrijkste projecten bouwt in 12-15 minuten - dat is te lang, zo kan het niet. Een snelle analyse toonde een enorme I/O-daling aan, en dat voor arrays.

Na een componentanalyse identificeerde ik drie brandhaarden. De eerste - «Kaspersky antivirus», die op alle Windows Build-agents de bronbestanden scant. De tweede - Windows Indexer. Hij was niet uitgeschakeld, en op de Build-agents werd alles in realtime geïndexeerd tijdens het deployproces.

De derde - Npm install. Het bleek dat we in de meeste Pipelines precies dit script gebruikten. Wat is er slecht aan? De Npm install-procedure wordt uitgevoerd bij het opbouwen van de afhankelijkheden in package-lock.json, waar de versies van de pakketten worden vastgelegd die voor de projectbuild zullen worden gebruikt. Het nadeel is dat Npm install elke keer de actuele versies van de pakketten uit het internet haalt, wat in het geval van een groot project veel tijd kost.

Ontwikkelaars experimenteren soms op hun lokale machine om een afzonderlijk onderdeel of het hele project te testen. Soms bleek dat alles lokaal perfect werkte, maar bij het bouwen en uitrollen - werkte er niets. We beginnen uit te zoeken wat het probleem is - ah, verschillende versies van pakketten met afhankelijkheden.

Oplossing

  • Bronbestanden in uitsluitingen AV.
  • Uitschakeling van indexering.
  • Overstappen op npm ci.

De voordelen van npm ci zijn dat we de boom van afhankelijkheden één keer opbouwen, en de mogelijkheid krijgen om de ontwikkelaar een actuele lijst van pakketten, waarmee hij lokaal onbeperkt kan experimenteren. Dit bespaart tijd voor ontwikkelaars die code schrijven.

Configuratie

Nu even iets over de configuratie van het repository. Historisch gezien gebruiken we Nexus voor het beheren van repositories, waaronder Internal REPO. In deze interne repository worden alle componenten geleverd die we voor interne doeleinden gebruiken, zoals zelfgeschreven monitoringtools.

.NET Core op Linux, DevOps aan de top.

We gebruiken ook NuGet, omdat het beter cachet in vergelijking met andere pakketbeheerders.

Resultaat

Nadat we de Build-agents hadden geoptimaliseerd, daalde de gemiddelde bouwtijd van 12 minuten naar 7.

Als we alle machines tellen die we voor Windows hadden kunnen gebruiken, maar die we voor dit project naar Linux hebben overgezet, hebben we ongeveer $10.000 bespaard. En dat is alleen op licenties, als we het onderhoud erbij rekenen - nog meer.

Plannen

Voor het volgende kwartaal hebben we plannen gemaakt om te werken aan de optimalisatie van de codelevering.

Overstappen op een pre-built Docker-image. TFS is een geweldige tool met veel plugins die integratie in de Pipeline mogelijk maken, waaronder het bouwen op een trigger, bijvoorbeeld van een Docker-image. Deze trigger willen we maken voor die specifieke package-lock.json. Als de samenstelling van de componenten die worden gebruikt voor het bouwen van het project op een of andere manier verandert, wordt er een nieuw Docker-image gemaakt. Dit wordt vervolgens gebruikt voor het implementeren van een container met de gebouwde applicatie. Dit is momenteel niet het geval, maar we zijn van plan over te schakelen op microservices-architectuur in Kubernetes, die actief wordt ontwikkeld in ons bedrijf en al geruime tijd productie-oplossingen ondersteunt.

Samenvatting

Ik roep iedereen op om Windows weg te gooien, maar niet omdat ik het niet kan gebruiken. De reden is dat het grootste deel van de Opensource-oplossingen - dit is Linux-stack. Je zult goed besparen op middelen. Naar mijn mening is de toekomst weggelegd voor Open Source-oplossingen op Linux met een krachtig community.

Profiel van spreker Alexander Sinchinov op GitHub.

DevOps Conf is een conferentie over het integreren van ontwikkelings-, test- en operationele processen voor professionals van professionals. Dat is ook de reden waarom het project waar Alexander over sprak is gerealiseerd en werkt, en op de dag van de presentatie zijn er twee succesvolle releases uitgevoerd. Op DevOps Conf op RIT++ 27 en 28 mei zullen er nog meer van dergelijke cases zijn van praktijken. Je kunt nog de laatste kans grijpen en een lezing in te dienen of rustig een ticket boeken een ticket. Laten we elkaar ontmoeten in Skolkovo!

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers 🔥 Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster