A DevOps-t a lehetőségeinkhez mérten fejlesztettük. Nyolcan voltunk, és Vanya volt a legjobb Windows szakértő. Hirtelen Vanya távozott, és nekem kellett egy új projektet beindítanom, ami Windows fejlesztéssel foglalkozik. Amikor az összes Windows fejlesztési eszközt az asztalra terítettem, rájöttem, hogy a helyzet fájdalmas...
Így kezdődik a történet Alexander Sinchinov Gyorsan emlékezzünk vissza, hogyan működik a moduláris aritmetika. Az óra már egy ismert koncepció. Az órák használata . Amikor a cég élő Windows szakértője távozott, Alexander elkezdte keresni a megoldást, hogy mit tegyen most. A válasza: természetesen áttérni Linuxra! Alexander elmeséli, hogyan sikerült példát állítania és átállítania a Windows fejlesztés egy részét Linuxra, egy 100 000 végfelhasználós projekt példáján.

Hogyan lehet könnyedén és problémamentesen kézbesíteni egy projektet RPM-be, a TFS, Puppet és Linux .NET Core használatával? Hogyan támogassuk a projekt adatbázisának verziókezelését, ha a fejlesztők először hallanak a Postgres és a Flyway szavakról, míg a határidő holnapra esedékes? Hogyan integráljuk a Dockert? Hogyan motiváljuk a .NET fejlesztőket arra, hogy mondjanak le a Windowsról és a smoothie-ról a Puppet és Linux javára? Hogyan kezeljük az ideológiai konfliktusokat, ha a Windows kezelésére nincs energia, vágy vagy forrás? Erről, valamint a Web Deploy-ról, a tesztelésről, a CI-ről, a TFS gyakorlati használatáról a meglévő projektekben, és természetesen a törött támaszokról és működő megoldásokról is Alexander előadásának egyértelműsítése során.

Tehát Vanya távozott, a feladat az én nyakamban, a fejlesztők már várják a villáikkal. Amikor végleg rájöttem, hogy Vanyát nem tudom visszaszerezni, nekiláttam a munkának. Először is felmértem a Windows virtuális gépek arányát a parkunkban. Az eredmény nem a Windows javára szólt.

Mivel aktívan fejlesztettük a DevOps-ot, rájöttem, hogy valamit változtatni kell az új alkalmazás kihelyezésének megközelítésében. Az egyetlen megoldás az volt – amennyire csak lehet, mindent át kell állítani Linuxra. A Google segített – addigra már portolták a .Net-et Linuxra, és rájöttem, hogy ez a megoldás!
Miért a .NET Core Linux-szal?
Több oka volt ennek. A legtöbben a 'pénzt adni' és a 'nem pénzt adni' opciónál az utóbbit választják – ahogyan én is. A MSDB licenc körülbelül 1 000 $-ba kerül, és a Windows virtuális gépek fenntartása több száz dollárra rúg. Egy nagy cég számára ezek óriási kiadások. Így megtakarítás — az első ok. Nem a legfontosabb, de jelentős.
A Windows virtuális gépek több erőforrást igényelnek, mint Linux testvéreik – nehézkesek.. Figyelembe véve a nagyvállalat méretét, Linuxot választottunk.
A rendszer egyszerűen integrálódik a meglévő CI-ba.. Magunkat progresszív DevOps-nak tartjuk, Bamboo, Jenkins és GitLab CI-t használunk, így a legtöbb dolog Linuxon fut.
Az utolsó ok — kényelmes karbantartás. Csökkentenünk kellett a belépési küszöböt a "karbantartók" számára - olyan fiatalok, akik értik a technikai részt, biztosítják a zökkenőmentességet és a második vonalbeli szolgáltatásokat üzemeltetik. Már ismerik a Linux stacket, így sokkal könnyebben megértik az új terméket, támogatják és karbantartják, mint hogy plusz forrást kellene fordítani a Windows platformokra hasonló funkcionalitás megértésére.
Követelmények
Elsődleges és legfontosabb — az új megoldás kényelme a fejlesztők számára. Nem mind volt felkészülve a változásokra, különösen a Linux szó után. A fejlesztők a kedvenc Visual Studio-jukat, a TFS-t az automatikus tesztekkel és a smoothieval akarják. Hogy hogyan zajlik a termelésbe való átadás — az nem érdekli őket. Ezért úgy döntöttünk, hogy nem változtatjuk meg a megszokott folyamatot, és mindent változatlanul hagyunk a Windows fejlesztéshez.
Az új projektet be kell építeni a meglévő CI-ba.. A sínek már készen álltak, és az egész munkát a konfigurációs menedzsment rendszer, a fogadott szállítási szabványok és a monitorozó rendszerek paramétereivel kellett elvégezni.
A támogatás és karbantartás egyszerűsége, mint a különböző osztályok és a karbantartó részleg új résztvevői számára a minimális belépési küszöb feltétele.
A határidő — tegnap.
A Windows fejlesztői csoport
Mivel dolgozott a Windows csapat?

