Статьи

Идиот-Доказательство Развертывания PHP с Phing

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

Давным-давно, давным-давно, я впервые вышел на сцену конференции и сказал, что, по-моему, я самый крутой PHP-разработчик в мире. Я на самом деле все еще думаю, что это довольно верно, и если вы будете работать со мной, вы поймете, что я в основном ломаю и чиню вещи примерно в равной степени. Имея это в виду, когда я недавно запустил свой собственный продукт (
BiteStatsвещь, которая автоматически отправляет вам сводку статистики аналитики каждый месяц), я знал, что мне нужен действительно надежный способ развертывания кода. В течение нескольких лет я делал несколько разных вещей, и я часто внедрял эти инструменты с другими организациями или для них, но у меня не так много странного кода в производстве, странно. Я решил, что Phing — это путь, установил его и решил
, что делать дальше.

build.xml

Я создал файл build.xml в корневом каталоге моего проекта, и изначально он содержал только следующее:

<?xml version="1.0" encoding="UTF-8"?>
<project name="bitestats" basedir="." default="deploy">
    <property name="builddir" value="./build" />

</project>

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

Задачи

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

<?xml version="1.0" encoding="UTF-8"?>
<project name="bitestats" basedir="." default="deploy">
    <property name="builddir" value="./build" />

    <target name="clean">
            <echo msg="Clean..." />
            <delete dir="${builddir}" />
    </target>

    <target name="prepare">
            <echo msg="Prepare..." />
            <mkdir dir="${builddir}" />
    </target>

</project>

Чтобы запустить задачи, вы просто делаете
Phing prepare или
Phing Clean соответственно.

Реальные задачи развертывания

Для запуска самого развертывания у меня есть задание по умолчанию, которое вы объявили в первом фрагменте, развернуть. Определение задачи выглядит так:

<target name="deploy">
      <echo msg="Next Tag ..." />
      <exec command="echo $(($(hg tags | egrep -o '^deploy\-([0-9]*) ' | egrep -o '[0-9]* ' | sort -nr | head -n 1) + 1))" outputProperty="nextTag" />
      <echo msg="... is ${nextTag}.  Tagging ..." />
      <exec command="hg tag deploy-${nextTag}" />
      <echo msg="Grab code ..." />
      <exec command="hg archive -r deploy-${nextTag} build/deploy-${nextTag}" />
      <echo msg="Zip code ..." />
      <exec command="tar zcf deploy-${nextTag}.tgz deploy-${nextTag}"
dir="build" />

      <!-- copy to live -->
      <echo msg="Put code onto live server ..." />
      <exec command="scp -i /path/to/ssh/key build/deploy-${nextTag}.tgz apache@server.example.com:/path/to/bitestats/htdocs/" />
      <!-- make live-->
      <exec command="ssh -i /path/to/ssh/key apache@server.example.com 'cd bitestats/htdocs && tar -zxf deploy-${nextTag}.tgz && ln -s deploy-${nextTag} next && ln -s /usr/local/Zend/ZendFramework-1.11.2-minimal/library/Zend/ public/library/Zend && php -f public/cli.php -- -a updatedbpatch && mv -fT next public'" logoutput="yes"/>
      <exec command="ssh lorna@server.example.com 'supervisorctl restart worker'" logoutput="yes"/>

  </target>

Краткий обзор того, что на самом деле происходит здесь:

  1. Мы выясняем, каким будет следующий тег, и помечаем кодовую базу. Я использую Mercurial для контроля исходного кода и размещаю свой код в частном репозитории на BitBucket
  2. Мы используем hg archive, который в основном похож на экспорт SVN, чтобы получить соответствующую версию кода, а затем tar и заархивировать ее.
  3. Код передается на сервер пользователем apache
  4. На удаленном сервере еще несколько команд запускаются сразу. Во-первых, код распакован
  5. Создается символическая ссылка «next», которая указывает на новую папку (я уже писал в блоге о моей стратегии символических ссылок, если вам интересно)
  6. Создается символическая ссылка на код библиотеки, в данном случае ZF, но вы также создадите символические ссылки на файлы конфигурации, каталоги загрузки / кэширования и все остальное, что необходимо на этом этапе.
  7. На этом этапе запускаются все необходимые исправления базы данных (опять же, я написал этот скрипт в блоге на тот случай, если вы захотите его увидеть)
  8. Мы переключаем символическую ссылку, чтобы новый контент работал
  9. Наконец, мы останавливаемся и запускаем работника gearman, чтобы он собирал новый код (один работник, все на одном сервере, на этом сайте действительно не так много нагрузки!). Мои процессы контролера контролируются супервизором , но он отвечает только моему пользователю. На самом деле он запрашивает у меня пароль

Наличие процесса развертывания

Весь процесс занимает несколько секунд, и пока он работает как шарм. Я очень доволен этим и очень рад, что нашел время, чтобы поставить это на место. Каждый раз, когда я выполняю развертывание, я чувствую себя немного самодовольным 🙂 Я знаю, что может быть сложно настроить компоненты развертывания, в конце концов, мы можем довольно легко выполнить все отдельные шаги, и у каждого есть множество других вещей, о которых нужно беспокоиться — но я думаю, это важно, и хотя «правильное» решение будет отличаться для каждого приложения и платформы, я хотел бы поделиться тем, что работает для меня. Что работает для вас? Оставьте мне комментарий!