разработка мобильных приложений, веб-сервисов и корпоративных систем
ru en
+7 (812) 324-27-24, +7 (495) 641-87-24
Заказать звонок

Система развертывания

Хочу рассказать вам о системе развертывания, используемой в таких замечательных проектах как http://e-shtab.ru и http://goozzy.com

Система самописная, достаточно тесно связана с процессом разработки и реализована при помощи sh-скрипта.

Общая схема

Система развертывания, deploy, django, sh, mysql, python.

На рисунке приведена немного сумбурная схема процесса развертывания.

Разработка ведется с использованием SVN установленным на локальном сервере, там же расположен и локальный сервер MySQL. MySQL используется всеми при разработке, структура создается через initdb. Начальные данные в обязательном порядке (скоро узнаете почему) сохраняются либо в fixtures, либо в init.sql, а в случае прав пользователей создается команда manage.py.

После каждого коммита автоматически запускается скрипт развертывания на DEV версию проекта. При этом исходный код на сервере обновляется (или загружается если проекта не существует), а структура базы обновляется при помощи замечательного mysqldiff. На схеме этот процесс помечен цифрой 1.

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

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

Когда проект готов для тестирования, менеджер проекта запускает (по ssh;) развертывание на TEST он же помечен цифрой 2 на схеме. Структура база данных переносится из DEV версии.

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

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

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

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

PROD версия проекта — инструмент пользователей. Используется интернет пользователями по назначению. (например для связи бизнеса и СМИ).

Обновляется по запросу, после окончания тестирования.

Публичная версия обновляется исключительно с TEST версии, копированием файлов и структуры базы. Это с одной стороны дает гарантию что мы запустим именно тот код который был оттестирован, с другой подразумевает что любые изменения должны быть проверены (задеплоиться с DEV или репозитория нельзя).

Расскажу об одном интересном моменте, почему при деплое не теряются пользовательские данные. Дело в том, что mysqldiff генерирует ALTER срипт, который изменяет лишь структуру БД, но не трогает сами данные. Файлы загруженные пользователями хранятся в отдельном месте и подключаются в структуру проекта с помощью символической ссылки. Таким образом мы имеем три независимых версии со своими данными в базе и загруженными файлами.

Конфигурация системы

Система планировалась более-менее универсальной, поэтому у каждого проекта есть опции развертывания, которые должны храниться в файле deploy/params.sh. Основные параметры:

  • Параметры SVN репозитория, для скачивания и обновления исходного кода.
  • Параметры MySQL сервера, который используется для переноса изменений структуры на DEV.
  • Имя конечного конфигурационного файла, который формируется из шаблона для каждой версии проекта.
  • Путь к media и загружаемым файлам пользователя.
  • Базовые порты FCGI и SPHINX.
  • Команда выполняемая сразу после деплоя (обычно команда инициализации прав пользователей).

Параметры представлены как переменные и добавляются с помощью включения скрипта.

MySQL

С базой при деплое все достаточно просто, если её не существует, скрипт запускает создание базы manage.py initdb, Django загружает fixtures, скрипт запускает init.sql и в конце выполняет прописанную в конфиге команду. Огромное разнообразие методов начальной загрузки данных удовлетворяет любые даже самые сложные случаи.

Например, в свое время мы столкнулись со сложностью распределения прав пользователей по группам. На уровне fixtures или init.sql ну никак не получалось этого сделать, из-за того что на разных версиях проекта, созданные initdb права, имеют разные id. В итоге и появилась команда выполняемая в конце развертывания, которая используя стандартные методы Django, формирует необходимые группы пользоватей и распределяет права доступа.

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

Если база данных уже создана, то при развертывании переносится только структура с помощью mysqldiff. Этот скрипт делает экспорт структуры двух баз данных (откуда и куда переносим), сравнивает эти данные и формирует sql скрипт для обновления целевой базы. Скрипт уже стандартными средствами СУБД применяется к базе. Причем при деплое на PROD, скрипт просматривается вручную, дабы в случае сбоя не удалить пользовательские данные.

Конфигурационные файлы

Одна из моих любимых функций нашей системы — генерация конфигурационных файлов.

Конфиг разработчиков хранится в отдельном файле base_settings.py а в стандартном settings.py всего одна строчка включения базовых настроек from base_settings.py import *.

Для настроек применяемых на хостинге создается специальный шаблон настроек template_settings.py в котором переопределяются нужные настройки из base_settings.py, причем следуя принципу DRY шаблонный файл всего один для всех трех версий системы.

Поведение специфичное для конкретной версии (имена баз данных, например, у всех разные) поддерживается макро-язык суть которого в замене конструкции {имя версии: значение} на значение. Допустим строка

DATABASE_NAME={dev:eshtab_dev}{test:eshtab_test}{prod:eshtab}

при развертывании на TEST будет исправлена на DATABASE_NAME = eshtab_test.

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

{instance}
DEV, TEST или PROD — версия системы.
{dbname}
имя базы данных.
{sitepath}
путь к файлам проекта.
{domain}
базовый адрес версии проектам (например dev.eshtab.ru).
{fcgi_port}
FCGI порт, используется как Django так и NGINX.
{sphinx_port}
порт поискового движка, используемого на наших проектах.
{media_path}
путь к статическим файлам.

Подстановки изумительны с точки зрения DRY, они используются как в Django так и в конфигурационных файлах SPHINX, NGINX, так и в скриптах запуска.

Макро-замены и подстановки осуществляются потоковым текстовым редактором sed. После замен settings.py заменяется шаблоном.

SPHINX, NGINX

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

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

{dev:#}{test:#}    server {
{dev:#}{test:#} listen 80;
{dev:#}{test:#} server_name .{domain};
{dev:#}{test:#} rewrite ^/(.*) http://www.{domain}/$1 permanent;
{dev:#}{test:#}
}

Как вы наверно догадались на DEV и TEST эти строки будут закомментированы, а на PROD веб-сервер будет переадресовывать запросы с domain на www.domain из эстетических соображений.

На правах заключения

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

Добавить комментарий