.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 c аўтатэстамі па зборках і смузи. Як адбываецца дастаўка ў прадакшн - ім не важна. Таму мы вырашылі не мяняць звыклы працэс і пакінуць для Windows-распрацоўкі ўсё без змен.

Новы праект патрэбны ўбудаваць у існуючы CI. Рэйкі ўжо былі і ўсю працу было неабходна выканаць з улікам параметраў сістэмы кіравання канфігурацыяй, прынятых стандартаў дастаўкі і сістэм маніторынгу.

Прастата ў падтрымцы і эксплуатацыі, як умова для мінімальнага парога ўваходжання для ўсіх новых удзельнікаў з боку розных падраздзяленняў і аддзела суправаджэння.

Дэдлайн - учора.

Група Win распрацоўкі

З чым тады працавала каманда Windows?

.NET Core на Linux, DevOps на кані

Цяпер я магу ўпэўнена сказаць, што IdentityServer4 - Гэта класная бясплатная альтэрнатыва ADFS з аналагічнымі магчымасцямі, ці што Ядро Entity Framework - рай для распрацоўніка, дзе можна не затлумляцца напісаннем SQL скрыптоў, а апісваць запыты ў БД у тэрмінах ААП. Але тады, на абмеркаванні плана дзеянняў, я глядзеў на гэты стэк як на шумерскі клінапіс пазнаючы толькі PostgreSQL і Git.

На той момант мы актыўна выкарыстоўвалі Лялечны як сістэму кіравання канфігурацыяй. У большасці нашых праектаў мы прымянялі GitLab CI, Эластычны, балансавалі высоканагружаныя сэрвісы з дапамогай HAProxy, сачылі за ўсім з дапамогай Zabbix, звязкі Графана и Праметэй, Егер, і ўсё гэта круцілася на жалязяках HPESXi на VMware. Усім знаёма - класіка жанру.

.NET Core на Linux, DevOps на кані

Паглядзім і паспрабуем зразумець, што ж адбывалася да таго, як мы задумалі ўсе гэтыя ўмяшанні.

Што было

TFS – гэта даволі магутная сістэма, якая не толькі дастаўляе код ад распрацоўніка да канчатковай прадакшн-машыны, але таксама мае набор для вельмі гнуткай інтэграцыі з рознымі сэрвісамі – для забеспячэння CI на кросплатформавым узроўні.

.NET Core на Linux, DevOps на кані
Раней гэта былі суцэльныя фортачкі. TFS выкарыстоўваў некалькі Build-агентаў, на якіх збіралася мноства праектаў. У кожным агенце па 3-4 worker-a, каб распаралеліць задачы і аптымізаваць працэс. Далей, паводле рэлізных праектаў, TFS дастаўляў новы Build на Windows-сервер прыкладанняў.

Да чаго мы хацелі прыйсці

Для дастаўкі і распрацоўкі выкарыстоўваны TFS, а запускаем дадатак на Linux Application server, і паміж імі нейкая магія. Гэты Чароўная скрынка і ёсць соль маючай адбыцца працы. Перад тым, як разабраць яго па частках, зраблю крок у бок і скажу два словы аб дадатку.

праект

Прыкладанне дае функцыянальнасць для аперыравання прадаплочанымі картамі.

.NET Core на Linux, DevOps на кані

Кліент

Існавала два тыпы карыстальнікаў. Першы атрымліваў доступ, аўтарызуючыся па сертыфікаце SSL SHA-2. У другога быў доступ па лагіне і паролю.

HAProxy

Далей кліенцкі запыт пападаў у HAProxy, які вырашаў наступныя задачы:

  • першасная аўтарызацыя;
  • тэрмінаванне SSL;
  • цюнінг HTTP запытаў;
  • трансляцыя запытаў.

Праверка сертыфіката кліента ішла па ланцужку. Мы - ўлада і можам сабе такое дазволіць, бо самі выдаём сертыфікаты кліентам сэрвісу.

Звярніце ўвагу на трэці пункт, крыху пазней вернемся да яго.

Backend

Бэкенд планавалі зрабіць на Linux. Бэкенд узаемадзейнічае з БД, падгружае неабходны спіс прывілеяў і потым, у залежнасці ад таго, якімі прывілеямі валодае які аўтарызаваўся карыстач, падае доступ для падпісання фінансавых дакументаў і адпраўкі іх на выкананне, або генерацыі нейкай справаздачы.

Эканомія c HAProxy

Апроч двух кантэкстаў, па якіх хадзіў кожны з кліентаў, існаваў яшчэ кантэкст identity. IdentityServer4 як раз дазваляе аўтарызавацца, гэта бясплатны і магутны аналаг для ADFS - Паслугі федэрацыі Active Directory.

Запыт у 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-агент, ён перадае яму яшчэ і банч зменных, якія трапляюць у environment працэсу апрацоўшчыка. У гэтых зменных асяроддзі перадаецца імя Build, імя версіі і іншыя зменныя. Падрабязней пра гэта ў з раздзеле "зборка RPM-пакета".