Most biztosan mondhatom, hogy IdentityServer4 — egy nagyszerű ingyenes alternatíva az ADFS-hez hasonló lehetőségekkel, vagy hogy Entity Framework Core — a fejlesztők mennyországa, ahol nem kell aggódni SQL szkriptek írása miatt, hanem a lekérdezéseket OOP kifejezésekben lehet leírni az adatbázisban. De akkor, amikor a cselekvési tervet vitattuk, úgy néztem erre a stack-re, mint egy sumér ékírásra, csak a PostgreSQL-t és a Git-et ismerve.
Akkoriban aktívan használtuk Puppet mint konfigurációs menedzsment rendszert. A projektjeink többségében használtuk GitLab CI, Elastic, nagy terheléssel bíró szolgáltatásokat egyensúlyoztunk a HAProxy, mindezt figyeltük a Zabbix, a kombináción keresztül, Grafanába és Prometheus, Jaeger, és mindez a HP c ESXi Gyorsan emlékezzünk vissza, hogyan működik a moduláris aritmetika. Az óra már egy ismert koncepció. Az órák használata VMware.Mindenki ismeri — a műfaj klasszikusát.

Nézzük meg, és próbáljuk megérteni, mi történt mielőtt belekezdtünk ebbe a beavatkozás sorozatba.
Mi volt
A TFS egy meglehetősen erős rendszer, amely nemcsak a kódot juttatja el a fejlesztőtől a végső produkciós gépig, hanem egy nagyon rugalmas integrációs keretet is kínál különböző szolgáltatásokkal - a CI biztosítása érdekében többplatformos szinten.

Korábban csupa ablak volt. A TFS több Build-ügynököt használt, amelyeken sok projekt gyűlt össze. Minden ügynökben 3-4 munkás, hogy párhuzamosítsa a feladatokat és optimalizálja a folyamatot. Ezután a kiadási tervek szerint a TFS frissen készült Buildet szállított egy Windows alkalmazásszerverre.
Hova akartunk eljutni
A TFS-t használjuk a szállításhoz és fejlesztéshez, az alkalmazást pedig Linux alkalmazásszerveren indítjuk el, közöttük meg valami varázslat. Ez a varázsdoboz és ez a munka kulcsa. Mielőtt megfejtenénk, egy lépést hátralépek, és mondok pár szót az alkalmazásról.
Projekt
Az alkalmazás funkciót biztosít előre fizetett kártyák kezelésére.

