.NET Core на Linux, DevOps на коня

Развивахме DevOps как можехме. Бяхме 8 души и Васил беше най-добрият по Windows. Внезапно Васил напусна, а аз получих задачата да стартирам нов проект, който предлага Windows разработка. Когато изсипах всичките технологии за Windows разработка на масата, осъзнах, че ситуацията е болезнена...

Така започва историята Александра Синчинова на DevOpsConf. Когато от компанията напусна водещият специалист по Windows, Александър се запита какво да прави сега. Разбира се, да премине на Linux! Александър ще разкаже как успя да създаде прецедент и да прехвърли част от Windows разработката на Linux на примера на реализирания проект с 100 000 крайните потребители.

.NET Core на Linux, DevOps на коня

Как лесно и неусетно да доставиш проект в RPM, използвайки TFS, Puppet, Linux .NET core? Как да поддържаш версионирането на базата данни на проекта, ако разработчиците за пръв път чуват думите Postgres и Flyway, а срокът е утре? Как да интегрираш с Docker? Как да мотивираш .NET разработчиците да се откажат от Windows и смутито в полза на Puppet и Linux? Как да решаваш идеологическите конфликти, когато обслужването на Windows в продукция е невъзможно? За това, както и за Web Deploy, тестване, CI, за практиките на използване на TFS в съществуващите проекти и, разбира се, за счупените опори и работещите решения, в разъяснението на доклада на Александър.

Възпроизведи видео

И така, Васил напусна, задачата е моя, разработчиците чакат нетърпеливо. Когато окончателно осъзнах, че Васил не може да се върне, започнах с работата. Първо оцених процента на Win VM в нашия парк. Резултатът не беше в полза на Windows.

.NET Core на Linux, DevOps на коня

Тъй като активно развиваме DevOps, осъзнах, че трябва да променим подхода при изнасянето на ново приложение. Решението беше едно - по възможност да преместим всичко на Linux. Google ми помогна - тогава вече беше портирован .Net под Linux и осъзнах, че това е решението!

Защо .NET core в комбинация с Linux?

Имаше няколко причини. Между "плащането" и "неплащането" повечето ще изберат второто - както и аз. Лицензията за MSDB струва около 1 000 $, поддръжката на парка виртуални машини Windows се изчислява на стотици долари. За голяма компания това са значителни разходи. Затова икономията — е първата причина. Не е най-важната, но е сред значимите.

Виртуалните машини Windows изискват повече ресурси от своите Linux братя - те са тежки. Имайки предвид мащаба на голямата компания, избрахме Linux.

Системата се интегрира безпроблемно в съществуващия CI. Считаме себе си за напреднали DevOps специалисти, използваме Bamboo, Jenkins и GitLab CI, затова голяма част от работата ни протича на Linux.

Последната причина е удобното поддържане. Трябваше да намалим прага на влизане за 'поддържащите' – хората, които разбират техническата част, осигуряват непрекъснатост и обслужват услугите от второ ниво. Те вече бяха запознати с Linux стек, затова им беше много по-лесно да разберат новия продукт, да го поддържат и обслужват, отколкото да влагат допълнителни ресурси, за да се запознаят с подобен функционал на софтуер за Windows платформа.

Изисквания

Първото и най-важно е удобството на новото решение за разработчиците. Не всички от тях бяха готови за промени, особено след произнесената дума Linux. Разработчиците искат любимата си Visual Studio, TFS с автотестове за билдове и смути. Как става доставката в продукция – не им е важно. Затова решихме да не променяме познатия процес и да оставим всичко за Windows разработката без изменения.

Новият проект трябва да бъде интегриран в съществуващия CI. Rails вече бяха на разположение и цялата работа трябваше да бъде извършена с оглед на параметрите на системата за управление на конфигурацията, приетите стандарти за доставка и системите за мониторинг.

Лесната поддръжка и експлоатация, като условие за минимален праг на влизане за всички нови участници от различни подразделения и отдела за поддръжка.

Крайният срок е вчера.

Групата по Win разработка

С какво тогава работеше екипът Windows?

