Щоденні релізи: досвід продуктових ІТ-компаній
Редакція DOU звернулася до українських продуктових ІТ-компаній, щоб з'єднання з'ясувати, як успішно релізити на продакшен по кілька разів на день та уникнути факапів. Як зорганізувати процес? Які проблеми виникають і як з ними впоратися?
Дмитро Волошин , CTO і co-founder в Preply
Ми в Preply пройшли довгий шлях від тижневих деплоїв, виконаних кваліфікованими інженерами, до щогодинних деплоїв, зреалізованих усією командою. Про історію еволюції наших процесів я розповідав на Highload FW days .
Тижневі релізи зумовлювало те, що в нас був громіздкий процес ручного тестування. Коли ж ми змогли його частково завтоматизувати, почали релізитися щоденно. Альо ця функція належала реліз-інженерам і була дуже монотонною. Щоб якось її гейміфікувати, ми ввели в штатний розпис свиню (на фото).
Реліз-інженер, який був відповідальний за релізи цього дня, брав її собі на стіл, і всі знали, до кого звертатися, якщо щось не працює або не релізиться. Згодом свиню десь загубили, і ми вирішили: це знак, що потрібно завтоматизувати процес. Основна мотивація полягала у тому, що наші інженери пишуть код постійно, і немає сенсу чекати наступного дня, щоб зарелізити код, якщо він потрібен користувачам вже сьогодні. Тобто ми розуміли, що нам треба зоптимізовувати метрику time to market.
Основні речі, які ми зімплементували, і які вможливили релізитися по десять або більше разів на день (enablers):
- Стабільний Continuous Integration-/Continuous Deployment-процес, з Дженкінсом і тестами. Бажано також, щоб end-2-end-тести відбувалися в середовищі, якнайбільше наближеному до продакшену. У нашій ситуації завдяки Kubernetes кожен інженер може розвернути тестовий стенд зі своєї гілки кодом.
- Trunk-Based Development — процес розробки, коли є якнайменші feature branches, які вливаються безпосередньо у master без проміжних гілок.
- Feature flags — це був еволюційний процес, але загалом ми змогли прийти до того, щоб майже кожну нову фічу можна було вимкнути за допомогою feature flag. Цьому також сприяла сильна культура A/B-тестування.
- Access democratization — кожен має можливість вливатися в майстер (після quality gates) і релізитися на продакшен. Відповідальність за свій код з часу написання до моменту доставки його кінцевому користувачу сприяє якості й швидкості.
- Service ownership — попри те, що у нас монорепозиторій, ми намагаємося поділяти наш монолітний продукт на сервіси зі слабшою зв'язку язністю. Це дає змогу мати набагато менш зв'язку язний продукт, коли кожна його частина має власника, якого навіть формалізовано через Codeowners-файл. Оскільки сервіси більш-менш незалежні, їх також можна релізити незалежно.
Основним побоюванням було те, що фічі різних команд конфліктуватимуть після вливання в майстер. Тобто через те, що команди не знають, хто що релізить, виникатимуть ситуації, коли команди ламають фічі інших команд. Це побоювання не справдилося: основні помилки визначаємо на етапі unit/integration/e2e-тестування. Якщо щось падає після деплоя, завдяки feature flags можна миттю виправити це для кінцевого користувача або відкотити зміни. Зазвичай баги виявляємо на етапі тестування розробником (мі нещодавно відмовилися від функції manual QA), інколи баги повідомляють кінцеві користувачі відділу служби підтримки користувачів. У середньому пропускаємо 2-3 середніх баги на продакшен на тиждень. Ми вважаємо, що отримати продукт узагалі без багів неможливо, але набагато важливіше, як ми на них реагуємо і як можемо оперативно їх виправити. Критичних проблем, коли «усе лежить», не так багато: це трапляється приблизно раз на 1000 релізів. Раз на 20-40 релізів ми за метриками або зверненнями користувачів помічаємо проблему й відкочуємо зміни. Щоразу відповідальний інженер готує post-mortem і розповідає про конкретний випадок на найближчому dev-мітингу. Приклад одного з останніх невдалих релізів і відповідного постмортему:
Вищеописане було б неможливе, якби не сильна DevOps-команда, яка в нас сформувалася, адже будь-яку автоматизацію все одно виконують люди. Бажання DevOps-команди даті цінність кінцевим користувачам продукту було основним драйвером поліпшень, що відбулися.
Володимир Ніконов , керівник департаменту розробки платформи в Terrasoft
Організацію процесу частих поставок на production в наших командах ми проходили не один раз і в складі багатьох команд. Протягом усіх змін ключовим моментом в даному питанні стоять не технології, не формат і розмір продукту, і навіть не технологічний рівень команд. На мій погляд, ключовим фактором є культура, яка панує в команді.
Починаючи змінювати свій підхід до постачання, ви повинні бути готові до помилок, причому іноді досить болючим. У нашій практиці на початку цього шляху було все: від простої недоступність сервісу до тимчасової втрати даних, які довелося відновлювати в ручному режимі. Озираючись на всі ці події, можна поставити питання: навіщо ж тоді йти на такі ризики, змінюючи звичні і налагоджені процеси?
Я можу з упевненістю сказати, що культура частих поставок функціоналу:
- докорінно змінює ставлення команди до розроблюваним функціоналу;
- змінює сприйняття пріоритетів завдань;
- дозволяє команді відчути продукт з користувацької боку і народжує потребу в технічних інновацій, які роблять ваш продукт/сервіс/код на порядок краще.
Всі наші команди, які працюють в такому режимі, знають актуальні потреби клієнтів і генерують набір поліпшень роботи користувачів, намагаючись включити в чергову поставку невелику порцію поліпшень.
Для організації такого механізму ми зробили кілька речей:
- Надали командам більшу свободу дій при прийнятті рішень (якщо цього не зробити, ви зіткнетеся з проблемою погоджень, яка буде затягувати поставки).
- Надали командам необхідні права та інструменти для швидкого вирішення інцидентів на production (з одного боку, це підвищення операційних ризиків, з іншого — ми отримали скорочення часу вирішення критичних інцидентів).
- Навчили команди розробки в галузях, де їх компетенції були недостатні, але необхідні для обслуговування своїх сервісів.
Крім навчань, ми еволюційно дійшли до автоматизації всіх можливих процесів постачання та операцій на production-середовищі (установка оновлень, перемикання трафіку і бекапирование і відновлення даних). Людський фактор — головна причина збоїв, і ми мінімізуємо його при будь-якій можливості. Саме тому нам довелося серйозно попрацювати в області автоматизації тестування і отримання можливості витрачати мінімум ручних зусиль при визнанні змін готовими до релізу на production.
Враховуючи наявність великої кількості поставок, ми постійно працюємо над їх швидкістю, зменшуючи простої сервісу або моменти перехідних періодів. Технічно підросли не тільки команди, які освоїли основні принципи, які треба враховувати при розробці і проектуванні функціоналу для високодоступних систем, ні і сам продукт придбав нові можливості, що дозволяють проводити канарково тестування і включати або відключати частину функціоналу.
Окремі операції, що вимагають раніше рівень сервісу, тепер працюють на «гарячу». З'явилися можливості інтеграції систем автоматизації та моніторинг бізнес-функцій для превентивної реакції на збої без очікування фідбек від користувачів.
На поточний момент у нас вісім команд, які самостійно працюють в режимі частих поставок. У підсумку, крім зростання рівня команд і можливості реалізовувати складні фічі в продукті, ми отримали ще і збільшення швидкості розвитку самого продукту, тому що тепер маємо менше накладних витрат на внесення змін в код і його постачання клієнту. Далі плануємо продовжувати впроваджувати цей підхід в інших напрямках.
Микита Артемчук , керівник департаменту розробки в Prom.ua
У співавторстві з Віталієм Харитонским , СТО Prom.ua
Частота релізів на продакшен залежить від інфраструктури. Так, Prom.ua — найбільший маркетплейс країни. На його платформі створили інтернет-магазини більше 236 тис. підприємців, які продають 111 млн товарів. Проекту 11 років, і в ньому паралельно існують монолітна і микросервисная інфраструктури.
У монолітній всі елементи пов'язані між собою. Щоб оновити окрему частину, потрібно оновлювати весь величезний Prom. Тому великі зміни виходять два рази на тиждень, а невеликі можуть частіше. В цілому, 1-3 рази в тиждень.
Щоб бути більш гнучкими, ми поступово переходимо до микросервисной інфраструктурі. Вона складається з автономних елементів, оновлювати які можна окремо і хоч кожну годину. Це знижує час виправлення помилки за рахунок того, що не потрібно оновлювати всю структуру.
Налагоджуючи цей досить складний процес, ми намагаємося знайти баланс між безпекою проекту і гнучкістю розробки. Як правило, викатка відбувається в кілька етапів:
- Оскільки багато розробників (над Prom.ua працює 107 розробників і ще 500+ ІТ-фахівців), то їх зміни можуть суперечити один одному. За допомогою спеціального ПО ми їх перевіряємо і шукаємо невідповідності між новими змінами з боку розробника і вже існуючої логікою проекту.
- Потім передаємо код в тестову середу. У нас таких кілька. Це різні копії Prom, які доступні тільки нам. У цих тестових середовищах код перевіряють інші розробники і тестувальники, а потім його проганяють через автоматичні тести.
- У момент першого польоту на Prom ми ще раз проганяємо нову версію проекту через автотесты.
Також ми намагаємося не виливати великі зміни відразу на всіх користувачів. Тому зі старту функціонал доступний невеликій групі клієнтів, але поступово розширюємо зміни на всіх.
Говорячи про проблеми, часто складно передбачити, що твоє поточне зміна може зламати в іншому шматку продукту. Адже Prom — великий і дорослий проект. Його елементи дуже сильно залежать один від одного за монолітною інфраструктури.
Тому важливо на людському рівні синхрониться один з одним, щоб не порушити або технічну цілісність продукту, або бізнес-логіку в пов'язаних між собою частинах функціоналу.
Для цього на технічному рівні у нас є культура взаємного ревю. Перевіряти можуть як програмісти з однієї команди, так і розробники з суміжних. Особливо це важливо, коли зміни торкаються частини функціоналу, які належать до окремих шматках продукту.
Швидко відловлювати проблеми допомагають автотесты автоматична перевірка доступності ключових шматків функціоналу продукту. Також ми практикуємо регулярні зустрічі product-менеджерів і тех. лідов, де ділимося планами розробки на найближчий час. Нарешті, є демовстречи, на яких команди показують всім — супорта, продажу, маркетингу — майбутні зміни.
Весь процес максимально автоматизований: досить натиснути одну кнопку в нашому CI/CD-інтерфейсі, і все відбудеться само собою. Реліз-команда і розробники користуються цим, щоб релізувати з телефону, по дорозі додому, вночі, в поході і в інших нестандартних ситуаціях. Тут потрібно розуміти, що тільки мажорний реліз відбувається в робочий час, коли всі на місцях. Мінорні релізи проходять часто непомітно для оточуючих, в будь-який час доби.
Для того щоб контролювати реліз постфактум, усі додаток і пов'язана інфраструктура покриті метриками та алертами. Якщо щось не працює, то з імовірністю 95% ми знаємо про це і працюємо, щоб усунути причини.
Багато складнощів відбувається на стику проекту і його зовнішніх залежностей: бази даних, пошуковий движок і конфігурація мережевих компонентів. Такі речі досить складно і ризиковано автоматизувати, тому що доводиться робити вручну. На щастя досить рідко.
Для того щоб автоматизувати процес деплоя, ми впровадили GitLab CI/CD, Docker і Kubernetes. Це значно спростило життя відділу інфраструктури, а також дозволило різним командам швидше запускати свої микросервисы і автономно використовувати залізо на продакшені.
Леонід Литвиненко , СТО в YouScan
Почнімо з того, що я трохи розповім про структуру команди розробки. Увесь колектив, майже 20 людей, поділили на чотири сквади — мінікоманди, що відповідають за різні напрями розвитку.
Команда, що відповідає за збір даних — Data Squad; команда, що відповідає за смарт-фічі, як-від аналіз зображень чи визначення трендів, — Data Science Squad; Platform Squad відповідає за автоматизацію нашої платформи й виробляє найкращі практики, які потім приймають інші команди; і Product Squad — команда, що безпосередньо розробляє основний продукт.
Нам подобається, що ми досягаємо одночасного руху в чотирьох напрямах з порівняно невеликою кількістю людей. Проте, щоб цього досягти, потрібно завтоматизовувати якомога більше промов на своєму шляху: CI/CD, prod-like staging environments, safe rollback, автоскейлінг, дашборди, сповіщення, реакцію на інциденти, run books і post-mortems.
Частий деплоймент — це, з одного боку, теж спосіб безпечної розробки невеликими командами, а з іншого боку, часті деплойменти не вийде робити без тотальної автоматизації.
За ці пів року ми вже нікого понад 2500 деплойментів у продакшн, але в нас майже сотня сервісів на більш як двох сотень віртуальних машин.
Іноді ми жартуємо, що у нас log driven development, тому що частину релізів можна реально перевірити лише на повному навантаженні. Для цього активно використовуємо в нашому продукті feature toggles. Та й узагалі, ми любимо feature toggles: якщо можна щось не цілком завершене задеплоїти, заховавши за feature toggle, — виберемо цей варіант.
Крім інструментів, потрібна ще й певна культура для того, щоб деплоїти часто. «You built it — you run it» — це про нас: розробник і деплоїть, і тестує, і стежить за роботою у production. Розробник уміє робити roll back або roll forward (коли замість деплою попередньої версії роблять виправлення й ще один новий деплой).
Ми практично завжди працюємо в master-гілці, гілки створюємо лише для великих завдань або принципових архітектурних змін.
Трошки про міграцію даних: у нас трапляються періоди, коли ми змінюємо місце й формат для величезної кількости даних, а також міграції, що тривають тижнями. У цей час ми підтримуємо код, який уміє працювати з двома версіями даних. На цю тему ми робили хорошу доповідь .
Дам ще кілька цікавих посилань на цю тему: Friday deploy freezes are exactly like murdering puppies і
Stack Overflow: How We Do Deployment — 2016 Edition .
Віктор Прокопенко, керівник функціонального розвитку в IT-Enterprise
Не буває релізів «часто» — є «навіщо» і «коли» потрібен реліз. На практиці — це майже завжди відомо. Для виходу нового функціоналу є терміни, вони, як правило, узгоджені, озвучені, часто опубліковані. Тут немає інших варіантів, окрім як встигнути у рядків і видати реліз не «часто», а «вчасно».
Важливо також, навіщо виходить реліз: нова функціональність чи усунення багів? Адже, якщо функціонал новий, то можливі баги. Частіше «постановочного» характером, ніж технічного. Для технічних — існують технічні засоби виявлення. Але трапляється, що якась функціональність не розглядалась, а сьогодні вже потрібна. Вона не документована, але, з точки зору користувача, її відсутність або реалізація не так, як очікував користувач, — це вже «бага».
Отже, потрібно вміти їх швидко виявляти і швидко виправляти. Тому неважливо — часто чи не часто виходить реліз — важливо, щоб своєчасно і без багів, навіть імовірних. Можна, звичайно, довше тестувати, але ринок втомиться чекати і почне користуватися чимось іншим. Зрештою, функціонал буде без багів, але не затребуваний. Щоб все передбачити, потрібен весь арсенал знань, засобів розробки і тестування, організації, обчислювальних потужностей і ще багато чого.
Абстрагуємося від багів. Розглянємо приклад нової функціональності. Вона буває двох типів — індивідуальна (замовна) і для масового ринку.
Індивідуальна (замовна) передбачає тісну роботу з клієнтом. Необхідно зрозуміти, що йому потрібно і у відведені терміни вкластись із реалізацією. Часто ці терміни знаходяться усередині інших проектних термінів, тобто дуже стислі. Аналітична робота обов'язково проводитися, але клієнт вимагає термінів реалізації більш коротких, ніж потрібно для глибокої аналітики. Буває також, що за аналітичну роботу клієнт не готовий платити. У цьому випадку необхідна тісна співпраця із зацікавленими людьми від клієнта. Розробка, демонстрація прототипів, зміна вимог виконуються паралельно. Як правило, такі процеси не надто чутливі до багів на етапі розробки і дослідної експлуатації, тому що клієнт з розробником «пливуть в одному човні». Альо баги все одно потрібно «лагодити» швидко. Ця технологія застосовувалася нами дуже часто на початку 2000-х років і працює досі у великих проектах.
Для масового ринку — ситуація інша. Баги в цьому софті не можна допускати, тому що це може призвести до втрати функціональності на деякий час і зупинці якихось процесів у значної кількості клієнтів. Це завжди загрожує репутаційними втратами (як мінімум). А якщо клієнт може скористатись у «проблемний» годину іншим софтом іншого виробника, то це може призвести до втрати клієнта.
Такий софт на момент внесення змін, як правило, непогано накритий функціональними тестами-сценаріями. Якщо йде розробка нового сценарію, то потрібно розробити нову порцію тестів. У разі необхідності — в старі варто внести зміни ще до розробки, або в процесі. Такий софт обов'язково повинен бути покрить тестами, тому що ефективність автоматизованого тестування трохи вище мануального. Альо без мануального теж не обійтися. І бажано, щоб після мануального тестування у базі даних залишався тест. Тому, на мій погляд, до таких змін необхідно підходити дуже зважено. Іноді можна затягнути часом не тестування і це виправдовується. Альо якщо з годиною тягнути не можна — наприклад, законодавчі зміни — то потрібно розподілити час так, щоб до кінця завжди залишався запас. Це завдання менеджера. Не обов'язково про це «говорити вголос» усій команді, але ризики потрібно мінімізувати.
Якщо одночасно проявився баг і з'єднання явилася фіча — чи варто випускати два релізи? Якщо бага проявилася — потрібно швидко її полагодити. Усі тести займають годину — а його немає. Тут на допомогу приходити логіка, формалізація, здоровий глузд, знання системи і т. д. Не варто шкодувати часу фахівців високої кваліфікації.
Завдання цього етапу — за найкоротші терміни прийняти рішення, внести зміни в софт, звузити область тестування до мінімуму, але при цьому необхідно бути впевненим, що помилку виправлено. Після усунення проблеми в продуктиві можна приступати до «розбору польотів», але не раніше. Спочатку потрібно ліквідувати проблему.
При виконанні такого роду завдань треба бути принциповим у частині складання релізу. Не треба змішувати «мух з котлетами»: якщо ми швидко лагодимо багу, то нові фічі, які хотілося б також включити разом у це оновлення, сюди допускати не можна. Для фічей необхідна своя процедура тестування та верифікації. Вона займає годину і розтягує тривалість некоректної роботи функціоналу загалом. Найгірше, що при змішуванні усунення баги з новим функціоналом — бага більш тривалий час знаходиться в продуктиві.
Існує організаційно-технічна процедура підготовки релізу. Процедура підготовки релізу програмістами автоматизована. За рахунок цього мінімізуються кваліфікаційні відмінності розробників і людський фактор «забув», «пропустивши», «це не потрібно, не впливає», і т. д. Реліз неможливо закрити технічно, не кажучи про публікації, якщо він не пройшов повну покрокову процедуру підготовки.
У нас є відділ якості та свої тестувальники. Процес тестування релізу теж автоматизований. Застосовуються як стандартні технології — Unit testing, Integration testing, UI, testing Service, так і власна система функціонального тестування, що має ряд переваг для завдань ERP-системи, зокрема — для багатьох паралельних сценаріїв, продуктивності, працездатності служб.
На допомогу розробникам так само надходять результати щоденних нічних прогонів тестів. Є спеціальні люди і процедури, які забезпечують виконання завдань «полагодити тест» у найкоротший термін, особливо, коли випускається реліз.
Ми випускаємо релізи щомісяця. Система тиражна. Постійно виконується багато проектів і необхідний новий функціонал. Нам потрібно встигати в проектні терміни. Згодом співробітники звикають до щомісячного релізу і це входити в культуру. Процеси розробки самі підлаштовуються під ці тимчасові рамки знизу. Якщо щось не встигають, то або прикладають більше зусиль, або домовляються про зміщення термінів. Кожен з підходів застосуємо, альо залежить від ситуації. Єдиної таблетки немає. Потрібно думати і домовлятися.
Унікальність, перш за все, диктує наш основний продукт — ERP-система. Особливістю ERP-систем є велика кількість функцій, модулів і підсистем. Для мінімізації ризиків у цій частині у нас розділені технологічно клієнтські «відтворення» і «серверні обчислення». Це, в свою чергу, вимагає підтримки власного інструментарію високорівневої розробки. Цей підхід непогано себе зарекомендував практично, тому що суттєво мінімізує як кількість багів, так і швидкість розробки. Розробникам не потрібно займатися написанням коду типу «відпрацювання кнопки Esc». Він за замовчуванням працює правильно. Якщо, раптом, необхідно внести зміни у стандартну поведінку, то вони вносяться, але вкрай рідко. Крім цього, єдиний підхід до роботи в інтерфейсах для користувачів мінімізує тимчасовий поріг для входу, тому що все схоже.
Крім цього, клієнтську і серверну логіку пишуть різні команди, що сприяє спеціалізації кваліфікацій і кращій якості.
Для нас як продуктової компанії, знання продукту, потреб своїх клієнтів та їх очікувань дуже важливе. І наявність цих знань у розробників лише сприяє створенню якісного продукту. Тому ми періодично підвищуємо прикладні знання розробників, ставимо в плани розвитку отримання нових скілів, знань і компетенцій, відвідування семінарів, запрошення тренерів, участь у івентах та інше.
Наступний момент — робота на випередження. Якщо клієнт пише — значить йому вже «набридло терпіти». Ми попереджаємо такі ситуації: для цього з низки проектів отримуємо щоденні зведення «здоров'я», міряємо і контролюємо «здоров'я системи». У зведеннях здоров'я ми спостерігаємо щоденну динаміку роботи в розрізі різних показників і маємо інтегральний показник «здоров'я», який контролюється особливо ретельно.
Сьогодні значної популяності набули месенджери. Ми застосовуємо їх для сигналізування у режимі on-line ситуацій виходу за встановлені межі якихось лічильників. Наприклад, стрибок завантаження процесора або пам'яті. Якщо він настав, то, не чекаючи щоденного звіту, відповідальні за напрямок отримують повідомлення і приступають до роботи негайно. Це стосується як лічильників на продуктиві, так і на робочих потужностях в офісі.
Крім цього, миттєва реакція дозволяє швидше розслідувати інцидент за гарячими слідами та ідентифікувати причину проблеми. Якщо причина відома — це вже пів-справи.
У разі, коли клієнт «закритий» від зовнішнього світу з різних причин (такі є), ми поставляємо свою систему контролю і накопичення статистики. Як правило, це великий бізнес зі своїм IT-відділом, де є відповідальні за такий напрямок люди.
Чи потрібно «дублювання функціональності»? Питання філософське, вимагає додаткових витрат і суперечить твердженням у колах розробників, що «дві програми, які реалізують один алгоритм, на одних і тих же даних дають різні результати».
Альо, тім не менш, у деяких рідкісних випадках — особливо, коли виконується перехід на новий функціонал і є непевність, а надійність дуже важлива — ми змушені це застосовувати.
При такому підході необхідно пам " ятати, що це тимчасове рішення. Тому в програмному коді обов'язково повинна бути закладена система збору статистики і обов'язкова періодична процедура обробки цієї статистики.
Дуже короткі висновки:
- Релізи потрібно робити.
- Релізи потрібно робити, коли вони потрібні.
- Релізи потрібно впроваджувати в культуру всього процесу розробки та експлуатації.
- Треба застосовувати автоматизацію для контролю якості — тоді ніхто нічого не забуває.
- Контроль якості має бути на всіх етапах: від постановки — до кінця життєвого циклу продукту.
- Процеси якості треба контролювати: потрібно міряти показники і утримувати їх в установлених межах.
- Баги бувають. Не помиляється той, хто нічого не робить. Потрібно вчитись усувати їх максимально швидко, але — що ще важливіше — необхідні процеси, які не допускають появу цих багів.
- Потрібно постійно моніторити систему. Помилки треба виправляти до того, як клієнт про це скаже чи помітить.
Опубліковано: 31/07/19 @ 10:00
Розділ Різне
Рекомендуємо:
Люди, алгоритми, ефективність та інша збірна солянка
ІТшники-волонтери: як харків'янка привернула увагу до «Розстріляного відродження»
DevOps дайджест #25: як деплоить за 50ms і не прокидатися о 4 ранку від алертів
Kanban як основа для виробництва software
Як направити трафік з instagram на сайт