.NET Core på Linux, DevOps på hästryggen

Vi utvecklade DevOps så gott vi kunde. Vi var 8 stycken, och Vasya var den coolaste i Windows. Plötsligt gick Vasya, och jag hade i uppgift att lansera ett nytt projekt som levererades av Windows-utveckling. När jag dumpade hela Windows-utvecklingsstacken på bordet insåg jag att situationen var jobbig...

Så här börjar historien Alexandra SinchinovaDevOpsConf. När den ledande Windows-specialisten lämnade företaget undrade Alexander vad han skulle göra nu. Byt till Linux såklart! Alexander kommer att berätta hur han lyckades skapa ett prejudikat och överföra en del av Windows-utvecklingen till Linux med hjälp av exemplet på ett avslutat projekt för 100 000 slutanvändare.

.NET Core på Linux, DevOps på hästryggen

Hur levererar man enkelt och utan ansträngning ett projekt till RPM med hjälp av TFS, Puppet, Linux .NET core? Hur stödjer man versionering av en projektdatabas om utvecklingsteamet hör orden Postgres och Flyway för första gången, och deadline är i övermorgon? Hur integrerar jag med Docker? Hur motiverar man .NET-utvecklare att överge Windows och smoothies till förmån för Puppet och Linux? Hur ska man lösa ideologiska konflikter om det varken finns styrkan, viljan eller resurserna att behålla Windows i produktion? Om detta, såväl som om Web Deploy, testning, CI, om praxis för att använda TFS i befintliga projekt, och, naturligtvis, om trasiga kryckor och fungerande lösningar, i transkriptionen av Alexanders rapport.


Så, Vasya lämnade, uppgiften ligger på mig, utvecklarna väntar otåligt med höggafflar. När jag äntligen insåg att Vasya inte kunde lämnas tillbaka, började jag. Till att börja med bedömde jag andelen Win VMs i vår flotta. Poängen var inte till fördel för Windows.

.NET Core på Linux, DevOps på hästryggen

Eftersom vi aktivt utvecklar DevOps insåg jag att något måste förändras i tillvägagångssättet för att leverera en ny applikation. Det fanns bara en lösning - överför om möjligt allt till Linux. Google hjälpte mig - vid den tiden hade .Net redan porterats till Linux, och jag insåg att detta var lösningen!

Varför .NET core i kombination med Linux?

Det fanns flera skäl till detta. Mellan "betala pengar" och "inte betala" kommer majoriteten att välja den andra - som jag. En licens för MSDB kostar cirka 1 000 USD; att underhålla en flotta av virtuella Windows-maskiner kostar hundratals dollar. För ett stort företag är detta en stor kostnad. Det är därför besparingar - första anledningen. Inte den viktigaste, men en av de betydande.

Virtuella Windows-maskiner tar upp mer resurser än deras Linux-bröder - de är tunga. Med tanke på storleken på det stora företaget valde vi Linux.

Systemet är helt enkelt integrerat i befintliga CI. Vi anser oss vara progressiva DevOps, vi använder Bamboo, Jenkins och GitLab CI, så det mesta av vårt arbete körs på Linux.

Den sista anledningen är bekvämt ackompanjemang. Vi behövde sänka inträdesbarriären för "eskorter" – killarna som förstår den tekniska delen, säkerställer oavbruten service och underhåller tjänster från andra linjen. De var redan bekanta med Linux-stacken, så det är mycket lättare för dem att förstå, stödja och underhålla en ny produkt än att spendera ytterligare resurser för att förstå samma funktionalitet hos programvaran för Windows-plattformen.

Krav

Först och främst - bekvämligheten med den nya lösningen för utvecklare. Inte alla av dem var redo för förändring, särskilt efter att ordet Linux uttalades. Utvecklare vill ha sin favorit Visual Studio, TFS med autotester för sammansättningar och smoothies. Hur leverans till produktion sker är inte viktigt för dem. Därför beslutade vi att inte ändra den vanliga processen och lämna allt oförändrat för Windows-utveckling.

Nytt projekt behövs integreras i befintliga CI. Skenorna fanns redan där och allt arbete måste göras med hänsyn till parametrarna för konfigurationshanteringssystemet, accepterade leveransstandarder och övervakningssystem.

Enkel support och drift, som ett villkor för den lägsta inträdesgränsen för alla nya deltagare från olika divisioner och supportavdelningen.

