Історія викочування, яка торкалася все

Історія викочування, яка торкалася все
Enemies of Reality by 12f-2

Наприкінці квітня, поки білі ходоки брали в облогу Вінтерфелл, у нас сталося щось цікавіше, ми зробили не зовсім звичайну викочування. У принципі ми постійно котимо нові фічі в прод (як і всі). Але ця була не така, як усі. Масштаб її був такий, що будь-які потенційні помилки, яких ми могли припуститися, поафектили б усі наші сервіси та користувачів. У результаті ми все викотили за планом, у запланований та анонсований термін даунтайму, без наслідків для продажу. Стаття про те, як ми цього досягли і як охочі можуть це повторити в домашніх умовах.

Я не описуватиму зараз прийняті нами архітектурні та технічні рішення, розповідати, як воно все працює. Це швидше замітки на полях про те, як проходила одна з найскладніших викочування, яку я спостерігав і в якій брав безпосередню участь. Не претендую на повноту чи технічні деталі, можливо вони з'являться в іншій статті.

Передісторія + що це за така функціональність

Ми будуємо хмарну платформу Mail.ru Cloud Solutions (MCS), де працюю технічним директором. І ось - настав час приробити до нашої платформи IAM (Identity and Access Management), який забезпечує єдине управління всіма обліковими користувачами, користувачами, паролями, ролями, сервісами та іншим. Навіщо він потрібен у хмарі — питання очевидне: у ньому зберігається вся інформація користувача.

Зазвичай такі речі починають будувати на етапі стартів будь-яких проектів. Але в MCS історично склалося трохи інакше. MCS будувався двома частинами:

  • Openstack із власним модулем авторизації Keystone,
  • Hotbox (S3-сховище) на базі проекту Хмара Mail.ru,

навколо яких потім з'явилися нові послуги.

По суті, це було два різні типи авторизації. Плюс ми використовували деякі окремі розробки Mail.ru, наприклад, загальне сховище паролів Mail.ru, а також самописний openid-конектор, завдяки якому забезпечувалася SSO (наскрізна авторизація) в панелі Horizon віртуальних машин (нативний UI OpenStack).

Зробити IAM нам означало поєднати це все у єдину систему, повністю свою. При цьому не втратити жодного функціоналу по дорозі, створити доробок на майбутнє, який дозволить нам прозоро його доопрацьовувати без рефакторингу, масштабувати за функціональністю. Також на старті у користувачів з'явилася рольова модель доступу до сервісів (центральний RBAC, role-based access control) та деякі інші дрібниці.

Завдання виявилося нетривіальним: python і perl, кілька бекендів, незалежно написані сервіси, кілька команд розробки та адмінів. І головне – тисячі живих користувачів на бойовій продакшен-системі. Все це треба було написати і, головне, викотити без жертв.

Що ми зібралися викотити

Якщо дуже грубо, десь за 4 місяці ми підготували таке:

  • Зробили кілька нових демонів, які агрегували функції, які раніше працювали в різних куточках інфраструктури. Решті сервісів прописали новий бекенд у вигляді цих демонів.
  • Написали своє центральне сховище паролів і ключів, доступне всім наших сервісів, яке можна вільно модифікувати, як нам потрібно.
  • Написали з нуля 4 нові бекенди для Keystone (користувачі, проекти, ролі, role assignments), які, по суті, замінили його базу, і тепер виступає єдиним сховищем наших паролів користувача.
  • Навчили всі наші сервіси Openstack ходити за своїми політиками до стороннього сервісу політик замість того, щоб читати ці політики локально з кожного сервера (так-так, за умовчанням Openstack так і працює!)

Така велика переробка потребує великих, складних і, головне, синхронних змін у кількох системах, написаних різними командами розробки. Після складання вся система має працювати.

Як викочувати такі зміни та не облажатися? Спочатку ми вирішили трохи зазирнути в майбутнє.

Стратегія викочування

  • Можна було б зробити викочування в кілька етапів, але це збільшило б термін розробки втричі. Крім того, на якийсь час ми мали б повну розсинхронізацію даних у базах. Довелося б писати свої інструменти синхронізації та довго жити з кількома сховищами даних. А це створює найрізноманітніші ризики.
  • Все, що могли підготувати для користувача прозоро, зробили заздалегідь. На це пішло 2 місяці.
  • Ми дозволили собі даунтайм протягом кількох годин – лише на операції користувачів зі створення та зміни ресурсів.
  • До роботи всіх вже створених ресурсів даунтайм був неприпустимий. Ми запланували, що при викочуванні ресурси повинні працювати без даунтайму та афекту для клієнтів.
  • Щоб зменшити вплив на наших замовників, якщо щось піде не так, ми вирішили викочуватися ввечері в неділю. Вночі менше замовників займається керуванням віртуальними машинами.
  • Усіх наших клієнтів ми попередили про те, що у вибраний для викочування період управління сервісами буде недоступним.