Ügyfél
Kétféle felhasználó létezett. Az első hozzáférést kapott, SSL SHA-2 tanúsítványon keresztül hitelesítve. A második felhasználónévvel és jelszóval lépett be.
HAProxy
Ezután az ügyfélkérés a HAProxy-ba került, amely az alábbi feladatokat oldotta meg:
- elsődleges hitelesítés;
- SSL lezárás;
- HTTP kérések optimalizálása;
- kérések továbbítása.
A kliens tanúsítványának ellenőrzése láncon keresztül zajlott. Mi vagyunk a hatóság és ezt megengedhetjük magunknak, mivel magunk adjuk ki a tanúsítványokat a szolgáltatás ügyfeleinek.
Figyeljen a harmadik pontra, kicsit később visszatérünk rá.
Backend
A backend Linuxra volt tervezve. A backend interakcióba lép az adatbázissal, betölti a szükséges jogosultságlisztát, majd attól függően, hogy milyen jogosultságokkal rendelkezik a hitelesített felhasználó, hozzáférést biztosít pénzügyi dokumentumok aláírásához és azok végrehajtásra küldéséhez, vagy valamilyen jelentés generálásához.
Megtakarítás a HAProxy-val
A két kontextus mellett, amelyeken minden ügyfél végighaladt, volt még egy identity kontextus. IdentityServer4 amely lehetővé teszi a hitelesítést, ez egy ingyenes és erős alternatíva a ADFS — Active Directory Federation Services.
Az identity-re küldött kérés több lépésben lett feldolgozva. Az első lépés - az ügyfél a backendbe került., amely adatokat cserélt ezzel a szerverrel és ellenőrizte az ügyfél tokenjének meglétét. Ha nem találta, a kérés visszatért arra a kontextusra, ahonnan érkezett, de már átirányítással, és az átirányítás az identity-re ment.
A második lépés - a kérés eljutott az IdentityServer bejelentkezési oldalára, ahol az ügyfél regisztrált, és az IdentityServer adatbázisában megjelent az a régóta várt token.
A harmadik lépés - az ügyfél visszairányítódott arra a kontextusra, ahonnan érkezett.

Az IdentityServer4-nek van egy sajátossága: a visszairányított kérésre HTTP-n keresztül válaszol,. Akárhogy is próbálkoztunk a szerver beállításaival, akárhány dokumentációt elolvastunk, de minden alkalommal az ügyfél kezdeti kérését kaptuk meg URL-lel, amely HTTPS-en érkezett, míg az IdentityServer ugyanazon kontextust visszajuttatta HTTP-val. Megdöbbentünk! És mindezt az identity kontextuson keresztül átirányítottuk a HAProxy-ra, a fejekben pedig a HTTP protokollt HTTPS-re kellett módosítanunk.
Mi az előny, és hol spóroltunk?
Pénzt spóroltunk azáltal, hogy ingyenes megoldást használtunk a felhasználói csoportok hitelesítésére, forrásokat, mivel az IdentityServer4-et egy külön nodként külön szegmensben nem futtattuk, hanem együtt használtuk az alkalmazás backendjével ugyanazon a szerveren, ahol a backend működik.
Hogyan kell működnie
Tehát, ahogy ígértem - Magic Box. Már értjük, hogy garantáltan a Linux irányába haladunk. Formáljunk meg konkrét feladatokat, amelyek megoldásra vártak.

Puppet manifesztumok. A szolgáltatás és az alkalmazás konfigurációs kezeléséhez klassz recepteket kellett írni. A ceruza és a tekercs beszédesen mutatja, hogy mennyire gyorsan és minőségben készült el ez.
A szállítás módja. A standard az RPM. Mindenki tudja, hogy Linuxon nélküle nem lehet, de maga a projekt fordítás után egy futtatható DLL-fájlok halmazaként jelent meg. Körülbelül 150 volt belőle, a projekt elég nehéz. Az egyetlen harmonikus megoldás, hogy ezt a bináris anyagot RPM-be csomagoljuk, és már abból telepítsük az alkalmazást.
Verziókezelés. Sűrűn kellett kiadnunk, és meg kellett határoznunk, hogyan alakítsuk ki a csomag nevét. Ez a TFS integrációs szintjének kérdése. A Build-ügynökünk Linuxon futott. Amikor a TFS felad egy feladatot az ügynöknek - worker - a Build-ügynökön, átkonvertálja számára a szükséges változókat, amelyeket a folyamat környezeti változóihoz ad. Ezek között a környezeti változók között átadható a Build neve, a verzió neve és egyéb változók. További részletek a 'RPM-csomag építése' részben találhatóak.
TFS beállítása a Pipeline beállítására összpontosult. Korábban a Windows-ügynökökön gyűjtöttük az összes Windows-projektet, most viszont megjelenik a Linux-ügynök - Build-ügynök, amelyet be kell iktatni az építési csoportba, bizonyos artefaktumokkal gazdagítani, megmondani, milyen típusú projekteket fognak ezen a Build-ügynökön összeállítani, és valamilyen módon módosítani a Pipeline-t.
IdentityServer. Az ADFS nem a mi utunk, az Open Source mellett állunk ki.
Nézzük át a komponenseket.
varázsdoboz
Négy részből áll.

Linux Build-ügynök. Linux, mert erre állítjuk össze - logikus. Ezt a részt három lépésben végeztük el.
- Ügynökök beállítása és nem egyet, mert elvártuk a projekt elosztott munkáját.
- A .NET Core 1.x telepítése. Miért éppen 1.x, amikor már elérhető a 2.0 a standard tárolóban? Mert amikor elkezdtük a fejlesztést, az 1.09 stabil verzió volt, így ezt a verziót választottuk a projekthez.
- Git 2.x.
RPM-tároló. Az RPM-csomagokat valahol tárolni kellett. Azt terveztük, hogy ugyanazt a vállalati RPM-tárolót használjuk, amely minden Linux hoszt számára elérhető. Így is tettünk. A tároló szerveren beállítottuk webhook amely letöltötte a megadott helyről a szükséges RPM-csomagot. A webhook verzióját a Build-ügynök közölte.
GitLab. Figyelem! A GitLab itt nem a fejlesztők által, hanem a üzemeltetési osztály által van használva az alkalmazás verzióinak, a csomagok verzióinak, minden Linux-gép állapotának ellenőrzésére, és az összes recept - minden Puppet-manifeszt itt található.
Puppet megoldja a vitás kérdéseket, és pontosan azt a konfigurációt szolgáltatja, amit szeretnénk, a Gitlab-ból.
Kezdjük el mélyebben belemerülni. Hogyan történik a DLL szállítása az RPM-be?
DLL szállítása az RPM-be
Tegyük fel, hogy van egy rockcsillagunk a .NET fejlesztésében. Ő a Visual Studio-t használja, és létrehoz egy kiadási ágat. Ezután feltölti azt a Git-be, és a Git itt - TFS entitás, tehát ez az alkalmazás tárolója, amellyel a fejlesztő dolgozik.

Ezután a TFS észleli, hogy új elkötelezés érkezett. Melyik alkalmazásról van szó? A TFS beállításaiban van egy címke, amely megmutatja, hogy milyen erőforrásokkal rendelkezik az egyes Build-ügynökök. Ebben az esetben látja, hogy .NET Core projektet építünk, ezért a Linux Build-ügynököt választja a poolból.
A Build-ügynök megkapja a forrást, letölti a szükséges függőségeket a .NET, npm stb. tárolóból, majd az alkalmazás építése és a csomagolás után elküldi az RPM-csomagot az RPM-tárolóba.
Másrészt a következő történik. Az üzemeltetési részleg mérnöke közvetlenül a projekt kiadásával foglalkozik: változtatja a csomagok verzióit a Hiera a tárolóban, ahol az alkalmazás receptje található, majd a Puppet aktiválja a Yum-ot,amely letölti az új csomagot a tárolóból, és az új verzió az alkalmazás készen áll a használatra.

Szóban minden egyszerű, de mi történik belül a Build-ügynökön?
DLL RPM csomagolása
Megkaptuk a projekt forrásait és a TFS-től érkező építési feladatot. A Build-ügynök elindítja a project építését a forrásokból.A megépített projekt több DLL fájl formájában érhető el,amelyeket zip-archívumba csomagolnak a fájlrendszer terhelésének csökkentése érdekében.
A ZIP-archívum a RPM csomagépítési könyvtárba kerül. Ezután a Bash-skriptek inicializálják a környezeti változókat, megkeresik a Build verzióját, a projekt verzióját, a build könyvtár elérési útját, és elindítják az RPM-build folyamatot. Az építés befejezése után a csomag publikálásra kerül a helyi tárolóba,amely a Build-ügynökön található.
Ezután a Build-ügynökről a szerverre az RPM-tárolóba JSON-kérést küldenek, amelyben megadják a verzió- és buildnevet. Az általam korábban említett Webhook letölti ezt a csomagot a Build-ügynök helyi tárolójából, és új építést tesz elérhetővé telepítésre.

Miért ilyen a csomagok tárolóba juttatásának terve? Miért nem lehet az összes csomagot közvetlenül a tárolóba küldeni? Az ok az, hogy ez a biztonság biztosítására szolgáló feltétel. Ez a forgatókönyv korlátozza a külső személyek általi jogosulatlan RPM-csomagok feltöltésének lehetőségét a minden Linux-gép számára elérhető szerverre.
DB verziózás
A fejlesztéssel folytatott konzíliumban kiderült, hogy a srácoknak közelebb áll a MS SQL, de a legtöbb nem Windows projektünkben már bőven használtuk a PostgreSQL-t. Mivel már eldöntöttük, hogy lemondunk minden fizetős megoldásról, így itt is a PostgreSQL-t kezdtük el használni.

Ebben a részben szeretném elmondani, hogyan végeztük a DB verzionálását, és hogyan választottunk a Flyway és az Entity Framework Core között. Nézzük meg az előnyeiket és hátrányaikat.
Hátrányok
A Flyway csak egy irányba működik, mi nem tudunk visszaváltani — ez jelentős hátrány. Az Entity Framework Core-ral más paraméterek szerint lehet összehasonlítani — a fejlesztők kényelme szempontjából. Biztosan emlékszik, hogy ezt állítottuk a középpontba, és alapvető kritérium volt, hogy semmit ne változtassunk meg a Windows fejlesztésben.
A Flyway-hoz szükségünk volt valamilyen burkolóra, hogy a srácok ne írjanak SQL-lekérdezéseket. Számukra sokkal kényelmesebb az OOP fogalmaival dolgozni. Írtunk utasításokat az DB objektumokkal való munkához, létrejött az SQL-lekérdezés és végrehajtásra került. Az új DB verzió kész, teszteltük — minden rendben van, minden működik.
Az Entity Framework Core-nak van egy hátránya — nagy terhelés esetén nem optimalizált SQL-lekérdezéseket épít, és a DB teljesítménye jelentős lehet. De mivel nem egy nagy terhelésű szolgáltatással dolgozunk, nem számítunk milliós RPS terhelésre, vállaltuk ezt a kockázatot és a jövőbeli problémát átdelegáltuk magunknak.
Előnyök
Entity Framework Core dobozból működik és kényelmes a fejlesztéshez, míg a Flyway könnyen integrálható a meglévő CI-be. De mi is a fejlesztők kényelmére összpontosítunk :)
A folyamatautomatizálás
A Puppet észleli, hogy változás történt a csomagok verziójában, beleértve azt is, amely a migrációért felelős. Először telepíti azt a csomagot, amely a migrációs szkripteket és az DB-vel kapcsolatos funkciót tartalmazza. Ezután újraindítja az alkalmazást, amely az DB-vel dolgozik. Ezután következik a többi komponens telepítése. A csomagok telepítési sorrendje és az alkalmazások indítása a Puppet manifesztjében van leírva.
Az alkalmazások érzékeny adatokat használnak, például tokeneket, DB jelszavakat, mindezek a konfigurációban a Puppet masterből töltődnek be, ahol titkosított formában tárolják őket.
TFS problémák
Miután eldöntöttük, és megértettük, hogy nálunk tényleg minden jól működik, úgy döntöttem, megnézem, mi történik a TFS buildjeivel az Win-fejlesztési részlegen más projekteknél — gyorsan vagyunk-e a buildel és a kiadáson, és jelentős sebességi problémákat fedeztem fel.
Az egyik fő projekt 12-15 percet vesz igénybe — ez hosszú, így nem lehet élni. Gyors elemzés mutatta, hogy borzalmasan gyenge az I/O, és ez az array-eken.
Megnézve komponensenként három gócpontot azonosítottam. Az első — „Kaspersky antivirus”, amely minden Windows Build-ügynökön beolvassa a forrásokat. A második - Windows Indexer. Nem volt letiltva, és a Build-ügynökök valós időben indexelték az összes folyamatban lévőt a telepítés során.
A harmadik - Npm install. Kiderült, hogy a legtöbb Pipeline-ban éppen ezt a szkriptet használtuk. Mi a hátránya? Az Npm install eljárás a függőségek fájltérképének létrehozásakor fut le. package-lock.json, ahol rögzítik a projektehez felhasznált csomagok verzióit. A hátránya, hogy az Npm install minden alkalommal a legfrissebb verziókat húzza le az internetről, ami jelentős időt vehet igénybe egy nagy projekt esetén.
A fejlesztők néha a helyi gépen kísérleteznek, hogy ellenőrizzék egy-egy rész vagy az egész projekt működését. Néha az történt, hogy helyben minden jól működött, de amikor összeállítottuk és telepítettük, semmi nem működött. Kezdünk utánajárni, mi a probléma - aha, különböző verziók a függőségekből.
Megoldás
- A források az AV kivételekben.
- Az indexálás letiltása.
- Átállás a npm ci.
Az npm ci előnye, hogy a függőségek fájltérképét egyszer állítjuk össze, és lehetőséget ad arra, hogy a fejlesztő számára aktuális csomaglistát, amellyel szabadon kísérletezhet helyben. Ez időt takarít meg a kódot író fejlesztők számára.
Konfiguráció
Most egy kicsit a repozitórium konfigurációjáról. Történelmileg a Nexus-t használjuk a repozitóriumok kezelésére, beleértve az Internal REPO-t.Ebben a belső repozitóriumban találhatóak mindazon komponensek, amelyeket belső célokra használunk, például a saját készítésű monitorozások.

