Deploy приложения Laravel с помощью Envoy

Table of contents

Introduction

Рано или поздно встает вопрос о необходимости автоматизировать доставку изменений в продакшн. В случае с Laravel-приложением нам на помощь приходит инструмент под названием Envoy.

Рассмотрим процесс деплоя с одного сервера (dev или staging), на котором проводится непосредственная разработка и тестирование, на продакшн сервер. Для этого нам необходимо немного настроить оба сервера.

Для демонстрации работы деплоя был создан тестовый проект: https://github.com/superrosko/example-laravel-envoy.

Настройка production-сервера

На продакшн сервере необходимо создать пользователя, назовем его deployer:

sudo useradd deployer -m
sudo usermod -G www-data deployer
sudo usermod -s /bin/bash deployer

Если нам необходимо использовать команды из под sudo без ввода пароля, то добавим следующую строку в /etc/sudoers:

# User rules for deployer
deployer ALL=(ALL) NOPASSWD:ALL

Зададим пароль для нового пользователя и залогинимся под ним:

sudo passwd deployer
sudo su deployer

Нам необходимо сгенерировать ключи для дальнейшего доступа и добавить их в authorized_keys:

ssh-keygen -t RSA -b 4096
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

Копируем созданный ключ:

cat ~/.ssh/id_rsa.pub

Добавим его в список ключей для деплоя в репозиторий gitlab.com:

deploy-keys-settings-gitlab

Или же в github.com:

deploy-keys-settings-github

После того, как ключи добавлены, необходимо соединиться с репозиторием для добавления в список доверенных хостов:

ssh git@github.com
ssh git@gitlab.com

После создания пользователя нам необходимо настроить web-сервер, а именно прописать document root, где app - это наше приложение, а current - это символьная ссылка на текущий релиз проекта:

/var/www/app/current

Теперь настроим файловую систему проекта, для этого в /var/www/app скопируем наш файл .env (для продакшн сервера) и создадим директорию shared, в которую скопируем медиаресурсы (картинки, видео…) из storage/app/public, создав также и данный путь.

Т.к. мы создали нового пользователя, то необходимо для него установить node через nvm. Сделать это можно как описано в статье Базовая настройка сервера для LEMP стека.

Настройка dev-сервера

Для деплоя с сервера разработки необходимо сохранить приватный ключ пользователя deployer для доступа к production.

Envoy будет считывать настройки из файла окружения, поэтому добавим в него следующую конфигурацию:

DEPLOY_USER=deployer
DEPLOY_USER_KEY=~/.ssh/deploy/deployer@production
DEPLOY_SERVER=production
DEPLOY_PATH=/var/www/app
DEPLOY_REPOSITORY=""
  • DEPLOY_USER - пользователь, под которым происходит деплой
  • DEPLOY_USER_KEY - путь до приватного ключа для соединения
  • DEPLOY_SERVER - адрес сервера, на который будет происходить деплой
  • DEPLOY_PATH - директория на сервере, в которую будет происходить деплой
  • DEPLOY_REPOSITORY - репозиторий, из которого будет деплой

Файл конфигурации Envoy

Создадим в корне проекта файл Envoy.blade.php, в котором опишем задачи для деплоя. Начнем с секции конфигурации параметров. Подключим подгрузку пакетов и считаем настройки из файла .env.

@include('vendor/autoload.php')

@setup
    $dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
    $dotenv->load();

    $releaseRotate = 5;
    $timezone = 'Europe/Moscow';
    $date = new datetime('now', new DateTimeZone($timezone));

    if(!($authUser = getenv('DEPLOY_USER'))) { throw new Exception('--DEPLOY_USER must be specified'); }
    if(!($authKey = getenv('DEPLOY_USER_KEY'))) { throw new Exception('--DEPLOY_USER_KEY must be specified'); }
    if(!($authServer = getenv('DEPLOY_SERVER'))) { throw new Exception('--DEPLOY_SERVER must be specified'); }

    $gitBranch = 'master';
    if(!($gitRepository = getenv('DEPLOY_REPOSITORY'))) { throw new Exception('--DEPLOY_REPOSITORY must be specified'); }

    if(!($dirBase = getenv('DEPLOY_PATH'))) { throw new Exception('--DEPLOY_PATH must be specified'); }
    $dirShared = $dirBase . '/shared';
    $dirCurrent = $dirBase . '/current';
    $dirReleases = $dirBase . '/releases';
    $dirCurrentRelease = $dirReleases . '/' . $date->format('YmdHis');
