Как быстро загрузить код на продакшн в Laravel

Небольшой пост о загрузке кода на продакшн сервер. Этот вопрос уже поднимался много раз, а в сети полно информации об этом. Как же в Laravel организовать деплой в продакшн, чтобы было легко и просто? Речь пойдет о инструменте deployer. Весь функционал запакован в phar файл и очень легко переносится от проекта к проекту. Есть несколько путей установки, включая и composer.

В общем, скачиваем дистрибутив deployer.phar и кидаем его в корень вашего проекта. И переименовываем в dep. Просто файл без расширения. Далее нужно создать файл настроек для определенного фреймворка. В нашем случае — это Laravel. Находясь в корне проекта, вводим следующую команду в терминал:

php dep init

После этого появится список фреймворков. Ставим цифру, которая стоит возле Laravel. В корне проекта появится новый файл: deploy.php Именно в нем мы и будем прописывать наши настройки.  Перед тем, как разобрать файл настроек, пару слов о том, как это все работает и как нужно настроить apache и nginx.

Смысл автоматического деплоя в том, чтобы создать ряд папок для хранения релизов и постоянных директорий и файлов. Например, на сервере будут созданы три каталога: current, releases и shared. Каталог current на самом деле пустой. Он по сути является ссылкой на текущий релиз. Когда произойдёт удачное развертывание проекта в папку releases, то для current будет создана новая ссылка на последний релиз.

Все релизы идут под номерами, которые генерируются исходя из даты деплоя на production. Именно внутри папки с цифрами и лежат все ваши файлы проекта. Вернее, почти все файлы. Так как общие файлы и папки, которые используются в любом релизе, хранятся в директории shared. А в релизах хранятся ссылки на эти общие файлы и папки.

С папкой current и releases разобрались. Что же должно быть в папке shared. В неё однозначно выносится файл настроек  проекта — .env. Именно в этом файле нужно прописать все настройки проекта, включая базу данных, работу с почтой и т.д. И он ни в коем случае не должен хранится в репозитории!

Также нужно в shared поместить npm, который применяется для всех релизов, папку storage, где хранятся кэш и логи. И те папки из public, которые одинаковы для всех релизов. Например, папка upload_images, куда загружаются изображения с сайта.

Теперь нужно подправить конфиги apache и nginx. В них нужно указать новую рабочую директорию, что-то типа:

/var/www/site/current/public

Единственное что нужно сделать на сервере, это только подправить конфиги. Создавать структуру папок не нужно. Это сделает сам deployer.

Для того, чтобы можно было делать выгрузку на production, вы должны хранить ваш проект в репозитории, например на github или bitbucket.

Помимо этого потребуется настроить ssh ключи доступа, чтобы ваш production сервер мог получать изменения из репозитория не по запросу пароля, а по приватному ключу. Как это делается можно легко найти в интернете. Переходим к настройке файла deploy.php:

<?php
/*
* This file has been generated automatically.
* Please change the configuration for correct use deploy.
*
* Start: php dep deploy production
*/
require 'recipe/laravel.php';
// Set configurations.
set('repository', '[email protected]:myname/myproject.git');
set('shared_files', ['.env']);
set('shared_dirs', [
'storage/app',
'storage/framework/cache',
'storage/framework/sessions',
'storage/framework/views',
'storage/logs',
'public/images/uploads',
'node_modules',
]);
set('writable_dirs', ['bootstrap/cache', 'storage', 'vendor', 'public/images/uploads']);
// Configure servers.
server('production', 'mysite.com', 22)
->user('admin')
->password()
->env('deploy_path', '/home/admin/web/mydomen.com/public_html');
/**
* Install NPM package.
*/
task('deploy:install-npm', function () {
run('cd {{release_path}} && npm i');
});
/**
* Compile assets.
*/
task('deploy:compile-assets', function () {
run('cd {{release_path}} && gulp --production');
});
/**
* Make migrate.
*/
task('deploy:migrations', function() {
run('cd {{release_path}} && php artisan migrate --force');
});
/**
* Make seed.
*/
/*task('deploy:seed', function() {
run('cd {{release_path}} && php artisan db:seed');
});*/
/**
* Create cache for routes.
*/
task('deploy:create-route-cache', function() {
run('cd {{release_path}} && php artisan route:clear');
});
/**
* Create cache for config.
*/
task('deploy:create-config-cache', function() {
run('cd {{release_path}} && php artisan config:clear');
});
/**
* Clear all cached data.
*/
task('deploy:clean-cached-data', function() {
run('cd {{release_path}} && php artisan view:clear');
});
/**
* Clear cached data from bootstrap.
*/
task('deploy:clean-cached-data-boot', function() {
run('cd {{release_path}} && rm bootstrap/cache/*');
});
/**
* Restart Apache on success deploy.
*/
task('reload:apache', function () {
run('sudo service httpd restart');
})->desc('Restart Apache service');
/**
* Restart Nging on success deploy.
*/
task('reload:nginx', function () {
run('sudo service nginx restart');
})->desc('Restart Nginx service');
task('deploy', [
'deploy:prepare',
'deploy:release',
'deploy:update_code',
'deploy:shared',
'deploy:vendors',
'deploy:clean-cached-data',
'deploy:clean-cached-data-boot',
'deploy:create-route-cache',
'deploy:create-config-cache',
'deploy:install-npm',
'deploy:compile-assets',
'deploy:migrations',
// 'deploy:seed',
'deploy:symlink',
'cleanup',
])->desc('Deploy your project');
after('deploy', 'success');
/**
* Restart servers.
*/
//after('success', 'reload:apache');
//after('success', 'reload:nginx');
/**
* After rollback restart servers.
*/
//after('rollback', 'reload:apache');
//after('rollback', 'reload:nginx');

Вначале указываем скрипту откуда нужно получать проект. В нашем случае из репозитория битбакет. Далее указываем, какие файлы будут общими. Общим будет только файл настроек.

Внимание, так как файл настроек не хранится в репозитории, то его необходимо будет залить на сервер вручную. Так как скрипт создаст пустой файл. Это нужно будет сделать только один раз.

Далее указываем, какие папки будут общими. Скрипт сам создаст эти папки на сервере. Потом указываем, какие папки будут записываемыми. Это нужно для того, чтобы скрипт выставил на них соответствующие права.

Затем указываем конфигурацию сервера, куда будем заливать релиз. Первый параметр в настройках сервера — это название для разворачивания. Например, может понадобится развернуть новый релиз не на одном сервере, а сразу на пяти. Тогда создаете пять разных настроек серверов. И в каждом указываете свое название: production, production1 и т.д. А потом при запуске деплоя просто указываете название сервера, куда нужно залить релиз:

php dep deploy production1

Идем дальше. А дальше у нас идут задачи (таски), которые нужно поочерёдно выполнять при заливке релиза. Первый параметр в таске — это название задачи. Потом идет функция замыкания, где в методе run указывается linux команда.

Сами по себе таски не запустятся, если не вызвать их запуск. Как видно из файлов настроек, в последней задаче переопределяем очередность вызова задач. Сидирование закомменировано. Как правило, его применяют только первый раз при заливке на продакшн. После этого он нам не нужен.

По последней задаче видно, что происходит, а именно: подготовка к загрузке проекта, соединение по ssh, соединение с репозиторием, далее происходит создание новой папки релиза и заливка в неё проекта, создание общих папок, установка пакетов и самого Laravel через composer, очистка разного кэша, установка nodeJS, компилирование ассетов через гулп, применение миграций, создание ссылки на новый релиз, очистка временных файлов.

Фактически, таски будут запущены этой командой:

after('deploy', 'success');

Будут выполнены таски, у которых есть префикс deploy и если всё пройдёт нормально, то будет возвращен статус успешного завершения деплоя на продакшн.

Ниже этой команды, можно увидеть ещё ряд закомментированых команд. Они нужны для автоматической перезагрузки apache и nginx, а также для перезагрузки серверов, если была команда на откат последнего релиза.

Для запуска автоматического деплоя на продакшн выполняете команды:

php dep deploy production

Или, если у вас только один сервер , то просто:

php dep deploy

Всё произойдет очень быстро и полностью автоматически. Кто ни разу не пользовался автодеплоем оценит по достоинству.