Деплой без простою в контейнерах - це rolling update: нові контейнери стартують, проходять healthcheck, отримують трафік, а старі зупиняються. Певний час стара й нова версії працюють одночасно з однією базою.
Звідси головне правило: схема бази має бути сумісною з обома версіями коду.
Небезпечні зміни, якщо робити їх за один крок:
- перейменування колонки: нова версія пише в
full_name, стара ще читаєname- помилки до завершення деплою; - видалення колонки: стара версія, що ще працює, звертається до неї;
NOT NULLдля нової колонки без значення за замовчуванням: стара версія не заповнює її при вставці;- зміна типу колонки з довгою перебудовою таблиці - блокування й таймаути.
Розширення й звуження (expand/contract, parallel change):
Перейменування name → full_name в три деплої:
- розширення: міграція додає
full_name(nullable); код пише в обидві колонки й читає зі старої; - перенесення: задача в черзі заповнює
full_nameдля старих рядків порціями; код читає з нової; - звуження: коли жодна версія не використовує
name- міграція видаляє її.
Порядок кроків деплою:
- зібрати образ, прогнати тести;
- виконати міграції разовим контейнером (
migrate --force --isolated) - схема стає «ширшою», стара версія продовжує працювати; - оновити контейнери поступово, з healthcheck;
- воркери черги - теж нова версія; задачі, поставлені старою версією, мають розбиратися новою (не змінювати сигнатуру конструктора job без сумісності);
- наступним деплоєм - очищувальна міграція.
Деталі, про які забувають:
- серіалізовані job у черзі: Laravel серіалізує об'єкт задачі; перейменований клас чи властивість - і задачі зі старого деплою падають у новому воркері;
- кеш: нова версія може читати з кешу дані у форматі старої - версіонуйте ключі чи очищуйте кеш;
- сесії й CSRF мають переживати деплой - Redis/база, однаковий
APP_KEY; - assets: користувач зі сторінкою старої версії підвантажує старі JS/CSS - вони мають бути доступні (CDN, хешовані імена);
- довгі міграції на великих таблицях - окремо від деплою, з
lock_timeout,CREATE INDEX CONCURRENTLYу PostgreSQL; - відкат: з розширювальними міграціями відкотити код можна без відкату схеми - це й робить їх безпечними.