.NET Core на Linux, DevOps на коня

Сега мога уверено да кажа, че IdentityServer4 е страхотна безплатна алтернатива на ADFS с подобни възможности, или че Entity Framework Core е рай за разработчика, където можеш да не се тревожиш за написването на SQL скриптове, а да описваш заявки в БД в термини на ООП. Но тогава, на обсъждането на плана за действие, гледах на този стек като на шумерска клинопис, разпознавайки само PostgreSQL и Git.

В този момент активно използвахме Puppet като система за управление на конфигурацията. В повечето ни проекти използвахме GitLab CI, Elastic, балансирахме високо натоварени услуги с помощта на HAProxy, наблюдавахме всичко с помощта на Zabbix, връзката Grafana и Prometheus, Jaeger, и всичко това работеше на хардуер HP с ESXi на VMware. Всички го знаят – класика на жанра.

.NET Core на Linux, DevOps на коня

Нека да разгледаме и да се опитаме да разберем какво се случваше преди да започнем всички тези намеси.

Какво стана

TFS е доста мощна система, която не само доставя код от разработчика до крайната производствена машина, но също така има набор за много гъвкава интеграция с различни услуги - за осигуряване на CI на кросплатформено ниво.

.NET Core на Linux, DevOps на коня
По-рано това бяха чисто прозорци. TFS използваше няколко Build агента, на които се събираха множество проекти. Във всеки агент имаше по 3-4 worker-а, за да паралелизира задачите и оптимизира процеса. След това, съгласно плановете за пускане, TFS доставяше прясно изпечен Build на Windows сървър на приложения.

Къде искахме да стигнем

За доставка и разработка използваме TFS, а стартираме приложението на Linux Application server, и между тях има някаква магия. Това Magic Box е солта на предстоящата работа. Преди да го разглобя на части, ще направя крачка встрани и ще кажа две думи за приложението.

Проект

Приложението предоставя функционалност за работа с предплатени карти.

.NET Core на Linux, DevOps на коня

Client

Съществуваха два типа потребители. Първият получаваше достъп, авторизирайки се с SSL SHA-2 сертификат. У второ имаше достъп чрез логин и парола.

HAProxy

След това клиентската заявка попадаше в HAProxy, който решаваше следните задачи:

  • първична авторизация;
  • терминиране на SSL;
  • настройка на HTTP заявките;
  • превод на заявките.

Проверка на клиентския сертификат минаваше по веригата. Ние - authority и можем да си позволим такова нещо, тъй като сами издаваме сертификати на клиентите на услугата.

Обърнете внимание на третия пункт, по-късно ще се върнем към него.

Backend

Бекендът планирахме да направим на Linux. Бекендът взаимодейства с БД, зарежда необходимия списък от привилегии и след това, в зависимост от това, какви привилегии има авторизираният потребител, предоставя достъп за подписване на финансови документи и изпращане за изпълнение, или генериране на някакъв отчет.

Икономия с HAProxy

Освен два контекста, по които минаваше всеки от клиентите, съществуваше още контекст identity. IdentityServer4 какъвто точно дава възможност за авторизация, това е безплатен и мощен аналог на ADFS — Active Directory Federation Services.

Заявката в identity се обработваше в няколко стъпки. Първата стъпка - клиент попадаше в бекенда, който обменяше данни с този сървър и проверяваше наличието на токен за клиента. Ако не намираше такъв – заявката се връщаше обратно на контекста, от който бе изпратена, но вече с редирект, и с редирект се отправяше към identity.

Вторият етап – заявката попадаше на страницата за удостоверяване в IdentityServer, където клиентът се регистрираше, а в базата данни на IdentityServer се появяваше този дългоочакван токен.

Третият етап – клиентът се редиректваше обратно на контекста, от който е изпратен.

.NET Core на Linux, DevOps на коня

При IdentityServer4 има особеност: отговорът на обратната заявка се връща по HTTP. Каквото и да правехме с настройката на сървъра, каквато и документация да прегледахме, всеки път получавахме първоначалната заявка на клиента с URL, който беше изпратен по HTTPS, а IdentityServer връщаше същия контекст, но с HTTP. Бяхме в шок! И всичко това го пренасочихме през контекста identity на HAProxy, а в хедерите трябваше да модифицираме протокола от HTTP на HTTPS.

