Модуль 33

Zero-downtime deploy

Ось готовий урок на тему Zero-downtime deploy, написаний у стилі Девіда Малана: енергійно, доступно та з фокусом на розумінні суті.


🎓 CS50: Zero-downtime Deploy (Розгортання без простою)

Привіт, світ! Радий бачити вас знову! 👋

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

Тема нашого уроку — Zero-downtime deploy.


1. 🔥 Вступ: Чому це болить?

Уявіть ситуацію. Ви запустили популярний інтернет-магазин. Зараз "Чорна п'ятниця", на сайті тисячі користувачів, кожну секунду проходять оплати. 💸

І тут ви знаходите критичний баг у коді розрахунку знижок. Або просто хочете додати нову круту кнопку "Купити в один клік".

Ви заливаєте новий код на сервер, перезапускаєте програму і... Бабах! 💥 На 30 секунд, хвилину або навіть 5 хвилин усі ваші користувачі бачать сторінку: «502 Bad Gateway» або «Сайт на технічному обслуговуванні».

Риторичне запитання: Що робить користувач, коли бачить помилку під час оплати? Правильно, він панікує, закриває вкладку і йде до конкурента. Ви втрачаєте гроші. Ви втрачаєте репутацію.

Раніше, у 90-х чи нульових, було нормально сказати: "Сайт не працюватиме з 02:00 до 04:00". Це як бібліотека, яка зачиняється на переоблік. 📚⛔️ Але сьогодні світ — це цілодобовий мегаполіс. Ви не можете просто вимкнути світло в усьому місті, щоб замінити одну лампочку.

Zero-downtime deploy — це техніка оновлення вашого додатку так, що жоден користувач навіть не помічає моменту переключення. Для них сайт працює завжди.


2. 🧠 Теоретична база: Як це працює "під капотом"?

Давайте розберемося без складних термінів. Як ми можемо оновити щось, не вимикаючи це?

Ключовий гравець тут — Балансувальник навантаження (Load Balancer). Уявіть його як швейцара на вході в готель. 🎩

  1. Користувачі не йдуть прямо до кухаря (вашого сервера з кодом).
  2. Вони йдуть до швейцара.
  3. Швейцар знає, де зараз кухня, і направляє гостей туди.

Щоб зробити Zero-downtime, нам потрібна надлишковість. Тобто, у нас має бути не одна версія додатку, а мінімум дві (або можливість запустити другу паралельно).

