Несомненно, тема, думаю, многими заезжена до дыр — всё-таки, деплой надо делать для каждого проекта — но я всё же подниму её и расскажу об одном замечательном инструменте, о котором, по какой-то странной причине, до сих пор ничего не написали на Хабре, да и вообще в русскоязычном сегменте как-то о нём мало что написано. Исправим это недоразумение.
Deployer хорош во многих отношениях. Код скрипта для деплоя получается коротким. Написан на старом добром Пыхчанском — то бишь, скорее всего, ставить отдельно какие-то другие инструменты на сервер вам не придётся. Если же и придётся — то PHP обычно устанавливается одной командой на любом сервере. Почему-бы и не заюзать его в своих проектах?
Написал утилиту некий Антон Медведев, у него кстати довольно приятный блог есть. Спасибо тебе, Антон :)
Первый коммит был сделан аж в 2013-м году, и до сих пор инструмент потихоньку развивается. У него также есть приятный сайт, на котором можно найти о нём всю документацию.
Что лично мне нравится больше всего из того, что даёт данный инструмент — это возможность быстро откатиться на прошлый "рабочий" релиз, если новый релиз оказался неудачным. Также довольно удобно то, что если при попытке "выкатить" новый релиз что-то пойдёт не так (миграции не применились, фронтенд файлы не скомпилировались, тесты не прогнались..) — то ваше текущее работающее приложение это никак не затронет — оно будет работать как ни в чём ни бывало. Дело в том, что Deployer не изменит ссылку у директории, обозначающей текущий активный релиз, до того момента, пока ваш новый "релиз" не будет полностью установлен и готов к работе.
Единственное, чего Deployer не решает — это возможные проблемы с применением миграций к вашей базе данных. Но это вообще тема сложна��, не знаю, существуют ли вообще элегантные решения в данном случае. Если существует — буду рад узнать, какое.
Структура папок релизов
Весь проект разделяется на три папки: current, releases и shared. В общем, это довольно распространённый вид для подобных инструментов, и он действительно удобен. Скажем, в одном из моих проектов на Laravel эта структура выглядит вот так:

current — ссылка на папку последнего успешно собранного релиза, т.е. текущее приложение.
releases — все релизы, которые были собраны. По умолчанию сохраняется только последние три релиза, и это значение можно легко поменять.
shared — папка, в которой находятся все "общие" файлы, которые относятся ко всем релизам одновременно и не должны создаваться каждый раз заново. К примеру — файл .env, загруженые пользователями файлы, и так далее.
Пример скрипта деплоя Laravel приложения
Я люблю лично зайти на свой сервер, запустить скрипт деплоя и наблюдать за процессом его работы. Просто, мне так намного спокойнее жить, так как я всегда могу предпринять какие-то срочные меры, если при деплое что-то пойдёт не так. А так, как я знаю, люди обычно запускают подобный скрипт со своей локальной машины, которая подключается по SSH к серверу и производит деплой. Если это надо сделать сразу на нескольких машинах — то такой подход конечно будет удобнее. К слову, Deployer позволяет выполнять деплой сразу на нескольких машинах в том числе.
Естественно, перед тем как получить возможность выполнить данный скрипт, вам необходимо сначала установить Deployer на свою систему.
В одном из моих проектов на Laravel 5 скрипт деплоя deploy.php выглядит следующим образом:
<?php // Подключим основные рецепты из Deployer'а require 'recipe/common.php'; require 'recipe/laravel.php'; // Укажем основные параметры деплоя localServer('local', 'localhost') ->user('{ваш-пользователь}') ->env('deploy_path', '/path/to/project/dir') ->stage('local') ; set('repository', '{ваш-git-репозиторий.git}'); env('branch', '{ветка-для-релизов}'); env('git_cache', true); // Общие папки для вашего проекта, которые будут прозрачно доступны всем релизам // Они не будут создаваться заново при новом релизе, вместо них будут созданы // ссылки на их одноимённые папки в папке shared set('shared_dirs', [ 'storage/app', 'storage/framework/cache', 'storage/framework/sessions', 'storage/framework/views', 'storage/logs', 'public/uploads', 'node_modules', ]); // Общие файлы. Принцип точно такой же, как с папками // В случае с Laravel нам необходимо сделать "общим" лишь один // файл - .env set('shared_files', ['.env']); // Папки, в которые приложение должно иметь возможность // писать данные. В нашем случае - это три директории set('writable_dirs', ['storage', 'vendor', 'public/uploads' ]); set('http_user', '{ваш-пользователь}'); set('composer_command', '/usr/local/bin/composer'); // Путь к расположение Composer'а // Задача для деплоя. Установить NPM компоненты task('deploy:install-npm', function() { run('cd {{release_path}} && npm i'); }); // Ещё одна задача: скомпилировать все фронтенд файлы, в моём случае // это делается через Grunt.js task('deploy:compile-assets', function() { run('cd {{release_path}} && grunt deploy-production'); }); // Выполнить миграции task('deploy:migrations', function() { run('cd {{release_path}} && php artisan migrate --force'); }); // Создать кеш для правил роутинга task('deploy:create-route-cache', function() { run('cd {{release_path}} && php artisan route:cache'); }); // Создать кеш для файлов конфигураций task('deploy:create-config-cache', function() { run('cd {{release_path}} && php artisan config:cache'); }); // Очистить все закешированные данные task('deploy:clean-cached-data', function() { run('cd {{release_path}} && rm bootstrap/cache/*'); }); // Перезапустить PHP после успешного деплоя task('reload:php-fpm', function() { run('sudo /usr/sbin/service php7.0-fpm restart'); }); task('deploy', [ 'deploy:prepare', 'deploy:release', 'deploy:update_code', // Скачать последний код с гитхаба 'deploy:shared', // Создать ссылки на общие данные 'deploy:vendors', // Обновить компоненты композера 'deploy:clean-cached-data', // Очистить все закешированные данные 'deploy:create-route-cache', // Создать кеш для правил роутинга 'deploy:create-config-cache', // Создать кеш для файлов конфигураций 'deploy:install-npm', // Обновить NPM компоненты 'deploy:compile-assets', // Скомпилировать фронтенд файлы 'deploy:migrations', // Применить миграции 'deploy:symlink', // создать ссылку текущего релиза на этот 'cleanup', // Удалить старые релизы ])->desc('Deploy your project'); after('deploy', 'success'); // После деплоя перезапустим php after('deploy', 'reload:php-fpm'); // После отката на прошлый релиз - тоже перезапустим его after('rollback', 'reload:php-fpm');
Также у меня есть пара маленьких файлов, лежащих рядом с вышеуказанным файлом: start-deploy.sh и rollback-deploy.sh. Для того чтобы быстро запустить деплой или, соответственно, откатить его.
Файл start-deploy.sh:
dep deploy local
Файл rollback-deploy.sh:
dep rollback local
Следовательно, чтобы запустить процесс деплоя, нам остаётся набрать лишь одну команду в Bash'е:
./start-deploy.sh
Таким образом, как мы видим, введя всего одну команду, мы заставим сервер выполнить все необходимые шаги для разворачивания нашего проекта. И только если всё прошло хорошо, папка current сменит ссылку на новый релиз и перезапустит PHP после всего этого.
В общем-то, это всё, что я хотел рассказать и показать. Надеюсь, это будет кому-то полезным. Ну и конечно интересно будет узнать мнение других людей о том, как они занимаются деплоем своих приложений.