Deadline - igår.

Vinn utvecklingsgrupp

Vad arbetade Windows-teamet med då?

.NET Core på Linux, DevOps på hästryggen

Nu kan jag med säkerhet säga det IdentityServer4 är ett coolt gratisalternativ till ADFS med liknande möjligheter, eller vad Entity Framework Core - ett paradis för en utvecklare, där du inte behöver bry dig om att skriva SQL-skript, utan beskriva frågor i databasen i OOP-termer. Men sedan, under diskussionen om handlingsplanen, tittade jag på denna stack som om den var sumerisk kilskrift, och kände bara igen PostgreSQL och Git.

På den tiden använde vi aktivt Marionett som ett konfigurationshanteringssystem. I de flesta av våra projekt använde vi GitLab CI, Elastisk, balanserade högbelastningstjänster med hjälp av HAProxy övervakade allt med Zabbix, ligament grafana и Prometheus, Jaeger, och allt detta snurrade på järnbitar HPESXi på VMware. Alla vet det - en klassiker i genren.

.NET Core på Linux, DevOps på hästryggen

Låt oss titta och försöka förstå vad som hände innan vi påbörjade alla dessa ingrepp.

Vad hände

TFS är ett ganska kraftfullt system som inte bara levererar kod från utvecklaren till den slutliga produktionsmaskinen, utan också har en uppsättning för mycket flexibel integration med olika tjänster – för att tillhandahålla CI på plattformsoberoende nivå.

.NET Core på Linux, DevOps på hästryggen
Tidigare var det rejäla fönster. TFS använde flera Build-agenter, som användes för att montera många projekt. Varje agent har 3-4 arbetare för att parallellisera uppgifter och optimera processen. Sedan, enligt släppplaner, levererade TFS den nybakade Build till Windows-applikationsservern.

Vad ville vi uppnå?

Vi använder TFS för leverans och utveckling och kör applikationen på en Linux applikationsserver, och det finns någon form av magi mellan dem. Detta magisk låda och där är saltet av det arbete som ligger framför oss. Innan jag tar isär den tar jag ett steg åt sidan och säger några ord om applikationen.

Projekt

Applikationen tillhandahåller funktionalitet för hantering av kontantkort.

.NET Core på Linux, DevOps på hästryggen

Klient

Det fanns två typer av användare. Först fick åtkomst genom att logga in med ett SSL SHA-2-certifikat. U den andra det fanns åtkomst med inloggning och lösenord.

haproxy

Sedan gick klientförfrågan till HAProxy, som löste följande problem:

  • primär auktorisation;
  • SSL uppsägning;
  • tuning HTTP-förfrågningar;
  • sändningsförfrågningar.

Klientcertifikatet verifierades längs kedjan. Vi - myndighet och det har vi råd med, eftersom vi själva utfärdar certifikat till servicekunder.

Var uppmärksam på den tredje punkten, vi återkommer till den lite senare.

backend

De planerade att göra backend på Linux. Backend interagerar med databasen, laddar den nödvändiga listan med privilegier och ger sedan, beroende på vilka privilegier den auktoriserade användaren har, tillgång till att signera finansiella dokument och skicka dem för exekvering, eller generera någon form av rapport.

Besparingar med HAProxy

Utöver de två sammanhang som varje klient navigerade, fanns det också en identitetskontext. IdentityServer4 låter dig bara logga in, detta är en gratis och kraftfull analog för ADFS - Active Directory Federation Services.

Identitetsbegäran behandlades i flera steg. Första steget - kund kom in i backend, som kommunicerade med denna server och kontrollerade närvaron av en token för klienten. Om den inte hittades returnerades förfrågan tillbaka till det sammanhang som den kom från, men med en omdirigering, och med omdirigeringen gick den till identitet.

Andra steget - begäran mottogs till auktoriseringssidan i IdentityServer, där klienten registrerade sig, och den efterlängtade token dök upp i IdentityServer-databasen.

Tredje steget - klienten omdirigerades tillbaka till sammanhanget från vilket det kom.

.NET Core på Linux, DevOps på hästryggen