Настройка TFS зводзілася да налады Pipeline. Раней мы збіралі на Windows-агентах усе Windows-праекты, а цяпер з'яўляецца Linux-агент - Build-агент, які трэба ўключыць у групу зборкі, узбагаціць нейкімі артэфактамі, сказаць, якога менавіта тыпу праекты будуць збірацца на гэтым Build-агенце, і неяк мадыфікаваць Pipeline.

IdentityServer. ADFS не наш шлях, палім за Open Source.

Пройдземся па кампанентах.

Чароўная скрынка

Складаецца з чатырох частак.

.NET Core на Linux, DevOps на кані

Linux Build-агент. Linux, таму што мы пад яго збіраем - лагічна. Гэтая частка выконвалася за тры крокі.

  • Наладзіць worker-ы і не адзін, бо меркавалася размеркаваная праца над праектам.
  • Усталяваць .NET Core 1.х. Чаму менавіта 1.х, калі ўжо даступна 2.0 у стандартным рэпазітары? Бо калі мы пачыналі распрацоўку, стабільнай версіяй была 1.09, і праект было вырашана рабіць пад яе.
  • Git 2.x.

RPM-repository. RPM-пакеты трэба было недзе захоўваць. Меркавалася, што мы будзем выкарыстоўваць той жа самы карпаратыўны RPM-рэпазітар, які даступны ўсім Linux хастам. Так і зрабілі. На серверы рэпазітара настроены вэб -кручок які спампоўваў з паказанага месца патрабаваны RPM-пакет. Версію пакета webhook'у паведамляў Build-агент.

GitLab. Увага! GitLab тут выкарыстоўваецца не распрацоўшчыкамі, а аддзелам эксплуатацыі для кантролю версій прыкладання, версій пакетаў, кантролю стану ўсіх Linux-машын і ў ім захоўваецца рэцэптура – ​​усе маніфесты Puppet.

Лялечны - разрульвае ўсе спрэчныя моманты і дастаўляе менавіта тую канфігурацыю, якую мы жадаем, з Gitlab.

Пачынаем апускацца. Як адбываецца дастаўка DLL у RPM?

Дастаўка DDL у RPM

Дапушчальны, у нас ёсць рок-зорка распрацоўкі на .NET. Ён выкарыстоўвае Visual Studio і стварае рэлізную галінку. Пасля гэтага загружае яе ў Git, і Git тут — TFS-сутнасць, гэта значыць гэта рэпазітар прыкладання, з якім працуе распрацоўнік.

.NET Core на Linux, DevOps на кані

Пасля чаго TFS бачыць, што прыляцеў новы коміт. Якое дадатак? У наладах TFS ёсць пазнака, якімі рэсурсамі валодае той ці іншы Build-агент. У дадзеным выпадку ён бачыць, што мы збіраем. NET Core праект і выбірае Linux Build-агент з пула.

Build-агент атрымлівае зыходнікі, выкачвае неабходныя залежнасці c рэпазітара .NET, npm і г.д. і пасля зборкі самога прыкладання і наступнага пакавання адпраўляе RPM-пакет у RPM-рэпазітар.

З іншага боку, адбываецца наступнае. Інжынер аддзела эксплуатацыі займаецца непасрэдна выкаткай праекта: мяняе версіі пакетаў у Hiera у рэпазітары, дзе захоўваецца рэцэптура прыкладання, пасля чаго Puppet трыгерыт Юм, забірае новы пакет з рэпазітара, і новая версія прыкладання гатова да выкарыстання.

.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 працуе са скрынкі і зручны распрацоўцы, а Flyway лёгка інтэгруецца ў існуючы CI. Але мы ж робім зручна дэвелаперам:)

Працэдура накату

Puppet бачыць, што прыходзіць змена версіі пакетаў сярод якіх, які адказвае за міграцыю. Спачатку ўсталёўвае пакет, дзе змяшчаюцца міграцыйныя скрыпты і функцыянал завязаны на БД. Пасля гэтага рэстартуецца дадатак, якое працуе з БД. Далей ідзе ўстаноўка астатніх кампанентаў. Чарговасць усталёўкі пакетаў і запуску прыкладанняў апісаны ў маніфесце Puppet.

Прыкладанні выкарыстоўваюць адчувальныя дадзеныя, такія як токены, паролі да БД, усё гэта падцягваецца ў канфіг з Puppet master, дзе яны захоўваюцца ў зашыфраваным выглядзе.

Праблемы TFS

Пасля таго, як мы вызначыліся і зразумелі, што ў нас сапраўды ўсё працуе, я вырашыў паглядзець, што робіцца са зборкамі ў TFS у цэлым для аддзела Win-распрацоўкі па іншых праектах – хутка ці не збіраемся/рэлізімся, і выявіў істотныя праблемы са хуткасцю .

Адзін з асноўных праектаў збіраецца 12-15 хвілін - гэта доўга, так жыць нельга. Хуткі аналіз паказаў жудасную прасадку па I/O, і гэта на масівах.

Прааналізаваўшы пакампанентна, я вылучыў тры ачагі. Першы - «Касперскі антывірус», які на ўсіх Windows Build-агентах скануе зыходнікі. Другі - Windows Indexer. Ён не быў адключаны, і на Build-агентах у рэальным часе індэксавалася ўсё падчас дэплояў.

Трэці - NPM install. Аказалася, што ў большасці Pipelines мы выкарыстоўвалі менавіта гэты сцэнар. Чым ён дрэнны? Працэдура Npm install запускаецца пры фармаванні дрэва залежнасцяў у package-lock.json, дзе фіксуюцца версіі пакетаў, якія будуць выкарыстоўвацца для зборкі праекту. Мінус у тым, што Npm install кожны раз падцягвае актуальныя версіі пакетаў з інтэрнэту, а гэта немалы час у выпадку вялікага праекту.

Распрацоўнікі часам эксперыментуюць на лакальнай машыне, каб праверыць працу асобнай часткі ці праекту цалкам. Часам атрымлівалася, што лакальна ўсё крута, але збіралі, выкочваліся - нічога не працавала. Пачынаем разбірацца, у чым праблема - ага, розныя версіі пакетаў з залежнасцямі.

рашэнне

  • Зыходнікі ў выключэнні AV.
  • Адключэнне індэксацыі.
  • Пераход на npm ci.

Плюсы npm ci, у тым, што мы збіраем дрэва залежнасцяў аднойчы, і атрымліваем магчымасць падаць распрацоўніку актуальны спіс пакетаў, з якім ён можа колькі заўгодна эксперыментаваць лакальна. Гэта эканоміць час распрацоўшчыкаў, якія пішуць код.

Канфігурацыя

Цяпер крыху аб канфігурацыі рэпазітара. Гістарычна мы выкарыстоўваем Сувязь для кіравання рэпазітарамі, у тым ліку Internal REPO. У гэты ўнутраны рэпазітар пастаўляюцца ўсе кампаненты, якія мы выкарыстоўваем для ўнутраных мэт, напрыклад, самапісныя маніторынгі.

.NET Core на Linux, DevOps на кані

Мы таксама выкарыстоўваем NuGet, так як ён лепш кэшуецца ў параўнанні з іншымі пакетнымі мэнэджэрамі.

Вынік

Пасля таго, як мы аптымізавалі Build-агентаў, сярэдні час зборкі скарацілася з 12 хвілін да 7.

Калі палічыць усе машыны, якія мы маглі б выкарыстоўваць для Windows, але перавялі на Linux у гэтым праекце, мы зэканомілі парадку $10 000. І гэта толькі на ліцэнзіях, а калі ўлічваць змест - больш.

Планы

На наступны квартал заклалі ў план працу над аптымізацыяй дастаўкі кода.

Пераход на прэбілд Docker-выявы. TFS - класная штука са мноствам плагінаў, якія дазваляюць інтэграваць у Pipeline, у тым ліку, і зборку па трыгеру, дапусцім, Docker-выявы. Гэты трыгер мы жадаем зрабіць на той самы package-lock.json. Калі нейкім чынам змяняецца склад кампанентаў, якія выкарыстоўваюцца для зборкі праекта - у нас збіраецца новы Docker-выява. У далейшым ён выкарыстоўваецца для разгортвання кантэйнера з сабраным дадаткам. Цяпер гэтага няма, але плануем перайсці на мікрасэрвісную архітэктуру ў Kubernetes, які актыўна развіваецца ў нашай кампаніі і даўно абслугоўвае прадакшн рашэнні.

Рэзюмэ

Заклікаю ўсіх выкінуць Windows, але гэта не таму, што я не ўмею яе гатаваць. Прычына ў тым, што большая частка Opensource-рашэнняў – гэта Linux-стэк. Вы добра зэканоміце на рэсурсах. На мой погляд, будучыня за рашэннямі Open Source на Linux з магутным кам'юніці.

Профіль спікера Аляксандра Сінчынава на GitHub.

DevOps Conf - Гэта канферэнцыя па інтэграцыі працэсаў распрацоўкі, тэсціравання і эксплуатацыі для прафесіяналаў ад прафесіяналаў. Менавіта таму праект, пра які расказваў Аляксандр? рэалізаваны і працуе, а ў дзень выступу праведзены два паспяховыя рэлізы. На DevOps Conf на РЫТ++ 27 і 28 траўня будзе яшчэ больш падобных кейсаў ад практыкаў. Яшчэ можна ўскочыць у апошні вагон і падаць даклад ці не спяшаючыся забраніраваць білет. Сустрэнемся ў Сколкава!

Крыніца: habr.com

Дадаць каментар