Відступ: що є викочування?

<обережно, філософія>

Кожен айтішник легко відповість, що таке викочування. Ставиш CI/CD, і автоматично все доставляється на прод. 🙂

Звичайно, це правильно. Але складність у тому, що при сучасних інструментах автоматизації доставки коду втрачається розуміння самої викочування. Як забуваєш про епічність винаходу колеса, дивлячись на сучасний транспорт. Все так заавтоматизовано, що викочування часто проводять без усвідомлення всієї картини.

А вся картинка така. Викочування складається з чотирьох великих аспектів:

  1. Доставка коду, включаючи зміну даних. Наприклад, їхня міграція.
  2. Відкат коду – можливість повернутися, якщо щось піде не так. Наприклад, через створення бекапів.
  3. Час кожної операції викочування/відкату. Потрібно розуміти таймінг будь-якої операції перших двох пунктів.
  4. Торкнувся функціонал. Потрібно обов'язково оцінити як очікуваний позитивний, і можливий негативний ефект.

Всі ці аспекти необхідно врахувати для успішного викочування. Зазвичай оцінюють лише перший, у кращому разі другий пункт, і тоді викочування вважається успішним. Але третій та четвертий навіть важливіші. Якому користувачеві сподобається, якщо викочування займе 3 години замість хвилини? Або якщо на викочуванні зафіксується щось зайве? Чи даунтайм одного сервісу призведе до непередбачуваних наслідків?

Акт 1..n, підготовка до релізу

Спочатку я думав коротко описати наші зустрічі: всією командою, її частинами, купи обговорень у каві поінтах, суперечок, тестів, брейнштормів. Потім подумав, що це зайве. Чотири місяці розробки завжди складаються з такого, особливо коли пишеш не те, що можна доставляти постійно, а велику одну фічу на живу систему. Яка стосується всіх послуг, але у користувачів нічого не повинно змінитися, крім «однієї кнопки в веб-інтерфейсі».

Наше розуміння того, як викочувати, змінювалося від кожної нової зустрічі, причому дуже суттєво. Наприклад, ми збиралися провести апдейт усієї нашої бази білінгу. Але порахували час і зрозуміли, що зробити це за розумний час викочування неможливо. Взяли майже тиждень додатково, щоб відшардувати та архівувати базу білінгу. А коли очікувана швидкість викочування і після цього не влаштувала, замовили додаткове, потужніше залізо, куди всю базу перетягнули. Не те щоб ми не хотіли зробити цього раніше, але поточна необхідність викочування не залишила нам варіантів.

Коли в одного з нас з'явилися сумніви, що викочування може торкнутися доступності наших віртуальних машин, ми витратили тиждень для проведення тестів, експериментів, розбору коду і отримали чітке розуміння, що такого не буде на нашому продакшені, і навіть люди, які сумніваються, з цим погодилися.

Тим часом хлопці з техсаппорту провели свої незалежні експерименти, щоб написати клієнтам інструкцію щодо способів підключення, які мали помінятися після викочування. Вони пропрацювали користувальницький UX, підготували інструкції та надавали особисті консультації.

Ми автоматизували всі операції з викочування, які тільки можна було. Будь-яку операцію скриптували, навіть найпростішу, постійно ганяли тести. Сперечалися, як краще вимикати сервіс – опускати демон або закривати доступ до сервісу фаєрволом. Створили чекліст команд на кожен етап викочування, постійно його актуалізували. Намалювали та постійно актуалізували діаграму Ганта з усіх робіт з викочування, з таймінгами.

І ось…

Акт фінальний перед викочуванням

… настав час викочуватися.

Як кажуть, витвір мистецтва неможливо завершити, тільки закінчити над ним працювати. Потрібно зробити вольове зусилля, розуміючи, що всього не знайдеш, але вірячи, що зробив усі розумні припущення, передбачив усі можливі випадки, закрив усі критичні баги і всі учасники зробили все, що могли. Чим більше коду викочуєш, тим складніше переконати себе в цьому (до того ж будь-хто розуміє, що передбачити все неможливо).

Ми вирішили, що ми готові викочуватися, коли переконалися, що ми зробили все можливе, щоб закрити всі ризики для наших користувачів, пов'язані з несподіваними афектами та даунтаймами. Тобто будь-що може піти не так, крім:

  1. Афекту (священної для нас, найдорожчої) інфраструктури користувача,
  2. Функціональностей: використання нашого сервісу після викочування має бути таким самим, як і до неї.

