Статьи

Разверните свое PHP-приложение с помощью Rocketeer

Было время, когда разработчикам PHP приходилось использовать инструменты развертывания, предназначенные для общих веб-приложений. Вы можете увидеть это в руководстве Йоханнеса Шиклинга по развертыванию приложений Laravel , например, с Capistrano . Это инструмент Ruby, и вам нужно написать код на Ruby. Эти инструменты выполняют свою работу, но имеют ограниченную интеграцию с приложениями PHP. Это может привести к хакерским решениям для определенных сценариев.

Но в настоящее время мы наделены несколькими инструментами развертывания, написанными на нашем языке, которые обеспечивают более глубокую интеграцию. Одним из таких инструментов является Rocketeer, инструмент, вдохновленный Capistrano и средой Laravel.

Rocketeer — это современный инструмент, который предлагает отличный подход для ваших нужд развертывания. Это значит запускать задачи и управлять вашим приложением в разных средах и на разных серверах. Вдобавок к этому, он также имеет некоторое волшебство, такое как установка зависимостей Composer, если он обнаруживает файл composer.json . Вы получаете разумные значения по умолчанию и автоматизацию типичных задач для современного приложения PHP. И у вас есть возможность настроить и расширить все.

Вы могли бы описать это как SSH Runner, который работает на стороне клиента. Команды выполняются на серверах через соединение SSH. Если вы используете провайдера виртуального хостинга только с доступом по FTP, к сожалению, вам не повезло. Вам также нужен удаленный репозиторий, откуда инструмент может получить ваш код. По умолчанию есть поддержка Git и SVN. Нужна поддержка другой системы контроля версий? Напишите свою собственную реализацию с предоставленными интерфейсами.

Вы можете установить Rocketeer двумя разными способами. Либо вы загружаете файл phar и делаете его исполняемым, либо устанавливаете его через Composer. Я сторонник последнего. Наличие его в качестве зависимости позволяет легко установить его при клонировании репозитория. Это может принести пользу любому, кто клонирует репозиторий, чтобы запустить его.

Установка с помощью Composer:

1
$ composer require anahkiasen/rocketeer —dev

Я не рекомендую устанавливать его глобально. Сохранение его на уровне хранилища гарантирует, что каждый человек, выполняющий развертывание, использует одну и ту же версию. То, что я действительно рекомендую, это чтобы вы добавили vendor/bin в PATH. Затем вы можете использовать бинарный файл, набрав rocketeer в корне вашего проекта.

Давайте начнем! Сначала вы загружаете каталоги и файлы для конфигурации. Вы делаете это, запустив rocketeer ignite в корне вашего проекта.

Когда ваше приложение зажигается, инструмент создает папку .rocketeer в вашем проекте. Содержимое каталога будет выглядеть так:

1
2
3
4
5
6
7
8
|
|
|
|
|
|
|
|

Это все файлы конфигурации, которые вам нужны для настройки ваших развертываний. Каждый раз, когда я ссылаюсь на файл конфигурации, он существует в .rocketeer/ .

Важно понимать, как Rocketeer управляет структурой своих папок на стороне сервера, поскольку он немного отличается от обычной настройки. Он использует несколько каталогов для управления определенными аспектами развертывания, поэтому он может быть эффективным в том, что он делает. Вы указываете путь к месту, где вы хотите развернуть свое приложение на своем сервере, а инструмент позаботится обо всем остальном. Эта папка будет выглядеть следующим образом, если в качестве каталога приложения вы используете /var/www/app .

1
2
3
4
5
6
7
8
9
|
|
|
|
|
|
|
|
|

Самая важная папка — current , которая указывает на ваш последний выпуск. Вот где должен быть установлен корень документа вашего веб-сервера. Так что же происходит при развертывании?

  1. Инструмент создает папку с releases каталоге releases .
  2. Завершает все задачи, чтобы сделать готовый релиз.
  3. Обновляет символическую ссылку current новой версии.

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

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

События управляют инструментом, и все стратегии и задачи запускают событие до и после запуска. Они также предоставляют специальное событие остановки при сбое задачи. Это может быть, например, dependencies.halt или deploy.halt для общего сбоя. Это позволяет нам подключиться к процессу, где нам нужно.

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

  • deploy.before : прежде чем что-то случится.
  • create-release.before : перед тем, как он создаст новый каталог выпуска.
  • create-release.after : после создания нового каталога выпуска.
  • dependencies.before : перед установкой или обновлением зависимостей.
  • dependencies.after : после установки или обновления зависимостей. Возможно, убедитесь, что исполняемые файлы в папке вашего поставщика являются исполняемыми.
  • test.before : перед запуском тестов.
  • test.after : после запуска тестов.
  • migrate.before : перед запуском миграций базы данных. Может быть, вы хотите сделать резервную копию вашей базы данных?
  • migrate.after : после выполнения миграций базы данных.
  • deploy.before-symlink : перед deploy.before-symlink ссылкой на выпуск в качестве нашего текущего выпуска.
  • deploy.after : завершено. Вы могли бы уведомить людей, что все было гладко или иначе.

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