IdentityServer4 har en funktion: den returnerar svaret på returförfrågan via HTTP. Oavsett hur mycket vi kämpade med att sätta upp servern, hur mycket vi än upplyste oss med dokumentationen, fick vi varje gång en initial klientförfrågan med en URL som kom via HTTPS, och IdentityServer returnerade samma sammanhang, men med HTTP. Vi blev chockade! Och vi överförde allt detta genom identitetskontexten till HAProxy, och i rubrikerna var vi tvungna att ändra HTTP-protokollet till HTTPS.

Vad är förbättringen och var sparade du?

Vi sparade pengar genom att använda en gratis lösning för att auktorisera en grupp användare, resurser, eftersom vi inte placerade IdentityServer4 som en separat nod i ett separat segment, utan använde den tillsammans med backend på samma server där backend av applikationen körs .

Hur det ska fungera

Så, som jag lovade - Magic Box. Vi förstår redan att vi garanterat kommer att gå mot Linux. Låt oss formulera specifika uppgifter som krävde lösningar.

.NET Core på Linux, DevOps på hästryggen

Dockan manifesterar sig. För att leverera och hantera service och applikationskonfiguration behövde man skriva coola recept. En pennrulle visar vältaligt hur snabbt och effektivt det gjordes.

Leverans metod. Standarden är RPM. Alla förstår att i Linux kan du inte klara dig utan det, men själva projektet, efter montering, var en uppsättning körbara DLL-filer. Det var cirka 150 stycken, projektet var ganska svårt. Den enda harmoniska lösningen är att paketera denna binära fil i RPM och distribuera applikationen från den.

Versionering. Vi var tvungna att släppa väldigt ofta och vi var tvungna att bestämma hur vi skulle bilda paketnamnet. Detta är en fråga om graden av integration med TFS. Vi hade en byggagent på Linux. När TFS skickar en uppgift till en hanterare - arbetare - till Build-agenten skickar den också ett gäng variabler till den som hamnar i hanterarprocessens miljö. Dessa miljövariabler innehåller byggnamnet, versionsnamnet och andra variabler. Läs mer om detta i avsnittet "Bygga ett RPM-paket".

Konfigurera TFS kom till att sätta upp Pipeline. Tidigare samlade vi alla Windows-projekt på Windows-agenter, men nu dyker det upp en Linux-agent - en Build-agent, som måste inkluderas i bygggruppen, berikad med några artefakter och berättade vilken typ av projekt som kommer att byggas på denna Build-agent , och på något sätt ändra Pipeline.

IdentityServer. ADFS är inte vårt sätt, vi går för öppen källkod.

Låt oss gå igenom komponenterna.

magisk låda

Består av fyra delar.

.NET Core på Linux, DevOps på hästryggen

Linux Build-agent. Linux, eftersom vi bygger för det - det är logiskt. Denna del gjordes i tre steg.

  • Konfigurera arbetare och inte ensam, eftersom fördelat arbete på projektet förväntades.
  • Installera .NET Core 1.x. Varför 1.x när 2.0 redan är tillgängligt i standardförvaret? För när vi startade utvecklingen var den stabila versionen 1.09, och det beslutades att göra projektet baserat på det.
  • Git 2.x.

RPM-förråd. RPM-paket behövde lagras någonstans. Det antogs att vi skulle använda samma företags RPM-förråd som är tillgängligt för alla Linux-värdar. Det var vad de gjorde. Lagringsservern är konfigurerad WebHook som laddade ner det erforderliga RPM-paketet från den angivna platsen. Paketversionen rapporterades till webhook av Build-agenten.

GitLab. Uppmärksamhet! GitLab här används inte av utvecklare, utan av driftavdelningen för att kontrollera applikationsversioner, paketversioner, övervaka statusen för alla Linux-maskiner, och den lagrar receptet - alla Puppet-manifest.

Marionett — löser alla kontroversiella problem och levererar exakt den konfiguration vi vill ha från Gitlab.

Vi börjar dyka. Hur fungerar DLL-leverans till RPM?

Leverans DDL till RPM

Låt oss säga att vi har en .NET-utvecklingsrockstjärna. Den använder Visual Studio och skapar en releasegren. Efter det laddar den upp den till Git, och Git här är en TFS-enhet, det vill säga det är applikationsförrådet som utvecklaren arbetar med.

.NET Core på Linux, DevOps på hästryggen

Därefter ser TFS att en ny commit har kommit. Vilken app? I TFS-inställningarna finns en etikett som anger vilka resurser en viss Build-agent har. I det här fallet ser han att vi bygger ett .NET Core-projekt och väljer en Linux Build-agent från poolen.

