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
:
Или же в github.com
:
После того, как ключи добавлены, необходимо соединиться с репозиторием для добавления в список доверенных хостов:
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 = $_ENV['DEPLOY_USER'] ?? false)) { throw new Exception('--DEPLOY_USER must be specified'); }
if(!($authKey = $_ENV['DEPLOY_USER_KEY'] ?? false)) { throw new Exception('--DEPLOY_USER_KEY must be specified'); }
if(!($authServer = $_ENV['DEPLOY_SERVER'] ?? false)) { throw new Exception('--DEPLOY_SERVER must be specified'); }
$gitBranch = 'master';
if(!($gitRepository = $_ENV['DEPLOY_REPOSITORY'] ?? false)) { throw new Exception('--DEPLOY_REPOSITORY must be specified'); }
if(!($dirBase = $_ENV['DEPLOY_PATH'] ?? false)) { 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-11-12 00:35:18
Автор : Rosko