В основе Rocketeer мы находим концепцию, называемую задачами . Большая часть того, что происходит под капотом, является основной задачей. Определение задачи может быть набором инструкций для выполнения в качестве шага в развертывании. Если мы посмотрим на некоторые классы, которые предоставляет инструмент, мы можем получить общее представление о том, что такое задачи: классы, такие как Deploy , Setup , Migrate , Rollback и Dependencies . При развертывании сама команда развертывания является задачей с подзадачами.

Здесь вы начнете видеть, насколько интегрирован инструмент с PHP, поскольку вы будете писать задачи на языке. Вы можете создавать свои собственные задачи тремя различными способами:

Произвольные терминальные команды . Это однострочники, которые вы хотите запустить на своем сервере. Может быть полезным для многих вещей, например, для запуска gulp build ---production .

Закрытия Если вам нужно немного больше гибкости или сложности, вы можете написать задачу как замыкание (анонимная функция). Скажем, вы хотите создать документацию для API во время развертывания.

1
2
3
function($task) {
    return $task->runForCurrentRelease(‘apigen generate source src destination api’);
}

Занятия Для более сложных задач вы должны использовать опцию создания классов для задач. Вы создаете класс и расширяете Rocketeer\Abstracts\AbstractTask . Затем вы должны предоставить хотя бы описание и метод execute() . Вот совершенно бесполезный пример, чтобы показать структуру класса задачи:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
namespace MyDeployableApp\Deploy\Tasks;
 
class HelloWorld extends \Rocketeer\Abstracts\AbstractTask
{
    /**
     * Description of the Task
     *
     * @var string
     */
    protected $description = ‘Says hello to the world’;
 
    /**
     * Executes the Task
     *
     * @return void
     */
    public function execute() {
        $this->explainer->line(‘Hello world!’);
 
        return true;
    }
}

Обратите внимание, что вы должны зарегистрировать классы задач самостоятельно. Либо вы делаете это через файл hooks.php и добавляете его в custom массив …

1
‘custom’ => array(‘MyDeployableApp\Deploy\Tasks\HelloWorld’,),

… или вы можете сделать это через фасад:

1
Rocketeer::add(‘MyDeployableApp\Deploy\Tasks\HelloWorld’);

Как только вы зарегистрируете его, вы можете выполнить его:

1
2
3
4
$ rocketeer hello:world
staging/0 |
staging/0 |=> Hello world!
Execution time: 0.004s

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

Самый простой способ определения ваших задач — в файле hooks.php . Для этого предусмотрено два массива, определяющих выполнение задачи до или после определенных событий.

1
2
3
4
5
‘before’ => [
    ‘setup’ => [],
    ‘deploy’ => [‘hello:world’],
    ‘cleanup’ => [],
],

Возможно, вы уже можете сказать, что поставленные задачи являются довольно общими. Взять, к примеру, Dependencies . О каких зависимостях мы говорим и какой менеджер пакетов?

Здесь стратегии вступают в игру. Стратегия — это конкретная реализация задачи, например, запуск тестов в Behat или использование Gulp для создания вашего интерфейса. Задачи имеют стратегию по умолчанию с возможностью запуска других стратегий через CLI. Мы можем перечислить доступные стратегии следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
$ rocketeer strategies
+—————+—————-+————————————————————————+
|
+—————+—————-+————————————————————————+
|
|
|
|
|
|
|
|
|
|
|
|
|
+—————+—————-+————————————————————————+

Скажем, вы делаете BDD с Behat для своего приложения вместо TDD. Затем вы хотите запустить свои тесты с Behat вместо PHPUnit. Поскольку это тестовый прогон, для этого уже есть пространство имен стратегии, но нет реализации. Создайте каталог .rocketeer/strategies/ и поместите BehatStrategy.php свой новый BehatStrategy.php .

01
02
03
04
05
06
07
08
09
10
namespace MyDeployableApp\Deploy\Strategies;
 
use Rocketeer\Abstracts\Strategies\AbstractStrategy;use Rocketeer\Interfaces\Strategies\TestStrategyInterface;
 
