Эта статья посвящена техническим сторонам командной разработки проектов на Друпал 6.
Я занимаюсь разработкой проектов на Drupal 6 чуть менее двух лет. Большой ли это срок? Если считать, что выполнено порядка 20 мелких проектов и пяток крупных и высокопосещаемых, на мой взгляд, срок большой. Ругать эту CMS (систему управления контентом) — грех (особенно на Хабре). Но об одной проблеме, с которой я столкнулся и местами даже удачно решил для себя, все же хочу рассказать. Я многократно поднимал вопрос командной разработки проектов на собрании друпаллеров: в Москве, в Киеве. Готового и стабильного решения в то время я не нашел.
Описанные здесь технологии предполагают работу Drupal 6 на Linux Ubuntu 10.04, с веб сервером Apache на dev-серверах и веб-сервером nginx на «боевом», в качестве БД используется MySQL. Так же, в эпизодах участвуют cron, rsync, migraine, SVN.
It-специалисты делятся на две категории: те кто уже делает бекапы и те, кто еще не делает. В нашем случае стоит написать простой скрипт и настроить запуск по расписанию, дважды в сутки: утром и в середине рабочего дня. Для этого я использую cron. Скрипт должен накапливать копии. То есть, новый бекап не должен перезаписывать предыдущий. Кроме того, должна быть возможность запустить этот скрипт не только из cron, но и по требованию, в моем случае из консоли. Очевидно, что копии должны храниться не на той же машине, что и файлы проекта. Не надо класть все свои яйца в одну корзину.
Мой скриптец для создания бекапа выглядит так:
Директория back-ups должна существовать и иметь права записи для пользователя, от которого запускается cron.
Скрипт запускается по событию cron дважды в сутки.
Пока проект прост и разработка находится в одних руках — все замечательно: быстро, гибко, управляемо. Как только начинается проект посложнее, в разработку включается еще несколько программистов, начинается проблема синхронизации изменений.
Как вести распределенную разработку? Сейчас я намеренно упускаю из виду дизайнеров, верстальщиков. Их работа незначительно коррелирует с работой программистов, а на поздних стадиях так и вообще практически исключается.
С кодом модулей и графической темы все понятно: ставим систему контроля версий (она же хранилище). В качестве хранилища я использую SVN. Каждому разработчику даём по веб-серверу (традиционно — виртуальному). Однако, специфика Друпала в том, что он хранит практически все свои настройки в базе данных (разве что settings.php лежит на файловой системе).
Как быть с базой данных? Как синхронизировать изменения нескольких разработчиков? Первое, что приходит на ум: использовать общую базу данных. Хорошее решение, но до поры, до времени, пока один из разработчиков не установит к себе код модуля, но в хранилище (SVN) еще не выложит. Модуль пропишется в общую базу, а код еще есть не у всех, потому что работа над настройкой еще не окончена. Эксперименты на общей базе данных могут принести много мусора, от которого тяжело будет избавиться.
Для этого случая я использую половинчатое решение: каждый разработчик имеет два веб-сервера:
"Локальная связка" используется для экспериментов, проверки и тестирования разнообразных решений. Вот тут и пригодятся бекапы: разработчик берет бекап, разворачивает на «локальной связке», проводит эксперименты по установке и настройке модуля, разрабатывает свой код, тестирует. После того, как решение проверено и устраивает, оно выкатывается вручную на dev-сервер, проверяется еще раз и выкладывается в хранилище.
"Сетевая связка" — общий полигон для рутинной работы.
Щекотливая ситуация наблюдается, когда обедненная версия проекта выкладывается в Мир, пользователи начинают с ней работать и создают огромное количество разнообразного контента.
С другой же стороны, на dev-серверах продолжает идти работа по наращиванию функционала и разработчики плодят изменения в огромных масштабах. Периодически необходимо все это синхронизировать: с «боевого» брать контент, с dev-серверов — логику и новый функционал. Простое зеркалирование здесь не подойдет. Мало того, «боевой» и dev скорее всего находятся на разных физических серверах и, вероятнее всего, по причинам безопасности, доступ к ним возможен лишь через ssh. Тут нам поможет rsync + migraine.
Rsync отвечает за синхронизацию файлов. Скрипт кидает файлы проекта с dev-сервера на «боевой» и пользовательские файлы с «боевого» на dev-сервер.
Скрипт выглядит вот так:
Ключи
Migraine — скрипт, писанный на python, отвечает за хитрую синхронизацию базы данных. Я запускаю его вот таким скриптом:
Настройки доступов к базам данных хранятся в migraine.ini
Что делает migraine в моей конфигурации?
Следует отметить, что первоначально migraine разрабатывался для Drupal 5. Полной адаптации под Drupal 6 я не нашел. Нашел лишь частное решение, которое чуток подпилил под себя. Так как решение было адаптировано, то пилить пришлось не напильником, а надфилем. Скрипт могу выложить по требованию.
Моя конфигурация проекта (ядро + модули) предполагает порядка 120 таблиц. Какие куда относятся — это отдельная тема для обсуждения. Тут надо включать свой мозг.
При работе, migraine должен иметь доступ сразу к двум базам данных. Как быть, если базы данных находятся на разных хостах? Подключаем базу с «боевого» при помощи ssh-туннеля. При этом, вешаем его на другой порт, например, на 3307:
База данных dev-сервера при этом висит на порту 3306. Migraine не умеет работать с портами, поэтому пришлось его чуток подпилить.
Проверить, что удаленная база удачно подключилась можно командой:
Результат должен выглядеть примерно вот так:
Пожалуй всё.
С удовольствием выслушаю критику данных методов и, возможно, у кого-то есть своё решение этих проблем.
Обсуждаемые проблемы:
- синхронизация изменений в базе данных результата работы нескольких разработчиков;
- рассмотрена работа (и доработка) скрипта migraine для Drupal 6;
- рассмотрена синхронизация изменений между dev-сервером и «боевым».
Введение
Я занимаюсь разработкой проектов на Drupal 6 чуть менее двух лет. Большой ли это срок? Если считать, что выполнено порядка 20 мелких проектов и пяток крупных и высокопосещаемых, на мой взгляд, срок большой. Ругать эту CMS (систему управления контентом) — грех (особенно на Хабре). Но об одной проблеме, с которой я столкнулся и местами даже удачно решил для себя, все же хочу рассказать. Я многократно поднимал вопрос командной разработки проектов на собрании друпаллеров: в Москве, в Киеве. Готового и стабильного решения в то время я не нашел.
Описанные здесь технологии предполагают работу Drupal 6 на Linux Ubuntu 10.04, с веб сервером Apache на dev-серверах и веб-сервером nginx на «боевом», в качестве БД используется MySQL. Так же, в эпизодах участвуют cron, rsync, migraine, SVN.
Резервные копии!
It-специалисты делятся на две категории: те кто уже делает бекапы и те, кто еще не делает. В нашем случае стоит написать простой скрипт и настроить запуск по расписанию, дважды в сутки: утром и в середине рабочего дня. Для этого я использую cron. Скрипт должен накапливать копии. То есть, новый бекап не должен перезаписывать предыдущий. Кроме того, должна быть возможность запустить этот скрипт не только из cron, но и по требованию, в моем случае из консоли. Очевидно, что копии должны храниться не на той же машине, что и файлы проекта. Не надо класть все свои яйца в одну корзину.
Мой скриптец для создания бекапа выглядит так:
#!/bin/sh
cd /sites/projectX.ru/
DATE=`date +%d.%m.%Y-%H.%M`
mkdir back-up
mysqldump -u user_name -pdb_password db_name -h db_host > ./back-up/db_site_common.sql
cp -R ./www/ ./back-up/www
tar -czf ./back-ups/projectX.ru-$DATE.tar.gz ./back-up
chmod -R 0777 ./back-up/
rm -rf ./back-up
Директория back-ups должна существовать и иметь права записи для пользователя, от которого запускается cron.
Скрипт запускается по событию cron дважды в сутки.
Несколько разработчиков
Пока проект прост и разработка находится в одних руках — все замечательно: быстро, гибко, управляемо. Как только начинается проект посложнее, в разработку включается еще несколько программистов, начинается проблема синхронизации изменений.
Как вести распределенную разработку? Сейчас я намеренно упускаю из виду дизайнеров, верстальщиков. Их работа незначительно коррелирует с работой программистов, а на поздних стадиях так и вообще практически исключается.
С кодом модулей и графической темы все понятно: ставим систему контроля версий (она же хранилище). В качестве хранилища я использую SVN. Каждому разработчику даём по веб-серверу (традиционно — виртуальному). Однако, специфика Друпала в том, что он хранит практически все свои настройки в базе данных (разве что settings.php лежит на файловой системе).
Как быть с базой данных? Как синхронизировать изменения нескольких разработчиков? Первое, что приходит на ум: использовать общую базу данных. Хорошее решение, но до поры, до времени, пока один из разработчиков не установит к себе код модуля, но в хранилище (SVN) еще не выложит. Модуль пропишется в общую базу, а код еще есть не у всех, потому что работа над настройкой еще не окончена. Эксперименты на общей базе данных могут принести много мусора, от которого тяжело будет избавиться.
Для этого случая я использую половинчатое решение: каждый разработчик имеет два веб-сервера:
- «локальная связка» — локальный веб-сервер со своей базой данных;
- «сетевая связка» — свой веб-сервер на dev-сервере с общей, «рабочей» базой данных.
"Локальная связка" используется для экспериментов, проверки и тестирования разнообразных решений. Вот тут и пригодятся бекапы: разработчик берет бекап, разворачивает на «локальной связке», проводит эксперименты по установке и настройке модуля, разрабатывает свой код, тестирует. После того, как решение проверено и устраивает, оно выкатывается вручную на dev-сервер, проверяется еще раз и выкладывается в хранилище.
"Сетевая связка" — общий полигон для рутинной работы.
Несколько серверов
Щекотливая ситуация наблюдается, когда обедненная версия проекта выкладывается в Мир, пользователи начинают с ней работать и создают огромное количество разнообразного контента.
С другой же стороны, на dev-серверах продолжает идти работа по наращиванию функционала и разработчики плодят изменения в огромных масштабах. Периодически необходимо все это синхронизировать: с «боевого» брать контент, с dev-серверов — логику и новый функционал. Простое зеркалирование здесь не подойдет. Мало того, «боевой» и dev скорее всего находятся на разных физических серверах и, вероятнее всего, по причинам безопасности, доступ к ним возможен лишь через ssh. Тут нам поможет rsync + migraine.
Rsync отвечает за синхронизацию файлов. Скрипт кидает файлы проекта с dev-сервера на «боевой» и пользовательские файлы с «боевого» на dev-сервер.
Скрипт выглядит вот так:
#!/bin/sh
rsync -aP --exclude=/usr/local/www/site/fast/projectX.ru/sites/default/settings.php \
--exclude=.svn /sites/projectX.ru/www/ ssh_user_name@prod_server_name:/home/_site/projectX.ru/
Ключи
--exclude
указывают, какие файлы не участвуют в синхронизации.Migraine — скрипт, писанный на python, отвечает за хитрую синхронизацию базы данных. Я запускаю его вот таким скриптом:
#!/bin/sh
python migraine-d6.py --dump-test --config=migraine.ini
python migraine-d6.py --migrate-to-prod --config=migraine.ini
python migraine-d6.py --dump-prod --config=migraine.ini
python migraine-d6.py --migrate-to-test --config=migraine.ini
Настройки доступов к базам данных хранятся в migraine.ini
Все таблицы Друпала migraine делит на пять типов:
- config_tables — таблицы с настройками: список таблиц через пробел, которые полетят с dev-сервера на «боевой»;
- content_tables — таблицы с контентом: список таблиц, которые полетят с «боевого» на «dev-сервер»;
- temp_tables — временные таблицы: список таблиц, которые очищаются. Не копируются;
- cache_tables — таблицы кэша. Должны быть очищены;
- ignore_tables — таблицы, которые нужно игнорировать.
Что делает migraine в моей конфигурации?
- Делает бекапы как таблиц dev-сервера, так и «боевого»;
- закидывает все таблицы с настройками на «боевой», а таблицы с контентом на «dev-сервер».
Следует отметить, что первоначально migraine разрабатывался для Drupal 5. Полной адаптации под Drupal 6 я не нашел. Нашел лишь частное решение, которое чуток подпилил под себя. Так как решение было адаптировано, то пилить пришлось не напильником, а надфилем. Скрипт могу выложить по требованию.
Моя конфигурация проекта (ядро + модули) предполагает порядка 120 таблиц. Какие куда относятся — это отдельная тема для обсуждения. Тут надо включать свой мозг.
При работе, migraine должен иметь доступ сразу к двум базам данных. Как быть, если базы данных находятся на разных хостах? Подключаем базу с «боевого» при помощи ssh-туннеля. При этом, вешаем его на другой порт, например, на 3307:
#!/bin/sh
ssh -C -L3307:localhost:3306 prod_user_name@projectX.ru
База данных dev-сервера при этом висит на порту 3306. Migraine не умеет работать с портами, поэтому пришлось его чуток подпилить.
Проверить, что удаленная база удачно подключилась можно командой:
netstat -an | grep LISTEN
Результат должен выглядеть примерно вот так:
tcp 0 0 127.0.0.1:3307 0.0.0.0:* LISTEN
Проблемы синхронизации
- Различные настройки Drupal-кэширования на «боевом» и dev-сервере. Решение: либо каждый раз после синхронизации устанавливать ручками, либо автоматизировать при помощи curl. То есть, из командной строки зайти в админку, зайти на страницу настройки производительности и проставить нужные «галки», сохранить форму. Первый вариант непреемлем, когда-нибудь забудем включить кэш и долго будем сокрушаться, кто же тааак грузит «боевой» сервер. Человеческий фактор неизбежен. Второй вариант — лучше, но нетривиален, есть свои подводные камни. Опишу по запросу.
- Различные настройки settings.php на разных серверах. Решение — кладем «боевой» settings.php в определенное место и добавляем в скрипт синхронизации строчку подмены конфигурационного файла. Либо при помощи ключа --exclude говорим rsync'у, что этот файл перезатирать не надо.
- Таблиц в друпале очень много и не удается до конца понять, в какую категорию отнести. Как в анекдоте с мартышкой: «А мне разорваться что — ли?» Так и хочется поступить с некоторыми таблицами. Тут надо действовать хитрее.
- Таблицы смешанного типа. Migraine позволяет разделить таблицы на настроечные и контентные. Настроечные те, которые с dev-сервера копируются на «боевой», контентные — таблицы с контентом, копируются с «боевого» на dev-сервера. Однако, тут снова не все так просто. Например, настройки модуля webform хранятся (тесно связаны) в контентных таблицах.
Пожалуй всё.
С удовольствием выслушаю критику данных методов и, возможно, у кого-то есть своё решение этих проблем.