Гибкий деплой приложений с Deployer
Feb 13, 2017 11:14 · 567 words · 3 minute read
Несомненно, тема уже хорошо известна, ведь многие стараются автоматизировать процессы развертывания приложений, тестирования, настройки серверов и обновления программного кода.
Для этого можно использовать множество разных инструментов — Phing, Envoyer, Capistrano, Ansistrano и конечно же Deployer. Давайте разберемся!
Deployer мне пришелся по душе по многим причинам — написан на php, устанавливается и настраивается очень просто, код скрипта получается коротким и понятным, хорошо документирован и есть много рабочих примеров.
Установка не должна вызвать никаких трудностей:
curl -LO https://deployer.org/deployer.phar
mv deployer.phar /usr/local/bin/dep
chmod +x /usr/local/bin/dep
Далее в каталоге с исходным кодом проекта необходимо создать файл eploy.php
, в котором и будем описывать процесс развертывания приложения:
touch deploy.php
Во-первых, необходимо настроить путь к репозиторию приложения, например:
...
set('repository', '{ваш-git-репозиторий.git}');
...
Во-вторых, необходимо описать хотя бы один сервер, на который будет производиться деплой:
...
server('production', 'example.com')
->user('{пользователь-для-деплоя}')
->identityFile()
->set('deploy_path', '/var/www/example');
...
Самый простой способ подключения к серверу для деплоя — авторизация по ssh-ключу. По умолчанию используются ключи ~/.ssh/id_rsa
и ~/.ssh/id_rsa.pub
, но если вы хотите использовать другие ssh-ключи или ключи, созданные с паролем, то нужно использовать параметр identityFile
, например:
...
->identityFile('~/Code/.ssh/id_rsa.pub', '~/Code/.ssh/id_rsa', 'password_for_keys')
...
Добавим также в скрипт деплоя так называемые «шары» — общие файлы и папки для всех релизов (например, это могут быть файлы настроек и каталог с логами/сессиями/кешем и т.д.):
...
add('shared_files', [
'.env'
]);
add('shared_dirs', [
'storage'
]);
...
С такой минимальной конфигурацией уже можно выполнять развертывание приложения:
dep deploy
Данная команда при выполнении создаст на сервере «example.com» в каталоге /var/www/example
следующую структуру проекта:
├── .dep
├── current -> releases/1
├── releases
│ └── 1
└── shared
├── .env
└── storage
В каталоге releases
будут находиться релизы (по умолчанию сохраняется 5 последних релизов, это значение можно изменить добавив в скрипт деплоя строку set('keep_releases', 3);
).
В каталоге shared
находятся общие файлы/папки для всех релизов, которые будут подключаться с помощью симлинков.
Несложно догадаться, что current
— это симлинк на последний успешно развернутый релиз (ссылка будет указывать на предыдущий релиз пока не выполнятся успешно все задачи из скрипта деплоя).
В каталоге .dep
хранятся метаданные для deployer
‘a — логи скрипта, логи релизов, файл .lock
(создается в момент деплоя) и т. д.
Как правило, минимальной конфигурации скрипта деплоя недостаточно для «реальных» проектов, поэтому некоторые задачи приходится дописывать самостоятельно. Например, если нам нужно после обновления программного кода перезапустить php-fpm
на сервере, то скрипт деплоя нужно дополнить:
...
desc('Restart PHP-FPM service');
task('php-fpm:restart', function () {
run('sudo systemctl restart php7.0-fpm.service');
});
after('deploy:symlink', 'php-fpm:restart');
...
Примечание. Пользователь, от которого выполняется деплой, должен иметь права на перезапуск сервиса php-fpm
на сервере.
После проделанных действий также нужно изменить путь к каталогу с кодом в настройках web-сервера, для Nginx это может выглядеть так:
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example/current/public;
location / {
try_files $uri /index.php$is_args$args;
}
}
Существуют также готовые рецепты для многих популярных фреймворков, таких как Laravel, Symfony, Yii, Zend и т.д., которые еще больше упрощают настройку деплоя, подробнее о них можно узнать здесь.
Мой скрипт деплоя полностью выглядит так:
<?php
namespace Deployer;
require 'recipe/laravel.php';
// Configuration
set('repository', '{git-репозиторий.git}');
set('keep_releases', 3);
add('shared_files', [
'.env'
]);
add('shared_dirs', [
'storage'
]);
add('writable_dirs', [
'bootstrap/cache',
'storage',
'node_modules',
'vendor'
]);
// Servers
set('default_stage', 'dev');
server('dev', '{dev-server}')
->user('deployer')
->identityFile('~/Code/.ssh/id_rsa.pub', '~/Code/.ssh/id_rsa')
->stage('dev')
->set('deploy_path', '/var/www/html');
server('prod', '{prod-server}')
->user('deployer')
->identityFile('~/Code/.ssh/id_rsa.pub', '~/Code/.ssh/id_rsa')
->stage('prod')
->set('deploy_path', '/var/www/html');
// Tasks
desc('Run NPM install');
task('deploy:install-npm', function () {
cd('{{release_path}}');
run('npm install');
});
desc('Run GULP');
task('deploy:compile-assets', function () {
cd('{{release_path}}');
run('gulp --production');
});
desc('Restart PHP-FPM service');
task('php-fpm:restart', function () {
run('sudo systemctl restart php7.0-fpm.service');
});
after('artisan:config:cache', 'deploy:install-npm');
after('deploy:install-npm', 'deploy:compile-assets');
after('deploy:writable', 'artisan:migrate');
after('deploy:symlink', 'php-fpm:restart');