class BehatStrategy extends AbstractStrategy implements TestStrategyInterface
{
    public function test() {
        return $this->binary(‘vendor/bin/behat’)->runForCurrentRelease();
    }
}

Теперь вы можете переключить свою тестовую стратегию на новую реализацию в strategies.php .

1
‘test’ => ‘Behat’,

Неважно, если у вас есть инфраструктура или вы планируете ее использовать. Не имеет значения, развернуто ли ваше приложение во многих средах на многих серверах. Ракетчик будет там для вас. Вы даже можете иметь много разных мест на одном сервере. Это где термины соединения и этапы ввода.

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

Стадии — это соединения внутри соединений, своего рода «восприятие соединения». Вы можете настроить промежуточную и производственную среду на одном сервере с использованием этапов. Таким образом, вместо двух отдельных соединений у вас есть одно соединение с двумя этапами.

Отличной особенностью является то, что мы можем расширить наш процесс с помощью плагинов. Есть несколько официальных для интеграции с Laravel , Slack , HipChat и Campfire . Тогда есть несколько, но не так много, на Packagist . Установка плагинов — это простая задача через CLI:

1
$ rocketeer plugin:install rocketeers/rocketeer-slack

Несмотря на ограниченное количество плагинов, это оставляет место для разработки плагинов в будущем. Это говорит о хорошей философии. И почему бы не разработать свой собственный?

Чтобы вывести ваше приложение с нуля, вам нужна базовая настройка. Вы должны указать Rocketeer, где найти ваше приложение и где оно должно быть развернуто. Давайте начнем с установки имени приложения и настройки производственного сервера в config.php .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
‘application_name’ => ‘my-deployable-app’,
 
// […]
 
‘connections’ => [
    ‘staging’ => [
        ‘host’ => ‘staging.my-deployable-app.com’,
        ‘username’ => »,
        ‘password’ => »,
        ‘key’ => ‘/Users/niklas/.ssh/id_rsa’,
        ‘keyphrase’ => »,
        ‘agent’ => »,
        ‘db_role’ => true,
    ],
    ‘production’ => [
        ‘host’ =>
        ‘www.my-deployable-app.com’,
        ‘username’ => »,
        ‘password’ => »,
        ‘key’ => ‘/Users/niklas/.ssh/id_rsa’,
        ‘keyphrase’ => »,
        ‘agent’ => »,
        ‘db_role’ => true,
    ],
],

Теперь у вас есть имя приложения и сервер для развертывания приложения. Эта настройка использует аутентификацию по ключу SSH, но вы также можете подключиться с помощью имени пользователя и пароля. Чтобы получить запрос на ввод имени пользователя и пароля, установите 'key' => '' . Инструмент будет хранить учетные данные на вашем локальном компьютере и использовать их каждый раз позже. Я не рекомендую устанавливать имя пользователя и пароль в конфигурационном файле, потому что вы никогда не хотите, чтобы учетные данные передавались в ваш репозиторий.

Теперь вы должны изменить подключение по умолчанию, к которому вы развертываете. Установка по умолчанию на производство не идеальна. Вы не хотите развертывать на производстве случайно. Поэтому в том же файле найдите ключ по default и вместо этого измените значение на staging .

1
‘default’ => [‘staging’],

Само название приложения не так важно. Но если вы не укажете папку для развертывания, она будет использовать ее в качестве имени папки в корневом каталоге. По умолчанию корень установлен на /home/www . С этим именем приложения оно будет развернуто в /home/www/my-deployable-app . Если вы хотите изменить свой корневой каталог, вы можете изменить это в remote.php .

1
2
// Deploys to /var/www/my-deployable-app/
‘root_directory’ => ‘/var/www/’,

В том же файле у вас есть возможность переопределить имя приложения и указать каталог для вашего приложения.

1
2
// Deploys to /var/www/tutsplus-tutorial
‘app_directory’ => ‘tutsplus-tutorial’,

Теперь у вас есть получающая сторона развертывания, но вам также нужно настроить местоположение вашего кода, чтобы его можно было извлечь. Вы делаете это, настраивая свой удаленный репозиторий в scm.php . По умолчанию он использует Git, но также поддерживает SVN. Вы сообщаете ему адрес нашего репозитория и при необходимости предоставляете учетные данные. Я предлагаю вам также использовать аутентификацию по SSH-ключу и оставить имя пользователя и пароль пустыми.

1
2
3
4
‘repository’ => ‘git@github.com:owner/name.git’,
‘username’ => »,
‘password’ => »,
‘branch’ => ‘master’,

Поскольку вы добавили соединение к производственному серверу, вы хотите развернуть основную ветку.