Викочування

Історія викочування, яка торкалася все
Двоє котять, 8 не заважають

Беремо даунтайм на всі запити від користувачів протягом 7 годин. На цей час у нас є як план викочування, так і план відкату.

  • Сама викочування займає приблизно 3 години.
  • 2 години – на тестування.
  • 2 години - запас на можливий відкат змін.

Складено діаграму Ганта на кожну дію, скільки часу вона займає, що йде послідовно, що проводиться паралельно.

Історія викочування, яка торкалася все
Шматок діаграми Ганта викочування, одна з ранніх версій (без перелікового виконання). Найцінніший інструмент синхронізації

У всіх, хто бере участь, визначено їх роль у викочуванні, які завдання роблять, за що відповідають. Намагаємось довести кожен етап до автоматизму, викотити відкотити, зібрати фідбек та котити знову.

хроніка подій

Отже, 15 людей приїхало на роботу в неділю 29 квітня, о 10-й вечора. Крім ключових учасників, деякі приїхали просто на підтримку команди, за що їм окреме спасибі.

Окремо варто згадати, що наш ключовий тестувальник у відпустці. Викочуватися без тестування неможливо, опрацьовуємо варіанти. Колега погоджується потішити нас із відпустки, за що їй безмежна подяка від усієї команди.

00:00. Стоп
Зупиняємо запити користувача, вішаємо шильдик, мовляв, технічні роботи. Моніторинг волає, але все штатно. Перевіряємо, що нічого не впало, окрім того, що мало. І розпочинаємо роботи з міграції.

У всіх є роздрукований план викочування по пунктах, всі знають, хто що робить і коли. Після кожної дії звіряємось із таймінгами, що не перевищуємо їх, і все йде за планом. Ті, хто не бере участі у викочуванні безпосередньо на поточному етапі, готуються, запустивши онлайн-іграшку (Xonotic, типу 3 квакі), щоб не заважати колегам. 🙂

02:00. Викотили
Приємний сюрприз – закінчуємо викочування на годину раніше, за рахунок оптимізації наших баз та скриптів міграції. Загальний клич, «викотили!» Всі нові функції в проді, але в інтерфейсі поки що бачимо тільки ми. Усі переходять у режим тестування, розбираються на купки і починають дивитися, що в результаті вийшло.

Вийшло не дуже, це розуміємо хвилин через 10, коли у проектах учасників команди нічого не підключено та не працює. Швидкий синк, озвучуємо наші проблеми, розставляємо пріоритети, розбиваємось на команди та йдемо в дебаг.

02:30. Дві великі проблеми vs чотири очі
Виявляємо дві великі проблеми. Зрозуміли, що замовники не побачать якісь підключені сервіси, і виникнуть проблеми з акаунтами партнерів. Обидві пов'язані з недосконалістю скриптів міграції в деяких крайових випадках. Потрібно фіксувати зараз.

Пишемо запити, які це фіксують мінімум у 4 очі. Прокочуємо на передпроді, щоб переконатися, що вони працюють і нічого не ламають. Можна котити далі. Паралельно запускається наше звичайне інтеграційне тестування, яке виявляє ще кілька проблем. Усі вони дрібні, але теж треба лагодити.

03:00. -2 проблеми +2 проблеми
Дві попередні великі проблеми зафіксовано, майже всі дрібні теж. Усі незайняті у фіксах активно працюють у своїх акаунтах та репортять, що знаходять. Пріоритезуємо, розподіляємо по командах, некритичне залишаємо на ранок.

Знову запускаємо тести, вони виявляють дві нові великі проблеми. Не всі політики сервісів доїхали правильно, так що деякі запити користувача не проходять авторизацію. Плюс нова проблема з обліковцями партнерів. Кидаємось дивитися.

03:20. Екстрений синк
Одну нову проблему виправлено. Для другої ми влаштовуємо екстрений синк. Розуміємо, що відбувається: попередній фікс полагодив одну проблему, але створив іншу. Беремо паузу, щоб розібратися, як зробити правильно і без наслідків.

03:30. Шість очей
Усвідомимо, який має бути підсумковий стан бази, щоб усе було гаразд у всіх партнерів. Пишемо запит у 6 очей, прокочуємо на передпроді, тестуємо, котимо на прод.

