Skip to content

CI/CD

CI/CD

Що таке CI та CD

CI - Continuous integration - Неперервна інтеграція Неперервна інтеграція - це практика автоматичної збірки та тестування програми після кожної зміни в коді. Це дозволяє раніше виявляти помилки і конфлікти між різними частинами додатка. Вона полягає в тому, що всі зміни, внесені в код, об'єднуються в центральному репозиторії (ця операція називається "злиття"). Злиття відбувається кілька разів на день, і після кожного злиття в конкретному проекті спрацьовує автоматична збірка та тестування.

Буває, що перед збіркою та тестуванням програму потрібно компілювати (це залежить від мови, на якій вона написана). Сьогодні все частіше виникає необхідність упакувати додаток в контейнер Docker. Потім автоматичні тести перевіряють конкретні модулі коду, роботу користувацького інтерфейсу, продуктивність додатка, надійність API та інше. Всі ці етапи разом зазвичай називають "збіркою".

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

CD - Continuous delivery - Неперервна доставка

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

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

CD - Continuous deployment - Неперервне розгортання

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

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

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

Links

За якою стратегією можуть викочуватися білди на продакшен?

Summary

Універсальної відповіді немає - частота релізів залежить від бізнесу, архітектури й рівня тестового покриття. Типовий "адекватний" варіант - feature-branch → MR у test → регрес → MR у main → міграції + деплой за двома незалежними кроками.

Один з типових пайплайнів:

  1. Розробка у feature-гілках. З гілки робиться MR у проміжну гілку test (або dev/staging). Перед merge на цій гілці автоматично запускається CI-пайплайн: лінтери, юніт-тести, інтеграційні тести. Merge дозволено тільки після зеленого пайплайну.

  2. Тестування на test. На цій гілці QA проганяє ручні тести або періодично робиться регрес (велике тестування на кілька днів) перед мажорним релізом.

  3. MR у main (релізна гілка). При створенні MR пайплайн прогоняється повторно - лінтери, повний набір тестів. Після зеленого статусу - merge.

  4. Деплой у два кроки:

  5. Крок 1 - міграції БД. Окрема "кнопка" в CI/CD виконує всі pending-міграції на проді.
  6. Крок 2 - викочення сервісу. Друга "кнопка" розкочує новий білд застосунку.

Розділення критичне: міграції мають бути backward-compatible зі старою версією коду, щоб під час викочення (rolling/blue-green) старі поди ще працювали з оновленою схемою.

  1. Перевірка після деплою. Smoke-тести, health-check, метрики. Якщо щось пішло не так - rollback (за можливості - лише код, не схему БД).

Розповсюджені стратегії викочення:

  • Rolling update - поди оновлюються поступово, по N за раз. Простий, без даунтайму.
  • Blue/Green - два паралельні середовища; трафік перемикається атомарно. Найшвидший rollback.
  • Canary - нова версія отримує спочатку малий відсоток трафіку, потім - поступово більше. Найбезпечніший для ризикових змін.
  • Feature flags - фіча задеплоєна, але вмикається флагом для частини користувачів. Розділяє деплой і реліз.

Частота: від "раз на 2 тижні з жорстким циклом" до "десятки разів на день". Залежить від тестового покриття, моніторингу та готовності робити швидкий rollback.

Як безпечно видаляти поле з БД при CI/CD?

Summary

Видалення колонки розкочується двома релізами. У першому - прибираємо використання поля з коду, схема БД залишається. У другому - застосовуємо міграцію DROP COLUMN. Це уникає вікна, коли БД вже без поля, а старий код (ще не докатився) очікує його.

Проблема "одного релізу":

  • Міграція виконалась - поле видалено з таблиці.
  • Старий код ще на хостах (rolling update триває) - звертається до поля і отримує помилку типу ProgrammingError: column does not exist.

Рішення: два релізи (expand-and-contract / parallel change):

  1. Реліз #1 - прибрати використання.
  2. Видалити поле з усього коду: моделей/серіалізаторів, форм, запитів, шаблонів, бізнес-логіки.
  3. Колонку в БД не чіпати.
  4. Викочуємо - у проді більше ніхто з поля не читає і не пише.

  5. Реліз #2 - прибрати колонку з БД.

  6. Згенерувати міграцію ALTER TABLE DROP COLUMN (в Django - RemoveField, в SQLAlchemy/Alembic - op.drop_column()).
  7. Викочуємо - спершу новий код (нічого не зміниться), потім міграція.

Та сама схема - для перейменування (expand-and-contract):

  1. Додати нову колонку, почати писати в обидві.
  2. Backfill - скопіювати дані зі старої в нову.
  3. Перемкнути читання на нову.
  4. Прибрати запис у стару.
  5. Видалити стару колонку (два релізи, як вище).

Це варіація патернів expand-and-contract / parallel change - база для будь-яких backward-incompatible змін схеми у системах з zero-downtime деплоєм.