В большинстве случаев вам не нужен один и тот же параметр конфигурации для всех ваших соединений или этапов. Например, вы хотите развернуть другую ветвь в промежуточной среде. Rocketeer позволяет вам переопределить значения конфигурации для соединений и этапов, используя config.php . Чтобы развернуть ветку с именем staging в вашем промежуточном соединении, вы делаете это:

1
2
3
4
5
6
7
8
9
‘on’ => [
    ‘connections’ => [
        ‘staging’ => [
            ‘scm’ => [
                ‘branch’ => ‘staging’,
            ]
        ]
    ],
],

Он использует вложенный массив для переопределения значений конфигурации. Под staging ключом найдите соответствующий ключ в файле, который вы хотите изменить. В этом случае это branch в scm.php .

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

1
$ rocketeer check

Если все в порядке, вы можете развернуть, запустив:

1
$ rocketeer deploy

Поскольку это было ваше первое развертывание, Rocketeer позаботится о том, чтобы все было на высоте. Инструмент создает каталоги, в которых он нуждается, и наше приложение будет жить. Если все идет гладко, у вас должна быть полная сборка приложения на сервере.

Если вы изменили подключение по умолчанию на промежуточное в предыдущем разделе, оно всегда будет развертываться в промежуточное. Это, конечно, если вы не скажете, чтобы развернуть в другом месте. Если вы хотите выполнить развертывание на другом соединении или более чем на одном, вы используете ключ --on .

1
2
3
4
5
# Deploy to production
$ rocketeer deploy —on=»production»
 
# Deploy to staging and production
$ rocketeer deploy —on=»staging,production»

Хотите посмотреть, что произойдет на вашем сервере после нажатия кнопки? Используйте флаг --pretend чтобы инструмент сообщал вам, что он будет выполнять на сервере.

1
$ rocketeer deploy —pretend

К сожалению, мы должны позаботиться о развертываниях, которые нарушают функциональность или наносят ущерб инфраструктуре. Затем вам нужно сделать быстрый откат до последней версии. К счастью, это простая операция — просто запустите команду:

1
$ rocketeer rollback

Поскольку он хранит несколько сборок, откат выполняется быстро. Он изменяет символическую ссылку current версии на предыдущую.

Настроить общие каталоги просто — просто добавьте их в shared массив, находящийся в remote.php . Rocketeer создаст и свяжет эти папки для вас в развертываниях после. Указанные пути должны быть относительно вашей корневой папки.

1
2
3
4
5
6
‘shared’ => [
    ‘storage/logs’,
    ‘storage/sessions’,
    ‘storage/uploads’,
    ‘.env’,
],

Большинству общих каталогов также понадобится веб-сервер, чтобы иметь возможность писать в них. Запись журналов, сеансов или загрузок файлов часто является задачей, выполняемой любым приложением. Это вы добавляете в массив permissions.files в remote.php .

1
2
3
4
5
6
7
8
‘permissions’ => [
    ‘files’ => [
        ‘storage/sessions’,
        ‘storage/logs’,
        ‘storage/uploads’,
    ],
    // […]
],

Установка или обновление зависимостей — это то, что вам нужно, если приложение зависит от каких-либо зависимостей. Инструмент поставляется с поддержкой самых популярных менеджеров пакетов. Настройка чего-либо не требуется, если у вас есть настройки по умолчанию для них. Он будет обнаруживать и устанавливать или обновлять зависимости для Composer , Npm , Bower и Bundler . Стратегия по умолчанию для dependencies установлена ​​в Polyglot . Это инструмент, позволяющий обнаруживать и устанавливать зависимости для разных менеджеров пакетов.

Но допустим, что вы хотите установить все зависимости при подготовке, и инструмент по умолчанию использует флаг --no-dev . Возможно, вы хотите установить PHPUnit для запуска тестов, что является зависимостью при разработке. В strategies.php вы можете найти ключ composer , который сообщает инструменту, как выполнить Composer. Затем вы можете переопределить это в config.php :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
use Rocketeer\Binaries\PackageManagers\Composer;
 
// […]
 
‘on’ => [
    // […]
    ‘connections’ => [
        ‘staging’ => [
            ‘strategies’ => [
                ‘composer’ => [
                    ‘install’ => function (Composer $composer, $task) {
                        return $composer->install([], [‘—no-interaction’ => null, ‘—prefer-dist’ => null]);
                    }
                ],
            ],
        ]
    ],
],