@endsetup
  • releaseRotate - количество релизов для хранения
  • authUser - пользователь, под которым происходит деплой
  • authKey - путь до приватного ключа для соединения
  • authServer - адрес сервера, на который будет происходить деплой
  • gitBranch - ветка, которая будет клонироваться на продакшн
  • gitRepository - репозиторий, из которого будет деплой
  • dirBase - директория на сервере, в которую будет происходить деплой
  • dirShared - директория на сервере для медиафайлов
  • dirCurrent - ссылка на последний релиз
  • dirReleases - директория на сервере с релизами
  • dirCurrentRelease - директория на сервере с текущим релизом

Укажем сервера, на которые происходит деплой:

@servers(['production' => '-i ' . $authKey. ' ' . $authUser . '@' . $authServer])

Далее зададим процесс деплоя:

@story('deploy', ['on' => 'production'])
    gitclone
    composer
    npm
    config_project
    set_current
    releases_clean
@endstory

Процесс деплоя будет состоять из последовательного выполнения задач, указанных в сторис.

Перейдем к описанию конкретных задач и начнем с задачи клонирования репозитория:

@task('gitclone', ['on' => $on])
    echo "# Gitclone task"

    mkdir -p {{$dirCurrentRelease}}
    git clone --depth 1 -b {{$gitBranch}} {{$gitRepository}} {{$dirCurrentRelease}}

    echo "# Repository has been cloned"
@endtask

Далее установим зависимости composer:

@task('composer', ['on' => $on])
    echo "# Composer task"

    cd {{$dirCurrentRelease}}
    composer install --no-interaction --quiet --no-dev --prefer-dist --optimize-autoloader

    echo "# Composer dependencies have been installed"
@endtask

После этого установим node modules и соберем assets:

@task('npm', ['on' => $on])
    echo "# Npm task"

    cd {{$dirCurrentRelease}}
    export NVM_DIR="$HOME/.nvm"
    [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
    [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
    npm install -only=production
    npm audit fix
    npm run production

    echo "# Npm dependencies have been installed"
@endtask

Далее конфигурируем проект и устанавливаем символьные ссылки:

@task('config_project', ['on' => $on])
    echo "# Config project task";

    echo "# Linking storage directory";
    rm -rf {{$dirCurrentRelease}}/storage/app;
    cd {{$dirCurrentRelease}};
    ln -nfs {{$dirShared}}/storage/app storage/app;
    php artisan storage:link

    echo "# Linking .env file";
    cd {{$dirCurrentRelease}};
    ln -nfs {{$dirBase}}/.env .env;

    chgrp -R www-data {{$dirShared}};
    chgrp -R www-data {{$dirCurrentRelease}};
    chmod -R ug+rwx {{$dirShared}};
    chmod -R ug+rwx {{$dirCurrentRelease}};

    echo "# Optimising installation";
    php artisan clear-compiled --env={{$env}};
    php artisan optimize --env={{$env}};
    php artisan config:cache --env={{$env}};
    php artisan cache:clear --env={{$env}};
@endtask

После конфигурации проект готов и останется только установить ссылку на данный релиз как текущую:

@task('set_current', ['on' => $on])
    echo '# Linking current release';
    ln -nfs {{$dirCurrentRelease}} {{$dirCurrent}};
@endtask

И затем почистим старые релизы:

@task('releases_clean')
    purging=$(ls -dt {{$dirReleases}}/* | tail -n +{{$releaseRotate}});

    if [ "$purging" != "" ]; then
        echo "# Purging old releases: $purging;"
        rm -rf $purging;
    else
        echo "# No releases found for purging at this time";
    fi
@endtask

Полный файл конфигурации доступен в репозитории: https://github.com/superrosko/example-laravel-envoy/blob/master/Envoy.blade.php.

Не были описаны задачи по миграции и созданию бекапа, т.к. использовался начальный проект Laravel без установки дополнительных пакетов и применения базы данных. Создание бекапов можно настроить как описано в статье: Настройка бекапирования для Laravel в облако AWS S3.

Теперь остается только установить envoy глобально:

composer global require laravel/envoy

И запустить деплой командой:

envoy run deploy

После запуска на продакшн сервере появится развернутая и сконфигурированная версия проекта.

Дата публикации :
Дата редактирования : 2020-04-04 15:34:38
Автор :

Cookies and IP addresses allow us to deliver and improve our web content, resolve technical errors, and provide you with a personalized experience. Our website uses cookies and collects your IP address for these purposes.