Три головні стратегії (запам'ятайте їх!):

🔵🟢 1. Blue-Green Deployment (Синьо-Зелений)

Це найпростіша для розуміння концепція. * У вас є Blue (поточна версія, працює зараз). * Ви розгортаєте Green (нова версія) поруч. Вона запускається, прогрівається, підключається до бази. Але користувачі її ще не бачать. * Момент істини: Ви даєте команду Балансувальнику (швейцару): "Тепер направляй усіх на Green!". * Це перемикання займає мілісекунди. * Якщо Green зламався — ви миттєво перемикаєте назад на Blue.

🔄 2. Rolling Update (Поступове оновлення)

Уявіть, що у вас кластер із 10 серверів. * Ви оновлюєте 1-й сервер. Інші 9 працюють на старій версії. * Потім 2-й. Потім 3-й. * Це як замінювати колеса у вантажівці, яка має 10 осей, на ходу. Вона продовжує їхати, просто спирається на інші колеса.

🐤 3. Canary Deployment (Канарейка)

Назва походить від шахтарів, які брали канарейку в шахту для перевірки газу. * Ви пускаєте на нову версію лише 5% користувачів. * Якщо вони не скаржаться і помилок немає — пускаєте решту 95%.

Інтуїтивно: Всі ці методи зводяться до одного — мати працюючу стару версію доти, доки нова не буде готова на 100% прийняти естафету.


3. 🧪 Приклади: Від простого до реального

Приклад 1: "Наївний" підхід (Як робити НЕ треба) ❌

# Ви заходите на сервер по SSH
git pull origin master
npm install
npm run build
pm2 restart all  <-- ТУТ ВАШ САЙТ ЛЯГАЄ

Чому: Між зупинкою старого процесу і запуском нового є час, коли порт (наприклад, 3000) ніхто не слухає.


Приклад 2: Blue-Green на рівні портів (Спрощено) ✅

Уявіть, що у нас є Nginx (наш швейцар).

  1. Зараз працює App v1 на порту 3000.
    • Nginx конфіг: proxy_pass http://localhost:3000;
  2. Ви запускаєте App v2 на порту 3001.
    • Перевіряєте: curl http://localhost:3001. Працює? Супер.
  3. Магія: Ви змінюєте конфіг Nginx:
    • proxy_pass http://localhost:3001;
    • І робите nginx -s reload (це безшовна команда).
  4. Тепер трафік йде на v2.
  5. Гасите v1 на порту 3000.

Питання до вас: А що станеться з користувачем, який саме в цей момент завантажував великий файл через v1 (порт 3000)? * Відповідь: Якщо ми просто "вб'ємо" процес v1 — завантаження обірветься. Тому нам потрібен Graceful Shutdown (ввічливе завершення).


Приклад 3: Проблема бази даних (Найскладніше) 🤯

Ви оновлюєте код: стара версія (v1) використовує колонку name, а нова (v2) розбила її на first_name та last_name.

  • Якщо ви спочатку зміните базу (міграція), стара версія (v1) впаде, бо не знайде колонку name.
  • Якщо ви спочатку викотите код (v2), він впаде, бо в базі ще немає нових колонок.

Як це вирішують профі? 1. Створити нові колонки, але залишити стару. 2. Викотити код (v2), який пише в нові, але вміє читати зі старої (якщо треба). 3. Тільки коли v1 повністю зникне — видалити стару колонку name (через тиждень).


4. 🛠 Практична частина

Уявіть, що ви DevOps у стартапі. Ваше завдання — продумати логіку.

Завдання 1: Ручний перемикач У вас є два процеси Node.js: app_blue та app_green. Напишіть псевдокод або алгоритм скрипта, який: 1. Перевіряє, хто зараз активний. 2. Оновлює "неактивний". 3. Перемикає трафік.

Завдання 2: "Graceful Shutdown" Напишіть фрагмент коду (мовою, яку знаєте, або псевдокодом), що робить додаток, коли отримує сигнал "Зупинись" (SIGTERM)? Підказка: Він має перестати брати нові запити, але дочекатися завершення старих.

Завдання 3: Кейс із міграцією Ви додаєте обов'язкове поле phone_number в таблицю Users. Як провести деплой без помилок, якщо старий код не знає про це поле і намагатиметься створити юзера без нього (а база видасть помилку NOT NULL constraint failed)? * Рішення: Зробити поле NULLABLE спочатку -> Деплой коду -> Заповнити дані -> Зробити NOT NULL. Розпишіть кроки.

Завдання 4: А що, якщо... Що, якщо ми використовуємо стратегію Canary (5% трафіку), і ці 5% користувачів поклали товари в кошик на новій версії, а потім ми знайшли баг і відкотили їх назад на стару версію? Чи зникне їхній кошик? Подумайте про те, де ми зберігаємо сесії.


5. 💡 Мислення як у розробника

Ось де новачки роблять помилки, а сеньйори п'ють каву спокійно:

  1. Сесії в пам'яті (In-Memory Sessions) — це зло. 😈 Якщо ви перезавантажуєте сервер або перекидаєте юзера з Blue на Green, а сесія була в оперативній пам'яті сервера — користувача "розлогінить".

    • Pro Tip: Завжди використовуйте зовнішнє сховище для сесій (наприклад, Redis). Тоді неважливо, який сервер відповідає — сесія на місці.
  2. Міграції БД — це окремий етап. Не змішуйте code deploy і db migration в одну купу в голові. База даних — це спільний ресурс для Blue і Green версій одночасно в момент деплою. Вона має бути сумісна з обома!

  3. Не бійтеся відкату (Rollback). Головне в Zero-downtime — це не тільки гарно викотити, а й миттєво повернути все назад, якщо нова версія зламана. Blue-Green ідеальний для цього: просто перемкніть рубильник назад.


6. 🧩 Підсумок

Отже, що ми сьогодні розібрали?

  1. Zero-downtime — це стандарт індустрії. Користувач не повинен страждати через ваші оновлення.
  2. Ми дізналися про Blue-Green, Rolling Updates та Canary.
  3. Ми зрозуміли роль Балансувальника (швейцара).
  4. Ми зрозуміли, що База Даних і Сесії — це підводні камені, про які треба дбати окремо.

Тепер ви вмієте думати не просто як кодер, який пише function(), а як інженер, який будує надійну систему. 🏗️

Тизер наступного уроку: Ви запитаєте: "Девіде, невже я маю щоразу руками перемикати ці порти і сервери?" Звісно, ні! На наступному уроці ми поговоримо про CI/CD та Docker — роботів, які робитимуть цю магію за вас автоматично, поки ви спите.

Це був CS50. Побачимось! 👋