Ось готовий урок на тему 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). Уявіть його як швейцара на вході в готель. 🎩
- Користувачі не йдуть прямо до кухаря (вашого сервера з кодом).
- Вони йдуть до швейцара.
- Швейцар знає, де зараз кухня, і направляє гостей туди.
Щоб зробити 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 (наш швейцар).
- Зараз працює App v1 на порту 3000.
- Nginx конфіг:
proxy_pass http://localhost:3000;
- Nginx конфіг:
- Ви запускаєте App v2 на порту 3001.
- Перевіряєте:
curl http://localhost:3001. Працює? Супер.
- Перевіряєте:
- Магія: Ви змінюєте конфіг Nginx:
proxy_pass http://localhost:3001;- І робите
nginx -s reload(це безшовна команда).
- Тепер трафік йде на v2.
- Гасите 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. 💡 Мислення як у розробника
Ось де новачки роблять помилки, а сеньйори п'ють каву спокійно:
-
Сесії в пам'яті (In-Memory Sessions) — це зло. 😈 Якщо ви перезавантажуєте сервер або перекидаєте юзера з Blue на Green, а сесія була в оперативній пам'яті сервера — користувача "розлогінить".
- Pro Tip: Завжди використовуйте зовнішнє сховище для сесій (наприклад, Redis). Тоді неважливо, який сервер відповідає — сесія на місці.
-
Міграції БД — це окремий етап. Не змішуйте
code deployіdb migrationв одну купу в голові. База даних — це спільний ресурс для Blue і Green версій одночасно в момент деплою. Вона має бути сумісна з обома! -
Не бійтеся відкату (Rollback). Головне в Zero-downtime — це не тільки гарно викотити, а й миттєво повернути все назад, якщо нова версія зламана. Blue-Green ідеальний для цього: просто перемкніть рубильник назад.
6. 🧩 Підсумок
Отже, що ми сьогодні розібрали?
- Zero-downtime — це стандарт індустрії. Користувач не повинен страждати через ваші оновлення.
- Ми дізналися про Blue-Green, Rolling Updates та Canary.
- Ми зрозуміли роль Балансувальника (швейцара).
- Ми зрозуміли, що База Даних і Сесії — це підводні камені, про які треба дбати окремо.
Тепер ви вмієте думати не просто як кодер, який пише function(), а як інженер, який будує надійну систему. 🏗️
Тизер наступного уроку: Ви запитаєте: "Девіде, невже я маю щоразу руками перемикати ці порти і сервери?" Звісно, ні! На наступному уроці ми поговоримо про CI/CD та Docker — роботів, які робитимуть цю магію за вас автоматично, поки ви спите.
Це був CS50. Побачимось! 👋