Phing - деплой проекта на продакшен в 1 клик
Время от времени, как это ни странно, приходится деплоить проект на продакшен. И всё чаще и чаще приходит мысль о том, что ведь можно же как-то упростить этот процесс буквально до нажатия одной кнопки.
Как показывает практика google, есть множество инструментов для автоматического деплоя проекта и автоматизации иных процессов, связанных с последним, но наиболее удобным для проектов, написанных на PHP, по моему мнению, является Phing. Разберём на примере вариант его использования для автоматического деплоя проекта на удалённый web-сервер.
В двух словах, что такое Phing - это 1 раз запущенная команда composer require
и довольно понятный XML-файл конфигурации. В общем-то, это всё, что минимально необходимо знать про него :)
Установка Phing
Установка Phing возможна как глобально через mv phing.phar /usr/sbin/phing
, так и в каждый проект отдельно. Я предпочитаю добавлять его в composer.json проекта:
{
"require-dev": {
"phing/phing": "2.*"
}
}
После этого в папке vendor проекта появится подпапка phing, в которой среди прочих файлов будет находиться исполняемый файл vendor/phing/phing/bin/phing
Небольшая предыстория
Некоторые исходные данные для нашей задачи:
- проект на php (не принципиально, но будет учтено в дальнейшем)
- проект на git
- разработка ведётся по gitflow, всё тестируется на dev/stage хостах (не принципиально) и только потом выкатывается на продакшен
- разработка ведётся в PHPStorm IDE (не принципиально)
- production на удалённом сервере, к которому есть доступ по SSH
Если бы деплой сводился к банальной команде git pull
, то вопросов бы особых не возникало, я думаю. Но ведь обычно ещё нужно скинуть файловый кеш как минимум twig'а, скинуть кеш статики, кеш доктриры, сделать composer dumpautoload
и т.д., и т.п.
Предположим, что наступил тот момент, когда очередная задача была успешно выполнена, feature-ветка была влита в релизную, та, в свою очередь, проверена, и в итоге было получено добро на релиз. Предполагается, что всё это делается в PHPStorm'е через удобное меню gitflow на панели инструментов, поэтому особо заострять на этом внимание не будем.
Также был успешно сделан Finish release, все изменения попали в master/develop ветки, после чего был сделан git push
и изменения благополучно улетели в remote-репозиторий.
И вот тут-то вступает в игру Phing!
Прежде, чем мы начнём
Следует убедиться, что плагин Phing корректно установлен и настроен в PHPStorm, вот тут есть официальня документация. Если кратко, то для этого достаточно немного потыкать мышкой в экран:
Пункт 3 на скрине не обязателен, если ранее вы уже установили в проект Phing через composer install
Также обязательно должен быть установлен пакет php-ssh2 (например, для mac такой пакет устанавливается как brew install php70-ssh2
)
Первые шаги
Теперь создадим в корне проекта файл phing.xml вот примерно с таким содержанием:
<?xml version="1.0" encoding="UTF-8"?>
<project name="MyProject" basedir="/" default="info">
<property name="HOST" value="192.168.100.200"/>
<property name="PORT" value="12345"/>
<property name="USER.NAME" value="username"/>
<property name="DIR" value="/home/www/domain.com/httpdocs"/>
<!-- Info -->
<target name="info">
<echo>
Hello, bro!
You should specify parameter (what you want me to do for you) to run me :)
Try these:
- deploy:prod - deploy to production
- deploy:test - deploy to test
- deploy:stage - deploy to stage
</echo>
</target>
<!-- Pre-request -->
<target name="pre-request">
<propertyprompt propertyName="USER.PASSWORD" promptText="Введите пароль" defaultValue="" />
<ssh
host="${HOST}"
port="${PORT}"
username="${USER.NAME}"
password="${USER.PASSWORD}"
command="echo 'Current branches:' && cd ${DIR} && echo '- - - - - - - - - -' && git branch -a echo '- - - - - - - - - -'"
display="true"
/>
<propertyprompt propertyName="BRANCH" promptText="Введите ветку" defaultValue="" />
</target>
<!-- Production -->
<target name="deploy:prod" depends="pre-request">
<ssh
host="${HOST}"
port="${PORT}"
username="${USER.NAME}"
password="${USER.PASSWORD}"
command="cd ${DIR} && ./update.sh ${BRANCH}"
/>
<echo>Done!</echo>
</target>
</project>
По идее сам «шторм» сразу же предложит ассоциировать этот файл с Phing-плагином, о чём вы увидите соответствующее уведомление. Но если этого не произошло, то просто кликните на этом файле правой кнопкой мыши и в контекстном меню выберите Add as Phing build file (скорее всего будет в самом низу списка). После этого появится соответствующий Tool Window:
На скрине виден список всех доступных «целей», которые можно запускать нажатием как раз всего одной кнопки :) Но давайте немного подробнее разберём, что же это за «цели» (target).
Структура файла
1. Корневой тег <project> - тут мы указываем название нашего проекта, базовую дирректорию и то задание (target), которое должно быть выполнено по-умолчанию, если не указано иного. Благодаря интеграции с PHPStorm можно спокойно пользоваться автодополнением при написании атрибутов, все они более, чем понятны (ну, например, ещё есть атрибут description - даже в документацию не надо лезть, чтобы понять, для чего он нужен ;)
2. Далее мы описываем нужные «свойства» (или, по сути, переменные) , все они понятны, опять же) Есть множество встроенных «свойств», для остальных же названия нужно придумывать самостоятельно.
3. Затем описывается тег <target> - это конкретное задание, которое мы хотим выполнить (например, деплой проекта на test/stage/production), среди прочих атрибутов указываются имя name="info"
задания. name для своего задания вы придумываете сами)
4. <target name="info">
- это задание, суть которого просто вывести информацию на экран пользователя.
5. <target name="pre-request">
- это задание, которое выполняется перед «основным» заданием. Чтобы не плодить copy/paste в разных target'ах, рекомендую общие части вынести вот в такой pre-request. В данном случае мы сначала запрашиваем пароль, следующая инструкция (подробнее о ней ниже) выведет нам на экран список доступных git-веток, затем просим указать ветку, из которой надо выкатить изменения на продакшен.
6. <target name="deploy:prod" depends="pre-request">
- это «задание» как раз и делает деплой на продакшен. Оно зависит от pre-request, что указано в атрибуте depends="pre-request" и содержит всего одну команду .
7. <ssh ... />
- эта инструкция, как не трудно догадаться, фактически коннектит по ssh на удалённый сервер и выполняет там нужную нам команду, а точнее запускает один единственный скрипт update.sh, который может выглядеть примерно вот так:
#!/bin/sh
# Определяем текущего пользователя, запустившего скрипт
CU=`whoami`
# Если это "нужный" пользователь
if [ "$CU" = "username" ] ; then
# Удалим "лишние" ветки
/bin/git remote prune origin
# Определяем текущую ветку
CURRENT_BRANCH="$(git symbolic-ref HEAD 2>/dev/null)" || CURRENT_BRANCH="(unnamed branch)"
CURRENT_BRANCH=${CURRENT_BRANCH##refs/heads/}
echo " - current branch: $CURRENT_BRANCH"
# Определяем новую ветку, которую нужно выкатить
NEW_BRANCH="$1"
if [ "$NEW_BRANCH" = "" ] ; then
NEW_BRANCH=$CURRENT_BRANCH
fi;
# Делаем чекаут и пулл
git checkout -b $NEW_BRANCH origin/$NEW_BRANCH
git pull
# ну и при необходимости запускаем любые дополнительные процедуры, например:
npm install
grunt production > /dev/null 2>&1
composer install
rm -rf ./tmp/cache/*
# перезапускаем memcache, nginx, php-fpm и так далее... что только душе угодно :)
fi;
Что в итоге
Весь деплой сводится к тому, чтобы просто нажать на «зелёный треугольник» в соответствующем Tool Window и указать пароль (который можно прописать в xml'ке, если не боитесь, что он «уйдёт» в чужие руки).