Build-agenten tar emot källorna och laddar ner de nödvändiga beroenden från .NET-förvaret, npm, etc. och efter att ha byggt själva applikationen och efterföljande paketering, skickar RPM-paketet till RPM-förrådet.

Å andra sidan händer följande. Driftsavdelningens ingenjör är direkt involverad i utbyggnaden av projektet: han ändrar versionerna av paket i Hiera i arkivet där applikationsreceptet lagras, varefter Puppet triggs Yum, hämtar det nya paketet från förvaret och den nya versionen av programmet är redo att användas.

.NET Core på Linux, DevOps på hästryggen

Allt är enkelt i ord, men vad händer i själva Build-agenten?

Förpackning DLL RPM

Fått projektkällor och bygguppgift från TFS. Byggagent börjar bygga själva projektet från källor. Det sammansatta projektet finns som ett set DLL-filer, som är förpackade i ett zip-arkiv för att minska belastningen på filsystemet.

ZIP-arkivet slängs till RPM-paketets byggkatalog. Därefter initierar Bash-skriptet miljövariablerna, hittar Build-versionen, projektversionen, sökvägen till build-katalogen och kör RPM-build. När bygget är klart publiceras paketet till lokalt förvar, som finns på Build-agenten.

Därefter från Build-agenten till servern i RPM-förvaret JSON-förfrågan skickas anger namnet på versionen och build. Webhook, som jag pratade om tidigare, laddar ner just detta paket från det lokala förvaret på Build-agenten och gör den nya sammansättningen tillgänglig för installation.

.NET Core på Linux, DevOps på hästryggen

Varför just detta paketleveransschema till RPM-förrådet? Varför kan jag inte omedelbart skicka det sammansatta paketet till förvaret? Faktum är att detta är en förutsättning för att säkerställa säkerheten. Detta scenario begränsar möjligheten för obehöriga att ladda upp RPM-paket till en server som är tillgänglig för alla Linux-maskiner.

Databasversionering

Vid en konsultation med utvecklingsteamet visade det sig att killarna var närmare MS SQL, men i de flesta icke-Windows-projekt använde vi redan PostgreSQL med all kraft. Eftersom vi redan hade bestämt oss för att överge allt betalt började vi använda PostgreSQL även här.

.NET Core på Linux, DevOps på hästryggen

I den här delen vill jag berätta hur vi versionerade databasen och hur vi valde mellan Flyway och Entity Framework Core. Låt oss titta på deras för- och nackdelar.

Nackdelar

Flyway går bara åt ett håll, vi vi kan inte rulla tillbaka - Detta är en betydande nackdel. Du kan jämföra det med Entity Framework Core på andra sätt - när det gäller utvecklarbekvämlighet. Du kommer ihåg att vi satte detta på spetsen, och huvudkriteriet var att inte ändra något för Windows-utveckling.

För Flyway us någon form av omslag behövdesså att killarna inte skriver SQL-frågor. De är mycket närmare att fungera i OOP-termer. Vi skrev instruktioner för att arbeta med databasobjekt, genererade en SQL-fråga och körde den. Den nya versionen av databasen är klar, testad - allt är bra, allt fungerar.

Entity Framework Core har ett minus - under tung belastning bygger suboptimala SQL-frågor, och neddragningen i databasen kan vara betydande. Men eftersom vi inte har en högbelastningstjänst, beräknar vi inte belastningen i hundratals RPS, vi accepterade dessa risker och delegerade problemet till framtida oss.

Fördelar

Entity Framework Core fungerar ur lådan och är lätt att utveckla, och Flyway Integreras enkelt i befintlig CI. Men vi gör det bekvämt för utvecklare :)

Roll-up procedur

Puppet ser att en förändring i paketversionen kommer, inklusive den som ansvarar för migreringen. Först installerar den ett paket som innehåller migreringsskript och databasrelaterad funktionalitet. Efter detta startas programmet som fungerar med databasen om. Därefter kommer installationen av de återstående komponenterna. Ordningen i vilken paket installeras och applikationer startas beskrivs i Puppet-manifestet.

Applikationer använder känslig data, såsom tokens, databaslösenord, allt detta dras in i konfigurationen från Puppet master, där de lagras i krypterad form.

TFS problem

Efter att vi bestämt oss och insett att allt verkligen fungerade för oss, bestämde jag mig för att titta på vad som pågick med monteringarna i TFS som helhet för Win-utvecklingsavdelningen på andra projekt - oavsett om vi byggde/släpper snabbt eller inte, och upptäckt betydande problem med hastigheten.

Ett av huvudprojekten tar 12-15 minuter att montera - det är lång tid, du kan inte leva så. En snabb analys visade en fruktansvärd neddragning i I/O, och detta var på arrayer.

Efter att ha analyserat det komponent för komponent, identifierade jag tre foci. Först - "Kaspersky antivirus", som skannar källor på alla Windows Build-agenter. andra - Windows Indexerare. Det var inte inaktiverat och allt indexerades i realtid på Build-agenterna under distributionsprocessen.

Tredje - Npm installera. Det visade sig att vi i de flesta pipelines använde detta exakta scenario. Varför är han dålig? Npm-installationsproceduren körs när beroendeträdet bildas i package-lock.json, där versionerna av paket som kommer att användas för att bygga projektet registreras. Nackdelen är att Npm install drar upp de senaste versionerna av paket från Internet varje gång, och detta tar mycket tid i fallet med ett stort projekt.

Utvecklare experimenterar ibland på en lokal maskin för att testa hur en viss del eller hela projektet fungerar. Ibland visade det sig att allt var coolt lokalt, men de monterade ihop det, rullade ut det och ingenting fungerade. Vi börjar ta reda på vad problemet är - ja, olika versioner av paket med beroenden.

beslutet

  • Källor i AV undantag.
  • Inaktivera indexering.
  • Gå till npm ci.

Fördelarna med npm ci är att vi Vi samlar in beroendeträdet en gång, och vi får möjlighet att tillhandahålla utvecklaren aktuell lista över paket, som han kan experimentera lokalt med så mycket han vill. Detta sparar tid utvecklare som skriver kod.

konfiguration

Nu lite om förvarets konfiguration. Historiskt använder vi Nexus för hantering av förråd, inklusive Intern REPO. Det här interna arkivet innehåller alla komponenter som vi använder för interna ändamål, till exempel självskriven övervakning.

.NET Core på Linux, DevOps på hästryggen

Vi använder också NuGet, eftersom den har bättre cachning jämfört med andra pakethanterare.

Resultat

Efter att vi optimerat byggagenterna minskade den genomsnittliga byggtiden från 12 minuter till 7.

Om vi ​​räknar alla maskiner som vi kunde ha använt för Windows, men som bytte till Linux i det här projektet, sparade vi cirka $10 000. Och det är bara på licenser, och mer om vi tar hänsyn till innehållet.

planer

Under nästa kvartal planerade vi att arbeta med att optimera kodleveransen.

Byter till en förbyggd Docker-bild. TFS är en häftig sak med många plugins som låter dig integreras i Pipeline, inklusive triggerbaserad montering av, säg, en Docker-bild. Vi vill göra denna trigger för samma package-lock.json. Om sammansättningen av komponenterna som används för att bygga projektet på något sätt förändras, bygger vi en ny Docker-bild. Den används senare för att distribuera behållaren med den sammansatta applikationen. Så är inte fallet nu, men vi planerar att byta till en mikrotjänstarkitektur i Kubernetes, som aktivt utvecklas i vårt företag och har betjänat produktionslösningar under lång tid.

Sammanfattning

Jag uppmuntrar alla att slänga Windows, men det är inte för att jag inte vet hur man lagar det. Anledningen är att de flesta Opensource-lösningar är det Linux-stack. mår du bra spara på resurser. Enligt min åsikt tillhör framtiden Open Source-lösningar på Linux med en kraftfull community.

Talarprofil för Alexander Sinchinov på GitHub.

DevOps Conf är en konferens om integrering av utvecklings-, test- och driftprocesser för proffs av proffs. Det var därför projektet som Alexander pratade om? implementerade och fungerar, och på föreställningsdagen var det två framgångsrika släpp. På DevOps Conf på RIT++ Den 27 och 28 maj kommer det att dyka upp ännu fler liknande fall från utövare. Du kan fortfarande hoppa in i den sista vagnen och lämna en rapport eller ta dig tid bok biljett. Möt oss i Skolkovo!

Källa: will.com

Lägg en kommentar