В какво се изразява подобрението и къде спестихме?

Спестихме пари, използвайки безплатно решение за удостоверяване на група потребители, ресурси, тъй като не изнесохме IdentityServer4 като отделен възел в отделен сегмент, а го използвахме съвместно с бекенда на същия сървър, на който работи приложението.

Как трябва да работи

И така, както обещах – Magic Box. Вече разбираме, че стабилно се движим в посока Linux. Нека формулираме конкретни задачи, които изискваха решение.

.NET Core на Linux, DevOps на коня

Манифестите Puppet. За да доставяме и управляваме конфигурацията на услугата и приложението, беше необходимо да напишем страхотни рецепти. Рулончето с молив красноречиво показва как бързо и качествено беше направено.

Начин на доставка. Стандартът – това е RPM. Всички разбират, че в Linux без него не може, но самият проект след компилация представляваше набор от изпълними DLL файлове. Бяха около 150, проектът е доста тежък. Единственото хармонично решение – да опаковаме тази бинарна мизерия в RPM и вече от него да разгръщаме приложението.

Версиониране. Необходимо беше да публикуваме много често и трябваше да решим как да форматираме името на пакета. Това е въпрос на интеграция с TFS. Build-агентът ни беше на Linux. Когато TFS изпраща задача на обработвача – worker – на Build-агента, той му предава и набор от променливи, които попадат в средата на процеса на обработка. В тези променливи на околната среда се предават името на Build, името на версията и други променливи. Повече за това в раздела „създаване на RPM-пакет“.

Настройка на TFS състоеше в настройката на Pipeline. По-рано събирахме всички Windows проекти на Windows-агенти, а сега се появява Linux-агент – Build-агент, който трябва да бъде включен в групата за събиране, да бъде обогатен с определени артефакти и да се уточни какъв тип проекти ще бъдат събирани на този Build-агент и как да модифицираме Pipeline.

IdentityServer. ADFS не е нашият път, залагаме на Open Source.

Нека разгледаме компонентите.

Magic Box

Състои се от четири части.

.NET Core на Linux, DevOps на коня

Linux Build-агент. Linux, защото събираме за него – логично. Тази част се извършва в три стъпки.

  • Настройка на worker-ите и не един, тъй като се предполагаше разпределена работа по проекта.
  • Инсталиране на .NET Core 1.x. Защо именно 1.x, когато вече е налична версия 2.0 в стандартното хранилище? Защото, когато започнахме разработката, стабилната версия беше 1.09 и проектът решихме да направим за нея.
  • Git 2.x.

RPM-хранилище. RPM-пакетите трябваше да се съхраняват някъде. Предполагаше се, че ще използваме същото корпоративно RPM-хранилище, което е достъпно за всички Linux хостове. Така и стана. На сървъра на хранилището е настроен webhook който изтегля необходимия RPM-пакет от посоченото място. Версията на пакета се съобщава на webhook-a от Build-агента.

GitLab. Внимание! GitLab тук не се използва от разработчиците, а от отдела за експлоатация за контрол на версиите на приложението, версиите на пакетите, мониторинг на състоянието на всички Linux машини и в него се съхранява рецептурата – всички манифести на Puppet.

Puppet – разрешава всички спорни моменти и предоставя точно конфигурацията, която искаме, от GitLab.

Започваме да се потапяме. Как се случва доставката на DLL в RPM?

Доставка на DLL в RPM

Да предположим, че имаме рок-звезда в разработката на .NET. Той използва Visual Studio и създава релизна версия. След това я качва в Git, а Git тук е TFS-сущност, тоест това е репозиторий на приложението, с който работи разработчикът.

.NET Core на Linux, DevOps на коня

След от това TFS вижда, че е пристигнал нов комит. Какво приложение? В настройките на TFS има етикет, с който ресурси разполага определен Build-агент. В този случай той вижда, че компилираме проект на .NET Core и избира Linux Build-агент от пул.