04:00. Все працює
Усі тести пройшли, критичних проблем не видно. Періодично у команді у когось щось не працює, оперативно реагуємо. Найчастіше тривога помилкова. Але іноді щось недоїхало, десь не працює окрема сторінка. Сидимо, фіксуємо, фіксуємо, фіксуємо. Окрема команда запускає останню велику фічу — білінг.

04:30. Точка неповернення
Наближається точка неповернення, тобто час, коли, якщо почнемо відкочуватися, не вкладемося у виданий нам даунтайм. Є проблеми з білінгом, який все знає та записує, але наполегливо не хоче списувати гроші з клієнтів. Є кілька багів на окремих сторінках, діях, статусах. Основний функціонал працює, усі тести проходять успішно. Приймаємо рішення, що викочування відбулося, відкочуватися не будемо.

06:00. Відкриваємо на всіх у UI
Баги пофікшені. Якісь, які не афектують користувачів, залишені на потім. Відкриваємо інтерфейс усім. Продовжуємо чаклувати над білінгом, чекаємо на фідбека користувачів та результатів моніторингу.

07:00. Проблеми з навантаженням на API
Стає ясно, що ми трохи неправильно розпланували навантаження на наше API та тестування цього навантаження, яке не змогло виявити проблему. Через війну ≈5% запитів фейлиться. Мобілізуємось, шукаємо причину.

Біллінг наполегливий, теж працювати не хоче. Вирішуємо його відкласти на потім, щоб провести зміни у спокійному режимі. Тобто всі ресурси в ньому збираються, але списання у клієнтів не проходять. Звичайно, це проблема, але порівняно загальною викочуванням здається не принциповою.

08:00. Фікс API
Викотили фікс для навантаження, фейли пішли. Починаємо розходитися додому.

10:00. Всі
Все зафіксовано. У моніторингу та у замовників тихо, команда поступово йде спати. Залишився білінг, його відновлюватимемо вже завтра.

Далі протягом дня були викатки, які полагодили логи, нотифікації, коди повернення та кастоми у деяких наших клієнтів.

Отже, викочування пройшло успішно! Може бути, звичайно, і краще, але ми зробили висновки про те, чого нам не вистачило, щоб досягти досконалості.

Разом

Протягом 2 місяців активної підготовки до моменту викочування виконано 43 завдання тривалістю від кількох годин до декількох днів.

Під час викочування:

  • нових і змінених демонів - 5 штук, що замінили 2 моноліти;
  • змін усередині баз даних - всі 6 наших баз з даними користувачів торкнулися, виконані вивантаження з трьох старих баз в одну нову;
  • повністю перероблений фронтенд;
  • кількість викачуваного коду - 33 тисяч рядків нового коду, ≈ 3 тисяч рядків коду в тестах, ≈ 5 тисяч рядків коду міграції;
  • всі ці цілі, жодна віртуалка замовника не постраждала. 🙂

Хороші практики для гарного викочування

Ними ми керувалися у цій складній ситуації. Але, взагалі кажучи, їх корисно дотримуватись при будь-якій викочуванні. Але чим викочування складніше, тим більшу роль вони грають.

  1. Перше, що треба — зрозуміти, як викочування може вплинути чи вплине на користувачів. Чи буде даунтайм? Якщо буде, то даунтайм чого? Як це вплине на користувачів? Які можливі найкращі та найгірші сценарії? І закривати ризики.
  2. Все спланувати. На кожному етапі потрібно розуміти всі аспекти викочування:
    • доставка коду;
    • відкат коду;
    • час кожної операції;
    • торкнувся функціонал.
  3. Програти сценарії до тих пір, поки не стануть очевидними всі етапи викочування, а також ризики на кожному з них. Якщо у чомусь є сумніви, можна взяти паузу та дослідити сумнівний етап окремо.
  4. Кожен етап можна і потрібно покращити, якщо це допоможе нашим користувачам. Наприклад, зменшить даунтайм або прибере якісь ризики.
  5. Тестування відкату набагато важливіше, ніж тестування доставки коду. Потрібно обов'язково перевірити, що в результаті відкату система повернеться до початкового стану, підтвердити це тестами.
  6. Все, що може бути автоматизовано, має бути автоматизовано. Все, що не може бути автоматизовано, має бути написане на шпаргалці.
  7. Зафіксувати критерій успішності. Який функціонал має бути доступним і в який час? Якщо цього немає, запускайте план отката.
  8. І найголовніше – люди. Кожен має бути в курсі, що робить, для чого і що від його дій залежить в процесі викочування.

А якщо однією фразою, то з гарним плануванням та опрацюванням можна викотити без наслідків для продання все що завгодно. Навіть те, що афектить усі ваші послуги в проді.

Джерело: habr.com

Додати коментар або відгук