Главная Технологии Услуги и цены Кейсы Блог Контакты
К списку статей DevOps и Инфраструктура

Пошаговое руководство по настройке Zero-Downtime CI/CD для Laravel

Опубликовано: 24.09.2026 в 15:18

Почему классический git pull на продакшене — это мина замедленного действия

Многие начинающие разработчики деплоят код прямо на «живом» сервере: заходят по SSH, делают git pull, а затем накатывают миграции и обновляют зависимости через composer install. В этот момент проект гарантированно уходит в даунтайм. Пользователи ловят 500-е ошибки из-за несоответствия старых кэшированных файлов OPcache новому коду, а тяжелые миграции ломают текущие транзакции. Наша цель — изолировать сборку от продакшена с помощью GitLab Runner и сделать переключение версий моментальным.

Анатомия атомарного деплоя через символические ссылки

Суть Zero-Downtime (деплоя без простоя) сводится к тому, что на сервере создается структура папок, где текущая рабочая директория является лишь виртуальной ссылкой (symlink). Каждая новая сборка заливается в отдельную изолированную папку, и только после успешного финала веб-сервер перенаправляется на нее.

схема без даунтайма
💡 Рис. 1 Схема без даунтайма

Шаг 1: Конфигурация рабочего процесса .gitlab-ci.yml

Создаем файл .gitlab-ci.yml в корне репозитория. Мы описываем глобальные стадии (stages) и подключаем легковесный Docker-образ с предустановленным PHP нужной версии для запуска тестов, а деплой осуществляем через SSH-клиент встроенного раннера.

yaml
stages:
  - test
  - deploy

cache:
  paths:
    - vendor/

run_tests:
  stage: test
  image: php:8.3-alpine
  before_script:
    - apk add --no-cache bash git unzip
    - docker-php-ext-install bcmath
    - curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
  script:
    - composer install --no-progress --prefer-dist
    - cp .env.example .env
    - php artisan key:generate
    - vendor/bin/phpunit
  only:
    - main

deploy_to_production:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client bash
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
  script:
    - |
      ssh $SERVER_USER@$SERVER_HOST "
        cd /var/www/isitreal
        # Сюда передается скрипт атомарного переключения
      "
  only:
    - main

Шаг 2: Алгоритм развертывания на сервере

Внутри изолированной SSH-сессии, которую инициировал GitLab Runner, мы выполняем строгую последовательность шагов, чтобы подготовить релиз к запуску:

  • Создание новой папки в каталоге releases/ с уникальным ID (таймстампом).
  • Клонирование репозитория в эту папку и установка production-зависимостей без dev-пакетов.
  • Связывание общего файла конфигурации .env и папки storage/app/public из директории shared/.
  • Запуск миграций базы данных в режиме принудительного выполнения (php artisan migrate --force).
  • Создание новой символической ссылки и атомарная подмена старой.
bash
# Пример атомарной подмены симлинка на стороне Linux
ln -sfn /var/www/isitreal/releases/release_$TIMESTAMP /var/www/isitreal/current
# Перезагрузка PHP-FPM для мгновенного сброса кэша OPcache
sudo systemctl reload php-fpm

Итоги и резюме

Итог автоматизации

Внедрение этой схемы полностью решает проблему «сломанного» продакшена. Если на этапе тестов или сборки Composer в GitLab CI/CD что-то пойдет не так, пайплайн аварийно остановится со статусом Failed, а сервер продолжит стабильно отдавать старый рабочий релиз из директории current. Время фактического переключения на новый код занимает менее 0.1 секунды.

Была ли полезна статья?

Оценки помогают мне понимать, какие темы вам наиболее интересны.

Чтобы оценить, войдите или зарегистрируйтесь.