Build-агентът получава изходни кодове, изтегля необходимите dependencies от репозитория на .NET, npm и т.н. и след компилирането на самото приложение и последващото опаковане изпраща RPM пакет в RPM репозитория.

От другата страна се случва следното. Инженерът от отдела за експлоатация работи директно върху внедряването на проекта: променя версиите на пакетите в Hiera в репозитория, където се съхранява рецептурата на приложението, след което Puppet задейства Yum, взема новия пакет от репозитория и новата версия на приложението е готова за използване.

.NET Core на Linux, DevOps на коня

На думи всичко е просто, но какво се случва вътре самият Build-агент?

Опаковане на DLL RPM

Получени са изходни кодове на проекта и задача за компилиране от TFS. Build-агентът стартира компилирането на самия проект от изходните кодове.Събраният проект е наличен под формата на множество DLL файлове, които са опаковани в zip архив за намаляване на натоварването на файловата система.

ZIP архивът се изхвърля в директорията за компилиране на RPM пакета. След това Bash скриптът инициализира променливи на средата, намира версията на Build, версията на проекта, пътя до директорията за компилиране и стартира RPM-build. След приключване на компилирането пакетът се публикува в локалния репозиторий, който се намира на Build-агента.

След това, от Build-агента на сървъра в RPM репозитория се изпраща JSON запитване с указание на името на версията и билда. Webhook, за който говорих по-рано, изтегля този пакет от локалния репозиторий на Build-агента и прави новата компилация налична за инсталиране.

.NET Core на Linux, DevOps на коня

Защо именно такава схема за доставка на пакета в RPM репозитория? Защо не може веднага да се изпрати събрания пакет в репозитория? Въпросът е, че това е условие за осигуряване на сигурността. Такъв сценарий ограничава възможността за неразрешено качване на RPM пакети от странични лица на сървера, който е достъпен за всички Linux машини.

Версиониране на БД

На консилиума с разработчиците беше установено, че на момчетата им е по-близо MS SQL, но в повечето non-Windows проекти вече използвахме PostgreSQL. Тъй като вече решихме да се откажем от всичко платено, започнахме да използваме PostgreSQL и тук.

.NET Core на Linux, DevOps на коня

В тази част искам да разкажа как реализирахме версионирането на базата данни и как избирахме между Flyway и Entity Framework Core. Да разгледаме техните плюсове и минуси.

Недостатъци

Flyway работи само в една посока, ние не можем да се върнем назад — това е съществен недостатък. Сравнението с Entity Framework Core може да се направи по други параметри — от гледна точка на удобството на разработчика. Вие помните, че поставихме това в основата, и основният критерий беше да не променяме нищо за Windows разработката.

За Flyway ни беше нужна някаква обвивка, за да не пишат ребята SQL-заявки. Те са много по-близо до работа в термини на ООП. Написахме инструкции за работа с обекти на базата данни, формулира се SQL заявката и тя се изпълнява. Новата версия на базата данни е готова, тества се — всичко е наред, всичко работи.

При Entity Framework Core има недостатък — при големи натоварвания той генерира не оптимизирани SQL заявки, и спадът в работата на базата данни може да бъде значителен. Но тъй като нашият сервис не е с високо натоварване, ние не измерваме натоварването в стотици RPS, ние поехме тези рискове и делегирахме проблема на бъдещите нас.

Плюсове

Entity Framework Core работи от кутията и е удобен за разработка, а Flyway лесно се интегрира в съществуващ CI. Но ние правим удобства за разработчиците :)

Процедурата по инсталиране

Puppet вижда, че идва промяна на версията на пакетите, сред които е и този, който отговаря за миграцията. Първо инсталира пакета, съдържащ миграционните скриптове и функционала, свързан с базата данни. След това рестартира приложението, което работи с базата данни. Следва инсталирането на останалите компоненти. Последователността на инсталиране на пакетите и стартиране на приложенията е описана в манифеста на Puppet.

Приложенията използват чувствителни данни, като токени, пароли за базата данни, всичко това се извлича в конфигурацията от Puppet master, където се съхраняват в криптиран вид.

