Релиз в пятницу вечером, «минутка технических работ» с заглушкой на сайте, звонок от владельца бизнеса «а почему магазин не работает» — знакомый сценарий для любой команды, которая деплоит 1С-Битрикс по старинке: остановили сайт, залили файлы, накатили миграции, включили обратно. На небольшом проекте пара минут простоя пройдёт незамеченной. На магазине с заказами каждую минуту и SLA перед оптовыми клиентами та же пара минут — это упущенная выручка, сорванный вебхук от платёжной системы и звонки в поддержку.
Zero-downtime деплой — это набор инженерных практик, при которых новая версия сайта выкатывается и проверяется, не затрагивая работающую версию, а переключение происходит так, что ни один пользовательский запрос не попадает в промежуток «сайта уже/ещё нет». Ниже — как адаптировать blue-green и rolling-стратегии к специфике 1С-Битрикс, где код и состояние (сессии, файлы, кэш) исторически тесно связаны с конкретным сервером. Материал основан на нашей практике автоматического zero-downtime деплоя и настройки CI/CD для проектов на 1С-Битрикс.
Коротко
- Битрикс сложнее деплоить, чем безстейтовое приложение: сессии, загруженные файлы и композитный кэш по умолчанию привязаны к конкретному серверу.
- Атомарная выкладка через симлинк на новый релиз убирает «рваное» промежуточное состояние даже на одном сервере.
- Полноценный blue-green требует общего хранилища сессий/файлов и здоровой стратегии миграций базы (expand-and-contract).
- Перед переключением трафика — health-check новой версии и прогрев композитного кэша, иначе первые посетители получат «холодные» медленные страницы.
- Откат должен быть спроектирован заранее — как переключение симлинка или балансировщика обратно, а не как экстренное «давайте разбираться».
Почему Битрикс сложнее деплоить, чем безстейтовое приложение
В классическом безстейтовом веб-приложении деплой выглядит просто: поднять новый контейнер, убедиться, что он отвечает на запросы, переключить на него трафик, погасить старый. Проблема в том, что 1С-Битрикс исторически проектировался под другую модель — один сервер, на котором физически лежит и код, и загруженные файлы, и файловый кэш, и (по умолчанию) сессии PHP. Это удобно для небольшого проекта на одном сервере и превращается в источник багов, как только серверов или окружений становится больше одного.
Из этой особенности вытекают три практических следствия, с которыми нужно разобраться до первого zero-downtime релиза:
- Файлы и код перемешаны. Каталог
/uploadс изображениями товаров и пользовательскими файлами обычно лежит рядом с кодом ядра и должен быть общим для всех версий и окружений, а не частью релиза, который заменяется целиком. - Композитный кэш требует прогрева. Композитный режим отдаёт статическую часть страницы мгновенно, но эта статика должна быть заранее собрана — «холодное» новое окружение без прогретого кэша выглядит рабочим, но заметно медленнее, что пользователь воспринимает как деградацию, даже если технически простоя не было.
- Сессии и корзина по умолчанию — на диске сервера. Если их не вынести в общее хранилище, переключение между окружениями в середине пользовательской сессии обрывает авторизацию и корзину — сайт формально не упал, но конкретный покупатель эффект простоя всё равно ощутил.
Что такое zero-downtime деплой
Формально zero-downtime деплой — это выкладка новой версии приложения таким образом, что ни один входящий HTTP-запрос не получает ошибку соединения и не обрывается из-за самого факта деплоя. Разница с «быстрым» деплоем принципиальна: быстрый деплой минимизирует окно простоя (секунды вместо минут), а zero-downtime устраняет это окно как явление — переключение происходит на границе завершённых запросов, а не поверх работающего процесса.
Технически это достигается тем, что новая версия сайта поднимается и полностью готова к работе до того, как на неё пойдёт хоть один реальный пользовательский запрос. Старая версия продолжает обслуживать трафик всё это время. Переключение — это не «остановить старое, запустить новое», а «включить новое, убедиться, что оно работает, и только потом выключить старое».
Blue-green и rolling: чем отличаются стратегии
Есть две основные стратегии переключения без простоя, и они решают немного разные задачи.
Blue-green деплой. Существуют два полных, идентичных по составу окружения — условно «синее» и «зелёное». В любой момент времени одно из них активно (принимает боевой трафик), второе — простаивает или используется для подготовки следующего релиза. Новая версия выкатывается целиком во второе окружение, проходит проверки, и только после этого балансировщик или веб-сервер переключает весь трафик на него одним движением. Плюс — мгновенный и полный откат (переключить обратно), минус — нужно вдвое больше вычислительных ресурсов на время деплоя.
Rolling-деплой. Вместо двух полных окружений есть несколько узлов кластера, и новая версия выкатывается на них по одному: узел выводится из ротации балансировщика, обновляется, проходит проверку, возвращается в ротацию — и так по кругу, пока все узлы не обновятся. Плюс — не нужно держать вдвое больше ресурсов, минус — какое-то время старая и новая версия работают параллельно и обслуживают разных пользователей одновременно, что требует более строгой обратной совместимости кода и схемы базы данных на этот переходный период.
| Критерий | Blue-green | Rolling |
|---|---|---|
| Ресурсы на время деплоя | ×2 (два полных окружения) | Минимальный оверхед (по одному узлу) |
| Скорость отката | Мгновенная (переключить обратно) | Требует повторного rolling в обратную сторону |
| Параллельная работа старой/новой версии | Практически нет (переключение разом) | Да, на время обновления всех узлов |
| Нужен веб-кластер из нескольких узлов | Не обязательно, достаточно двух окружений | Да, минимум 2–3 узла |
| Требования к обратной совместимости кода | Ниже (переключение почти мгновенное) | Выше (версии сосуществуют дольше) |
Симлинк, rolling, blue-green — что выбрать
Между «просто перезаписать файлы на сервере» и полноценным blue-green есть промежуточный и очень практичный вариант для проекта на одном сервере или BitrixVM — атомарная выкладка через симлинк. Идея простая: каждый релиз разворачивается в отдельный каталог (/releases/2026-12-05-142300/), а рабочий каталог сайта — это символическая ссылка, которая одной атомарной операцией переключается на новый каталог релиза. Пока новый релиз разворачивается, тестируется зависимостями и прогревает кэш, старый продолжает обслуживать трафик из своего каталога — пользователи не видят никакого промежуточного «наполовину нового» состояния.
- Симлинк-деплой. Минимальные затраты на инфраструктуру, подходит для одного сервера, откат — переключить симлинк обратно за доли секунды. Не спасает от простоя во время долгих миграций базы данных, если код и база меняются несовместимо.
- Rolling. Нужен, когда сайт уже работает на нескольких веб-узлах веб-кластера — деплой на них по очереди без потери ёмкости кластера. Хорошо сочетается с симлинк-деплоем на каждом узле по отдельности.
- Blue-green. Оправдан при частых релизах, высоких требованиях к SLA или когда откат должен быть гарантированно мгновенным независимо от типа изменений. Дороже по инфраструктуре, но даёт наибольший запас надёжности.
На практике зрелые проекты на 1С-Битрикс комбинируют подходы: симлинк-деплой на каждом узле веб-кластера плюс rolling-переключение между узлами — это даёт большую часть выгод blue-green без удвоения инфраструктуры. Подробнее про сам веб-кластер и балансировку — в статье о кластеризации и отказоустойчивости 1С-Битрикс.
Миграции базы данных на лету: expand-and-contract
Самое хрупкое место любого zero-downtime деплоя — не код, а данные. Пока переключение происходит, старая и новая версия кода могут какое-то время (даже доли секунды при blue-green, и куда дольше при rolling) работать с одной и той же базой данных. Если миграция схемы «разрушающая» — переименовала колонку, изменила тип данных несовместимо, удалила поле, — одна из версий кода в этот момент начинает падать с ошибками SQL.
Решение — паттерн expand-and-contract (расширение, затем сжатие), который разбивает любое изменение схемы на безопасные шаги:
- Expand — добавить новое, не трогая старое. Новая колонка, новая таблица, новый highload-блок добавляются рядом с существующими. Старый код их не видит и продолжает работать как раньше.
- Выкатить код, который пишет в оба места. Переходный релиз кода записывает данные и в старую, и в новую структуру одновременно — это даёт возможность откатиться на предыдущую версию кода в любой момент без потери данных.
- Перенести исторические данные фоновым скриптом. Миграция существующих записей из старого формата в новый выполняется отдельно от деплоя кода, без блокировки таблицы целиком, обычно порциями (батчами).
- Выкатить код, который читает только из нового места. Когда все данные перенесены и стабильно пишутся в новую структуру, следующий релиз кода перестаёт обращаться к старой.
- Contract — удалить старое отдельным релизом. Только когда точно нет кода, который зависит от старой колонки или таблицы (включая код на других узлах при rolling-деплое), её можно безопасно убрать.
Сессии, файлы и корзина: общее состояние между окружениями
Blue-green и rolling предполагают, что запрос одного и того же пользователя в любой момент может обслужить любое из работающих окружений. Это работает только если состояние пользователя не привязано к конкретному серверу.
- Сессии. Хранение сессий в файлах на локальном диске сервера — первое, что ломается при переключении между окружениями. Нужно общее хранилище — база данных или, для нагруженных проектов, распределённый кэш (Redis, memcached), доступный обоим окружениям одинаково.
- Загруженные файлы. Каталог
/upload— изображения товаров, файлы из карточек заказов — должен физически находиться в общем сетевом хранилище (NFS, S3-совместимое объектное хранилище), а не быть частью релиза, который целиком заменяется каждый деплой. - Корзина и авторизация. Если корзина и данные авторизации хранятся вместе с сессией в общем месте, покупатель, оформляющий заказ в момент переключения трафика между окружениями, не заметит ничего — запрос просто попадёт на другой, но полностью эквивалентный сервер.
Этот пункт по сути пересекается с тем, что требуется для веб-кластера как такового — не случайно обе задачи (масштабирование под нагрузку и zero-downtime деплой) опираются на одну и ту же архитектурную работу: вынести состояние из-под конкретного сервера в общий слой.
Прогрев композитного кэша перед переключением
Композитный режим 1С-Битрикс собирает статические HTML-снимки страниц, чтобы отдавать их без обращения к PHP и базе данных. На новом окружении сразу после деплоя этих снимков ещё нет — первые запросы вынуждены собирать страницу «вживую», что заметно медленнее. Если переключить трафик на неразогретое окружение резко и полностью, первая волна пользователей получит просевшую по скорости версию сайта — формально без простоя, но с деградацией, которую легко перепутать с ним по ощущениям.
Практическое решение — прогревать композитный кэш управляемо, до переключения боевого трафика: пройтись краулером или скриптом по ключевым страницам (главная, топ-категории каталога, популярные карточки товаров) на новом окружении, пока оно ещё не принимает реальных пользователей, и только затем переключать балансировщик. На рolling-деплое то же самое имеет смысл делать на каждом обновлённом узле перед возвратом его в ротацию.
Health-check перед переключением трафика
Готовность нового окружения нельзя определять фактом «процесс запустился» — нужна содержательная проверка, что сайт реально работает: отдаёт корректный HTML на ключевых страницах, подключается к базе данных, видит распределённый кэш и хранилище сессий, а не просто слушает порт. Практический набор проверок перед переключением обычно включает: HTTP-статус 200 на главной и нескольких страницах каталога, отсутствие ошибок в логе PHP за время прогрева, доступность подключения к базе и к Redis/memcached, и — отдельно — успешное выполнение «смоук-теста» ключевого сценария (например, добавление товара в корзину через тестовый запрос).
Health-check должен быть частью автоматизированного пайплайна, а не ручной проверкой «глазами полистал — вроде работает». Ручная проверка не масштабируется на частые релизы и пропускает регрессии, которые не бросаются в глаза с первого взгляда.
Откат за секунды: как его спроектировать заранее
Возможность быстрого отката — не то, что придумывается в момент инцидента, а часть архитектуры деплоя, заложенная заранее. Три условия, при которых откат действительно занимает секунды, а не превращается в отдельный экстренный релиз:
- Предыдущий релиз физически ещё существует. При симлинк-деплое — это соседний каталог в
/releases/, который ещё не удалён; при blue-green — окружение, которое просто пока не остановлено, а не разобрано. - Миграции базы данных были обратно совместимы. Откат кода на предыдущую версию не должен упираться в то, что база уже не соответствует старой схеме — именно поэтому важен expand-and-contract, описанный выше.
- Откат — это тоже переключение, а не повторное развёртывание. Переключить симлинк или балансировщик обратно на прежний каталог/окружение — операция того же порядка скорости, что и сам деплой, в отличие от «откатить руками через git revert и передеплоить с нуля».
Хорошая практика — держать в пайплайне отдельную, заранее протестированную команду отката, которая ничем не отличается по механике от деплоя, кроме направления переключения. Тогда решение «откатываемся» в момент инцидента не требует придумывать процесс на ходу под давлением времени.
Реализация в 1С-Битрикс: пайплайн деплоя
На практике весь процесс — от коммита в git до переключения боевого трафика — управляется CI/CD-пайплайном, а не ручными командами инженера на сервере. Типичный дашборд такого пайплайна для 1С-Битрикс выглядит примерно так:
Типовой pipeline zero-downtime деплоя — по шагам
- Сборка релиза в изолированный каталог. Код разворачивается в новый каталог (
/releases/{timestamp}/) или новое окружение, не затрагивая рабочую версию. - Обратно совместимые миграции базы. Только «расширяющие» изменения схемы (expand) применяются на этом этапе — ничего, что сломало бы работающий сейчас старый код.
- Симлинки на общие каталоги.
/uploadи другие общие данные подключаются к новому релизу через символические ссылки на общее хранилище, а не копируются. - Прогрев композитного кэша. Скрипт обходит ключевые страницы нового релиза, пока он ещё не принимает боевой трафик.
- Health-check и смоук-тест. Автоматическая проверка ключевых страниц и одного-двух критичных сценариев (например, оформление тестового заказа в песочнице).
- Переключение трафика. Атомарное изменение симлинка рабочего каталога либо переключение балансировщика на новое окружение (blue-green) или поочерёдное обновление узлов (rolling).
- Мониторинг после переключения. Несколько минут повышенного внимания к логам ошибок и метрикам ответа — окно, в течение которого откат ещё максимально дёшев.
- «Уборочный» релиз миграций. Отдельным более поздним деплоем — удаление устаревших полей и таблиц (contract), когда весь трафик гарантированно обслуживается новым кодом.
Частые ошибки
- Совмещают в одной миграции добавление нового поля и удаление старого — старый код падает в момент, пока идёт переключение трафика.
- Держат сессии и корзину в файлах на локальном диске сервера при переходе на несколько узлов или окружений — пользователей начинает «разлогинивать» на переключении.
- Переключают трафик на новое окружение сразу после разворачивания файлов, не прогрев композитный кэш — первая волна пользователей получает заметно более медленный сайт.
- Проверяют готовность нового релиза только по факту «сервер отвечает», без содержательного health-check — регрессии в бизнес-логике проскакивают в прод.
- Не тестируют процедуру отката заранее — в момент реального инцидента откат превращается в ещё один стрессовый деплой с непредсказуемым временем.
- Оставляют каталог
/uploadчастью самого релиза вместо общего сетевого хранилища — файлы, загруженные через старое окружение, не видны новому. - Удаляют предыдущий релиз сразу после переключения «для экономии места» — теряют возможность мгновенного отката именно тогда, когда он нужнее всего.
- Разворачивают zero-downtime пайплайн только для кода, забывая, что часть логики 1С-Битрикс выполняется агентами по расписанию — их тоже нужно учитывать при переключении, чтобы одна и та же задача не запустилась дважды на старом и новом окружении одновременно.
Чек-лист перед первым zero-downtime релизом
Прежде чем полагаться на zero-downtime деплой в проде, стоит пройти по контрольному списку:
- Выкладка атомарна. Новый релиз собирается в отдельном каталоге/окружении, переключение — одна атомарная операция (симлинк или балансировщик).
- Сессии и корзина — в общем хранилище. Не привязаны к диску конкретного сервера.
- Загруженные файлы — на общем сетевом хранилище. Не являются частью самого релиза.
- Миграции базы разбиты по паттерну expand-and-contract. Ни одна не совмещает добавление и удаление несовместимых изменений в одном шаге.
- Есть автоматический прогрев композитного кэша перед переключением боевого трафика на новую версию.
- Настроен содержательный health-check и смоук-тест ключевого сценария, а не только проверка «порт отвечает».
- Откат протестирован заранее — команда/кнопка отката существует, а не придумывается в момент инцидента.
- Учтены фоновые агенты Битрикс. Понятно, как они себя ведут при переключении между окружениями, и исключён риск двойного запуска.
Вывод
Zero-downtime деплой на 1С-Битрикс — это прежде всего архитектурная работа, а не просто более умный скрипт выкладки: нужно вынести сессии, файлы и корзину из-под конкретного сервера, разбить миграции базы на обратно совместимые шаги, прогревать композитный кэш до переключения и держать откат таким же дешёвым и быстрым, как сам деплой. Сделав это один раз, вы получаете возможность выкатывать релизы днём, часто и без звонков «а почему магазин не работает» — вне зависимости от того, идёт ли речь о симлинк-деплое на одном сервере или о полноценном blue-green на кластере.