Миграция баз данных часто является чем-то, что вы хотите сделать, когда у вас есть полный выпуск, непосредственно перед тем, как он будет символически ссылаться на текущий. Какой бы инструмент вы ни использовали, вы можете указать, чтобы он запускался до deploy.before-symlink . Этот крючок не обычный, а внутренний. Затем вам нужно зарегистрировать его где-нибудь еще, кроме hooks.php . Это можно сделать в events.php , который вы можете создать, если он еще не существует.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
use Rocketeer\Facades\Rocketeer;
 
// Laravel
Rocketeer::addTaskListeners(‘deploy’, ‘before-symlink’, function ($task) {
    $task->runForCurrentRelease(‘php artisan migrate’);
});
 
// Symfony2
Rocketeer::addTaskListeners(‘deploy’, ‘before-symlink’, function ($task) {
    $task->runForCurrentRelease(‘php app/console doctrine:migrations:migrate’);
});
 
// Stand-alone Doctrine
Rocketeer::addTaskListeners(‘deploy’, ‘before-symlink’, function ($task) {
    $task->runForCurrentRelease(‘doctrine migrations:migrate —no-interaction’);
});

Выполнение тестов в процессе развертывания — это отличный способ убедиться, что не сломанный код или тесты не проскользнули через трещины. По умолчанию инструмент использует PHPUnit, и вы можете подключить тестовый прогон для запуска после установки или обновления зависимостей.

1
2
3
4
5
6
‘after’ => [
    ‘setup’ => [],
    ‘deploy’ => [],
    ‘dependencies’ => [‘test’],
    ‘cleanup’ => [],
],

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

1
2
3
4
5
6
7
8
9
staging/0 |—- Test (Run the tests on the server and displays the output) fired by dependencies.after
staging/0 |—— Test/Phpunit (Run the tests with PHPUnit)
$ cd /var/www/my-deployable-app/releases/20160129220251$ /var/www/my-deployable-app/releases/20160129220251/vendor/bin/phpunit —stop-on-failure
[deploy@staging.mydeployableapp.com] (staging) PHPUnit 4.8.21 by Sebastian Bergmann and contributors.
[deploy@staging.mydeployableapp.com] (staging)
[deploy@staging.mydeployableapp.com] (staging) .
[deploy@staging.mydeployableapp.com] (staging) Time: 4.79 seconds, Memory: 6.00Mb
[deploy@staging.mydeployableapp.com] (staging) OK (1 test, 1 assertion)
[deploy@staging.mydeployableapp.com] (staging)staging/0 |=====> Tests passed successfully

Часто наши приложения являются не только серверной частью, если, например, они не являются REST API. Запуск инструментов сборки для нашего интерфейса — обычная задача для таких инструментов, как Grunt , Gulp или Webpack . Создание этой части нашего процесса развертывания — не что иное, как использование ловушки для запуска таких команд, как:

1
2
3
4
5
6
‘after’ => [
    ‘setup’ => [],
    ‘deploy’ => [],
    ‘dependencies’ => [‘gulp build’],
    ‘cleanup’ => [],
],

Внешний интерфейс также часто зависит от зависимостей, поэтому запускайте инструменты после их установки или обновления.

Если вы не хотите создавать новый выпуск при развертывании, вы можете запустить обновление. Будьте осторожны при этом, так как вы не сможете откатиться до предыдущей версии, только до предыдущей версии. Но это быстрый и простой способ обновления вашего приложения с последними изменениями с помощью:

1
$ rocketeer update

Иногда полезно запускать задачи в вашей локальной среде. Допустим, вы хотите выполнить проверку PHPCS или создать статические ресурсы и загрузить их на сервер, что устраняет необходимость в определенных двоичных файлах на сервере. Если вы создаете класс задачи, вы можете установить для защищенной переменной $local значение true .

1
2
3
4
5
6
class MyTask extends Rocketeer\Abstracts\AbstractTask
{
    protected $local = true;
 
    // […]
}

Процесс развертывания является важной частью жизненного цикла приложения. Такие инструменты, как Rocketeer, позволяют с легкостью сделать это простым делом. Это особенно верно при использовании его для приложения PHP, так как оно так хорошо интегрируется с ним.

Для тех из вас, кто только начинает работать с PHP или хочет расширить свои знания, сайт или приложение с помощью расширений, у нас есть множество вещей, которые вы можете изучить в Envato Market .

Написание вводного урока для Rocketeer оказалось сложной задачей. Инструмент настолько гибок, что нарисовать линии, где остановиться, не так просто. Я надеюсь, что я получил возможность использовать этот инструмент и узнать, как он может помочь вам и вашему приложению. Если вы хотите копать глубже, я предлагаю прочитать полную документацию . Это гораздо больше, чем то, что я мог бы рассказать в этой статье.