Проблеми с TFS

След като се определи и разбере, че всичко наистина работи, реших да погледна какво става със сборките в TFS изобщо за отдела по Windows разработки по другите проекти — бързо ли се събираме/релизираме, и открих съществени проблеми със скоростта.

Един от основните проекти се изгражда за 12-15 минути — това е дълго, така не може да се живее. Бързият анализ показа ужасни спадове по I/O, и то при масивите.

След анализ по компоненти, откроих три огнища. Първото — «Kaspersky antivirus», който на всички Windows Build-агенти сканира изходниците. Втори - Windows Индексиращ. Той не беше деактивиран и на Build-агентите в реално време се индексираше всичко по време на деплоя.

Трети - Npm install. Оказа се, че в повечето Pipelines ние използвахме именно този сценарий. С какво е лошо? Процедурата Npm install стартира при формирането на дървото на зависимостите в package-lock.json, където се фиксират версиите на пакетите, които ще се използват за компилиране на проекта. Минусът е, че Npm install всеки път извлича актуалните версии на пакетите от интернет, а това отнема доста време в случай на голям проект.

Разработчиците понякога експериментират на локалната машина, за да проверят работата на отделна част или целия проект. Понякога се е случвало, че локално всичко е супер, но когато се компилира, не работи. Започваме да разследваме в какво е проблемът - ага, различни версии на пакети с зависимости.

Решение

  • Изходниците в изключения AV.
  • Деактивиране на индексирането.
  • Преминаване на npm ci.

Плюсът на npm ci е, че ние създаваме дървото на зависимостите само веднъж, и получаваме възможността да предоставим на разработчика актуален списък на пакетите, с който той може безпроблемно да експериментира локално. Това спестява време на разработчиците, които пишат код.

Конфигурация

Сега малко за конфигурацията на репозитория. Исторически ние използваме Nexus за управление на репозиториите, включително Internal REPO. В този вътрешен репозиторий се предоставят всички компоненти, които използваме за вътрешни нужди, например, самописни мониторинги.

.NET Core на Linux, DevOps на коня

Ние също така използваме NuGet, тъй като той кешира по-добре в сравнение с другите пакетни мениджъри.

Резултат

След като оптимизирахме Build-агентите, средното време за компилиране спадна от 12 минути до 7.

Ако сметнем всички машини, които можехме да използваме за Windows, но преместихме на Linux в този проект, спестихме около $10 000. И това е само за лицензи, а ако включим разходите за поддръжка - повече.

Планове

За следващото тримесечие планирахме работа по оптимизацията на доставката на код.

Преминаване на предварително изграждане на Docker-образа. TFS е страхотно нещо с много плъгини, които позволяват интегриране в Pipeline, включително и компилиране по тригер, например, Docker-образа. Този тригер искаме да направим за онзи. package-lock.json. Ако по някакъв начин се променя съставът на компонентите, които се използват за сглобяване на проекта — при нас се създава нов Docker образ. В по-нататъшната работа той се използва за разгръщане на контейнер с готовото приложение. В момента това не е така, но планираме да преминем на микросервисна архитектура в Kubernetes, която активно се развива в нашата компания и отдавна обслужва продукционни решения.

Резюме

Призовавам всички да се откажат от Windows, но това не е, защото не знам как да я подготвя. Причината е, че голямата част от решенията с отворен код — това е Linux стек. Вие ще спестите ресурси.От моя гледна точка, бъдещето е в решенията с отворен код на Linux с мощна общност.

Профил на говорителя Александър Синчинов в GitHub.

DevOps Conf — това е конференция за интеграция на процесите на разработка, тестване и експлоатация за професионалисти от професионалисти. Именно затова проектът, за който разказваше Александър, е реализиран и функционира, а в деня на выступлението проведоха два успешни релиза. На DevOps Conf на РИТ++ на 27 и 28 май ще има още повече подобни казуси от практици. Все още можете да се присъедините в последния момент и подадете доклад или без особено натоварване резервирате билет. Срещаме се в Сколково!

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster