Мы развівалі DevOps як маглі. Нас было 8 чалавек, і Вася быў самым крутым па Windows. Раптам Вася сышоў, а ў мяне з'явілася задача вывесці новы праект, які пастаўляе Windows-распрацоўка. Калі я высыпаў на стол увесь стэк Windows-распрацоўкі, то зразумеў, што сітуацыя – боль…
Так пачынаецца гісторыя Аляксандра Сінчынава на DevOpsConf. Калі з кампаніі сышоў кіроўны адмысловец па Windows, Аляксандр задаўся пытаннем, што зараз рабіць. Пераходзіць на Linux, вядома ж! Аляксандр раскажа, як яму ўдалося стварыць прэцэдэнт і перавесці частку Windows распрацоўкі на Linux на прыкладзе рэалізаванага праекта на 100 000 канчатковых карыстальнікаў.
Як лёгка і нязмушана дастаўляць праект у RPM, выкарыстоўваючы TFS, Puppet, Linux. NET core? Як падтрымліваць версіяванне БД праекта, калі распрацоўка ўпершыню чуе словы Postgres і Flyway, а дэдлайн пазаўтра? Як інтэграваць з Docker? Як матываваць. NET-распрацоўнікаў адмовіцца ад Windows і смузи ў карысць Puppet і Linux? Як вырашаць ідэалагічныя канфлікты, калі абслугоўваць Windows у прадакшн няма ні сіл, ні жаданні, ні рэсурсаў? Аб гэтым, а таксама аб Web Deploy, тэставанні, CI, аб практыках выкарыстання TFS у існых праектах, і, вядома, аб зламаных мыліцах і працавальных рашэннях, у расшыфроўцы дакладу Аляксандра.
Такім чынам, Вася сышоў, задача на мне, дэвелаперы чакаюць з віламі з нецярпеннем. Калі я канчаткова ўсвядоміў, што Васю не вярнуць - прыступіў да справы. Для пачатку ацаніў працэнт Win VM у нашым парку. Рахунак быў не на карысць Windows.
Так як мы актыўна развіваем 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?
Цяпер я магу ўпэўнена сказаць, што IdentityServer4 - Гэта класная бясплатная альтэрнатыва ADFS з аналагічнымі магчымасцямі, ці што Ядро Entity Framework - рай для распрацоўніка, дзе можна не затлумляцца напісаннем SQL скрыптоў, а апісваць запыты ў БД у тэрмінах ААП. Але тады, на абмеркаванні плана дзеянняў, я глядзеў на гэты стэк як на шумерскі клінапіс пазнаючы толькі PostgreSQL і Git.
На той момант мы актыўна выкарыстоўвалі Лялечны як сістэму кіравання канфігурацыяй. У большасці нашых праектаў мы прымянялі GitLab CI, Эластычны, балансавалі высоканагружаныя сэрвісы з дапамогай HAProxy, сачылі за ўсім з дапамогай Zabbix, звязкі Графана и Праметэй, Егер, і ўсё гэта круцілася на жалязяках HP c ESXi на VMware. Усім знаёма - класіка жанру.
Паглядзім і паспрабуем зразумець, што ж адбывалася да таго, як мы задумалі ўсе гэтыя ўмяшанні.
Што было
TFS – гэта даволі магутная сістэма, якая не толькі дастаўляе код ад распрацоўніка да канчатковай прадакшн-машыны, але таксама мае набор для вельмі гнуткай інтэграцыі з рознымі сэрвісамі – для забеспячэння CI на кросплатформавым узроўні.
Раней гэта былі суцэльныя фортачкі. TFS выкарыстоўваў некалькі Build-агентаў, на якіх збіралася мноства праектаў. У кожным агенце па 3-4 worker-a, каб распаралеліць задачы і аптымізаваць працэс. Далей, паводле рэлізных праектаў, TFS дастаўляў новы Build на Windows-сервер прыкладанняў.
Да чаго мы хацелі прыйсці
Для дастаўкі і распрацоўкі выкарыстоўваны TFS, а запускаем дадатак на Linux Application server, і паміж імі нейкая магія. Гэты Чароўная скрынка і ёсць соль маючай адбыцца працы. Перад тым, як разабраць яго па частках, зраблю крок у бок і скажу два словы аб дадатку.
праект
Прыкладанне дае функцыянальнасць для аперыравання прадаплочанымі картамі.
Кліент
Існавала два тыпы карыстальнікаў. Першы атрымліваў доступ, аўтарызуючыся па сертыфікаце SSL SHA-2. У другога быў доступ па лагіне і паролю.
HAProxy
Далей кліенцкі запыт пападаў у HAProxy, які вырашаў наступныя задачы:
першасная аўтарызацыя;
тэрмінаванне SSL;
цюнінг HTTP запытаў;
трансляцыя запытаў.
Праверка сертыфіката кліента ішла па ланцужку. Мы - ўлада і можам сабе такое дазволіць, бо самі выдаём сертыфікаты кліентам сэрвісу.
Звярніце ўвагу на трэці пункт, крыху пазней вернемся да яго.
Backend
Бэкенд планавалі зрабіць на Linux. Бэкенд узаемадзейнічае з БД, падгружае неабходны спіс прывілеяў і потым, у залежнасці ад таго, якімі прывілеямі валодае які аўтарызаваўся карыстач, падае доступ для падпісання фінансавых дакументаў і адпраўкі іх на выкананне, або генерацыі нейкай справаздачы.
Эканомія c HAProxy
Апроч двух кантэкстаў, па якіх хадзіў кожны з кліентаў, існаваў яшчэ кантэкст identity. IdentityServer4 як раз дазваляе аўтарызавацца, гэта бясплатны і магутны аналаг для ADFS - Паслугі федэрацыі Active Directory.
Запыт у identity апрацоўваўся за некалькі крокаў. Першы крок - кліенттрапляў у бэкенд, Які абменьваўся дадзенымі з гэтым серверам і правяраў наяўнасць токена для кліента. Калі не знаходзіў - запыт вяртаўся назад на той кантэкст, з якога ён прыйшоў, але ўжо з рэдырэктам, і з рэдырэктам ішоў на identity.
Другі крок - запыт трапляў на старонку аўтарызацыі ў IdentityServer, дзе кліент рэгістраваўся, а ў базе дадзеных IdentityServer з'яўляўся той самы доўгачаканы токен.
Трэці крок кліент рэдырэктыў назад на кантэкст, з якога ён прыйшоў.
У IdentityServer4 ёсць асаблівасць: адказ на зваротны запыт ён вяртае па HTTP. Як ні біліся з наладай сервера, як ні адукоўваліся дакументацыяй, але мы кожны раз атрымлівалі першапачатковы запыт кліента з URL, які прыйшоў па HTTPS, а IdentityServer вяртаў той жа самы кантэкст, але з HTTP. Мы былі ў шоку! І перавялі ўсё гэта праз кантэкст identity на HAProxy, а ў хедэрах прыйшлося мадыфікаваць пратакол HTTP на HTTPS.
У чым жа паляпшэнне і дзе зэканомілі?
Мы зэканомілі грошы, выкарыстоўваючы бясплатнае рашэнне для аўтарызацыі групы карыстачоў, рэсурсы, бо не выносілі IdentityServer4 як асобную ноду ў асобны сегмент, а выкарыстоўвалі яго сумесна з бэкэндам на тым жа самым серверы, дзе круціцца бэкенд прыкладання.
Як павінна працаваць
Такім чынам, як я абяцаў - Magic Box. Мы ўжо разумеем, што гарантавана рухаемся ў бок Linux. Давайце сфармулюем канкрэтныя задачы, якія патрабавалі рашэнні.
Маніфесты 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.
Пройдземся па кампанентах.
Чароўная скрынка
Складаецца з чатырох частак.
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-сутнасць, гэта значыць гэта рэпазітар прыкладання, з якім працуе распрацоўнік.
Пасля чаго TFS бачыць, што прыляцеў новы коміт. Якое дадатак? У наладах TFS ёсць пазнака, якімі рэсурсамі валодае той ці іншы Build-агент. У дадзеным выпадку ён бачыць, што мы збіраем. NET Core праект і выбірае Linux Build-агент з пула.
Build-агент атрымлівае зыходнікі, выкачвае неабходныя залежнасці c рэпазітара .NET, npm і г.д. і пасля зборкі самога прыкладання і наступнага пакавання адпраўляе RPM-пакет у RPM-рэпазітар.
З іншага боку, адбываецца наступнае. Інжынер аддзела эксплуатацыі займаецца непасрэдна выкаткай праекта: мяняе версіі пакетаў у Hiera у рэпазітары, дзе захоўваецца рэцэптура прыкладання, пасля чаго Puppet трыгерыт Юм, забірае новы пакет з рэпазітара, і новая версія прыкладання гатова да выкарыстання.
На словах усё проста, але што адбываецца ўсярэдзіне на самім Build-агенце?
Упакоўка DLL RPM
Атрыманы зыходнікі праекту і задача на зборку ад TFS. Build-агент запускае зборку самога праекту з зыходнікаў. Сабраны праект даступны ў выглядзе мноства DLL файлаў, Якія спакаваны ў zip-архіў для зніжэння нагрузкі на файлавую сістэму.
ZIP-архіў выкідваецца у дырэкторыю зборкі пакета RPM. Далей Bash-скрыпт ініцыялізуе зменныя асяроддзі, знаходзіць версію Build, версію праекту, шлях да дырэкторыі зборкі, і запускае RPM-build. Па заканчэнні зборкі пакет публікуецца ў лакальны рэпазітар, які знаходзіцца на Build-агенце.
Далей, з Build-агента на сервер у RPM-рэпазітара адпраўляецца JSON-запыт з указаннем імя версіі і білда. Webhook, пра які я раней казаў, выпампоўвае гэты самы пакет з лакальнага рэпазітара на Build-агенце і робіць новую зборку даступнай для ўсталёўкі.
Чаму менавіта такая схема дастаўкі пакета ў рэпазітар RPM? Чаму нельга адразу адправіць сабраны пакет у рэпазітар? Справа ў тым, што гэта ўмова для забеспячэння бяспекі. Такі сцэнар абмяжоўвае магчымасць несанкцыянаванай загрузкі RPM-пакетаў староннімі людзьмі на сервер, які даступны ўсім Linux-машынам.
Версіянаванне БД
На кансіліуме з распрацоўкай высветлілася, што рабятам бліжэй MS SQL, але ў большасці non-Windows праектаў мы ўжо на ўсю моц выкарыстоўвалі PostgreSQL. Бо мы ўжо вырашылі адмовіцца ад усяго платнага, то сталі выкарыстоўваць PostgreSQL і тут.
У гэтай частцы хачу расказаць, як мы ажыццяўлялі версіяванне БД і як выбіралі паміж 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-агентах скануе зыходнікі. Другі - WindowsIndexer. Ён не быў адключаны, і на Build-агентах у рэальным часе індэксавалася ўсё падчас дэплояў.
Трэці - NPM install. Аказалася, што ў большасці Pipelines мы выкарыстоўвалі менавіта гэты сцэнар. Чым ён дрэнны? Працэдура Npm install запускаецца пры фармаванні дрэва залежнасцяў у package-lock.json, дзе фіксуюцца версіі пакетаў, якія будуць выкарыстоўвацца для зборкі праекту. Мінус у тым, што Npm install кожны раз падцягвае актуальныя версіі пакетаў з інтэрнэту, а гэта немалы час у выпадку вялікага праекту.
Распрацоўнікі часам эксперыментуюць на лакальнай машыне, каб праверыць працу асобнай часткі ці праекту цалкам. Часам атрымлівалася, што лакальна ўсё крута, але збіралі, выкочваліся - нічога не працавала. Пачынаем разбірацца, у чым праблема - ага, розныя версіі пакетаў з залежнасцямі.
рашэнне
Зыходнікі ў выключэнні AV.
Адключэнне індэксацыі.
Пераход на npm ci.
Плюсы npm ci, у тым, што мы збіраем дрэва залежнасцяў аднойчы, і атрымліваем магчымасць падаць распрацоўніку актуальны спіс пакетаў, з якім ён можа колькі заўгодна эксперыментаваць лакальна. Гэта эканоміць час распрацоўшчыкаў, якія пішуць код.
Канфігурацыя
Цяпер крыху аб канфігурацыі рэпазітара. Гістарычна мы выкарыстоўваем Сувязь для кіравання рэпазітарамі, у тым ліку Internal REPO. У гэты ўнутраны рэпазітар пастаўляюцца ўсе кампаненты, якія мы выкарыстоўваем для ўнутраных мэт, напрыклад, самапісныя маніторынгі.
Мы таксама выкарыстоўваем NuGet, так як ён лепш кэшуецца ў параўнанні з іншымі пакетнымі мэнэджэрамі.
Вынік
Пасля таго, як мы аптымізавалі Build-агентаў, сярэдні час зборкі скарацілася з 12 хвілін да 7.
Калі палічыць усе машыны, якія мы маглі б выкарыстоўваць для Windows, але перавялі на Linux у гэтым праекце, мы зэканомілі парадку $10 000. І гэта толькі на ліцэнзіях, а калі ўлічваць змест - больш.
Планы
На наступны квартал заклалі ў план працу над аптымізацыяй дастаўкі кода.
Пераход на прэбілд Docker-выявы. TFS - класная штука са мноствам плагінаў, якія дазваляюць інтэграваць у Pipeline, у тым ліку, і зборку па трыгеру, дапусцім, Docker-выявы. Гэты трыгер мы жадаем зрабіць на той самы package-lock.json. Калі нейкім чынам змяняецца склад кампанентаў, якія выкарыстоўваюцца для зборкі праекта - у нас збіраецца новы Docker-выява. У далейшым ён выкарыстоўваецца для разгортвання кантэйнера з сабраным дадаткам. Цяпер гэтага няма, але плануем перайсці на мікрасэрвісную архітэктуру ў Kubernetes, які актыўна развіваецца ў нашай кампаніі і даўно абслугоўвае прадакшн рашэнні.
Рэзюмэ
Заклікаю ўсіх выкінуць Windows, але гэта не таму, што я не ўмею яе гатаваць. Прычына ў тым, што большая частка Opensource-рашэнняў – гэта Linux-стэк. Вы добра зэканоміце на рэсурсах. На мой погляд, будучыня за рашэннямі Open Source на Linux з магутным кам'юніці.
DevOps Conf - Гэта канферэнцыя па інтэграцыі працэсаў распрацоўкі, тэсціравання і эксплуатацыі для прафесіяналаў ад прафесіяналаў. Менавіта таму праект, пра які расказваў Аляксандр? рэалізаваны і працуе, а ў дзень выступу праведзены два паспяховыя рэлізы. На DevOps Conf на РЫТ++ 27 і 28 траўня будзе яшчэ больш падобных кейсаў ад практыкаў. Яшчэ можна ўскочыць у апошні вагон і падаць даклад ці не спяшаючыся забраніраваць білет. Сустрэнемся ў Сколкава!