Emellett használjuk a NuGet-et,, mivel jobban cache-eli, mint a többi csomagkezelő.
Eredmény
Miután optimalizáltuk a Build-ügynököket, az átlagos összeállítási idő 12 percről 7 percre csökkent.
Ha számításba vesszük az összes gépet, amelyet használhattunk volna Windows alatt, de ebben a projektben Linuxra váltottunk, körülbelül 10 000 dollárt spóroltunk meg. És ez csak a licenceken, ha figyelembe vesszük a fenntartási költségeket - még többet.
Tervek
A következő negyedévre a kód szállításának optimalizálására terveztük a munkát.
Átállás a prebuildezett Docker-képre. A TFS nagyszerű dolog sok pluginnal, amelyek lehetővé teszik az integrációt a Pipeline-ba, beleértve a trigger szerinti összeállítást, például a Docker-képet. Ezt a triggert akarjuk megvalósítani arra a célra. package-lock.json. Ha valamilyen módon megváltozik a projekt összeállításához használt összetevők összetétele – új Docker-képet készítünk. Ezt követően ezt használjuk a konténer telepítéséhez a létrehozott alkalmazással. Jelenleg ez nincs, de tervezzük, hogy áttérünk a Kubernetes mikroszolgáltatás-architektúrára, amely aktívan fejlődik cégünknél és már régóta támogatja a produkciós megoldásokat.
Összefoglaló
Arra kérek mindenkit, hogy dobnak ki a Windows-t, de nem azért, mert nem tudom elkészíteni. Az oka az, hogy a legtöbb nyílt forráskódú megoldás – ez Linux-stack. Nagyon jól megtakarít pénzt az erőforrásokon. Véleményem szerint a jövő a Linuxon alapuló nyílt forráskódú megoldásoké, erős közösséggel.
A speaker profilja: Alexander Sinchinov .
– egy konferencia a fejlesztési, tesztelési és üzemeltetési folyamatok integrálásáról szakemberek számára szakemberektől. Éppen ezért a projekt, amelyről Alexander beszélt, megvalósult és működik, míg a beszéd napján két sikeres kiadás is zajlott. A május 27-én és 28-án még több hasonló eset lesz a gyakorlóktól. Még lehet ugrani az utolsó vonatra és vagy nyugodtan jegyet. Találkozunk Skolkovo-ban!
Forrás: habr.com
