Настраивать VDS'ки для выкладки django-проектов довольно утомительно бывает, да и легко что-то забыть (т.к. делаешь это не каждый день). Гораздо лучше, когда этот процесс автоматизирован: с меньшими усилиями можно получить правильно настроенный проект и набор команд для работы с ним.
Существую разные подходы к этому процессу: специфичные для питона (fabric, buildout) или неспецифичные (puppet, Chef, наборы shell-скриптов и т.д.).
Подход fabric — локально выполняемый скрипт ходит по ssh на сервер и выполняет там команды. Этот подход довольно прямолинеен и прост в отладке, тем и хорош (обзор на хабре). Из разнообразных команд fabric постепенно вырисовался велосипед под названием django-fab-deploy. Это набор fabric-скриптов, который умеет настраивать серверы под Debian Lenny или Squeeze, а потом с минимальными усилиями разворачивать там django-проекты и управлять этими проектами в дальнейшем.
С выходом Debian Squeeze взялся за django-fab-deploy посерьезнее, поправил некоторые шероховатости и теперь, думаю, самое время об этом проекте рассказать. У проекта есть документация, тут будет краткий пересказ с лирическими отступлениями.
Общие принципы:
Серверная часть:
Главными критериями для выбора способа развертывания были стабильность/надежность, и тут связке apache+mod_wsgi+nginx на данный момент равных нет. Думаю, поддержку убунты добавить будет не сложно, но чего об этом говорить-то, раз поддержки убунты прямо сейчас нет (сам убунтой не пользуюсь).
Проекту хорошо бы хранится в системе контроля версий (сейчас поддерживается mercurial). Имеется полузаглушка с загрузкой/распаковкой tar.gz на случай, если проект не в VCS; она работает, но в продакшн-режиме я ее не проверял (незачем было), и есть вероятность, что проявятся какие-нибудь особенности.
Ниже описан базовый способ развертывания сервера, если он по каким-то причинам не подходит, то не страшно: django-fab-deploy — просто набор скриптов; их можно использовать по частям, или какие-нибудь полезности подсмотреть, или отправить патч, или просто статью почитать.
Предполагается, что у нас есть чистый Debian-сервер (можно и не «чистый», об этом позже), настроен ssh-доступ по публичному ключу к root.
Пожалуйста, не используйте VPS на OpenVZ, т.к. на них ограничивается VIRT вместо RSS и поэтому куча софта (в том числе апач и mysql+innodb) под OpenVZ ест гораздо больше памяти, чем под xen/kvm (в 10 раз — да легко).
Джанго-проекты и так часто используют какую-нибудь разновидность трюка с 'local_settings.py', лежат в системе контроля версий, в репозитории имеют файлик с pip-зависимостями и папку с настройками для веб-сервера. Ничего кроме этого django-fab-deploy, по сути, и не требует. Дальше — детали.
1. Устанавливаем django-fab-deploy и его зависимости:
django-fab-deploy не работает с Fabric 0.9.x, Fabric должен быть установлен с github'а.
2. Создаем файл fabfile.py в корне проекта. В этом файле должна быть одна или несколько функций, настраивающих параметры сервера. Ну и т.к. это обычный fabric-скрипт, там могут быть любые другие (специфичные для проекта) команды. Пример:
Обратите внимание на env.hosts. Тут есть фишка: укажите в качестве пользователя (my_site) название своего проекта (оно должно быть правильным названием переменной в python — без тире и пробелов). Не страшно, если такого пользователя нет, django-fab-deploy сможет его создать и настроить ssh-доступ позже. В любом случае, иметь отдельного пользователя для каждого проекта — хорошая идея.
В env.conf применяются некоторые соглашения для упрощения всего. Например, название БД (DB_NAME) по умолчанию совпадает с названием экземпляра проекта (INSTANCE_NAME), которое, в свою очередь, совпадает с пользователем из env.hosts.
Чтобы узнать больше о том, что и как можно настраивать тут, см. документацию по fabfile api.
3. Создадим шаблоны настроек для веб-сервера и т.д.:
Появится папка config_templates в корне проекта, там лежат шаблоны настроек. Проекты бывают разные, и часто настройкам потребуются правки — как минимум бегло прочтите их.
В шаблонах настроек можно использовать переменные, заключенные в {{ }} (шаблонизатор тут — jinja2). Эти переменные будут заменены на значения из словаря env.conf при выкладке шаблонов на сервер.
4. Создайте config.server.py в корне проекта. Этот файл станет файлом config.py на сервере. Пример:
Создайте также config.py с локальными настройками для разработки. Импортируйте config.py в settings.py:
Трюк широко известный, часто config.py называют также local_settings.py. Этот файл должен быть добавлен в игнорируемые в VCS (если VCS используется).
Как можно было заметить, config.server.py — тоже шаблон (как и файлы из папки config_templates), в него тоже будут подставляться переменные из env.conf.
5. Создайте папку 'reqs' в корне проекта. Пример такой папки можно получить, выполнив следующую команду из корня проекта:
В этой папке должны лежать текстовые файлы с pip-зависимостями. Один файл имеет особое значение: reqs/all.txt. Это главный файл с зависимостями, все пакеты оттуда будут установлены при развертывании. Там можно или все зависимости просто перечислить, или (лучше) подключать другие файлы с зависимостями через опцию “-r”.
Есть еще команда
После того, как шаги 1-5 выполнены, проект должен выглядеть как-то так:
Если все так, то проект готов.
1. Если в env.hosts был указан несуществующий пользователь, то создадим его и настроим ssh-доступ по ключу, вручную или вот так (понадобится файл с вашим публичным ключом):
Проверяем, что ssh работает:
2. Настроим БД. Если БД уже настроена вручную (например, проект уже работает), то ничего делать не нужно. django-fab-deploy сейчас умеет устанавливать mysql и создавать пустую базу под проект:
mysql_install ничего не делает, если mysql уже установлен на сервер. Если mysql не установлен, то он устанавливается, а пароль для mysql-пользователя root выставляется в env.conf['DB_PASSWORD'].
mysql_create_db создает пустую базу с названием env.conf['DB_NAME'] (в нашем примере это будет имя пользователя из env.hosts).
Если используется не mysql или пользователь mysql — не root, то лучше сейчас все руками сделать. А еще лучше — автоматизировать (написать fabric-скрипт для этого) и отправить патч в django-fab-deploy.
3. Все, сервер готов. Можно скрестить пальцы и запустить команду из корня проекта:
Если все было сделано правильно, сайт должен заработать.
Эта команда:
Исходные коды будут лежать в ~/src/<INSTANCE_NAME>, virtualenv будет помещен в ~/envs/<INSTANCE_NAME>.
django-fab-deploy отключит сайты «default» для апача и nginx'а, а также станет командовать апачевским ports.conf (апач больше не будет слушать 80 порт). Если на сервере крутились другие сайты под апачем, то они станут недоступными из-за этого. Если наружу торчал только nginx, то все должно быть хорошо — django-fab-deploy ничего хитрого с сервером не делает.
Залить изменения на сервер и применить их:
Еще пример (выложить изменения на сервер prod, при этом обновить зависимости и выполнить миграции):
Обновить настройки веб-сервера:
Обновить настройки джанги (config.server.py):
Полный список команд можно найти в документации. Если хочется чего-то более высокоуровнего (в духе — запустил fab redeploy и все сразу обновилось, и код, и настройки, и зависимости, и миграции выполнились) — можно легко написать свою fab-команду как обертку над базовыми командами. Если команда push делает слишком много (она, например, запускает тесты по умолчанию), то не стесняйтесь — гляньте на код и напишите в своем fabfile.py более подходящую версию. Если считаете какой-то такой эксперимент полезным и удачным — открывайте тикет в баг-трекере.
Наиболее близкий аналог django-fab-deploy — woven. Судя по всему, тоже отличная штука. Woven ориентирован на Ubuntu, Debian поддерживается примерно как Ubuntu в django-fab-deploy: «вроде должно работать с небольшими изменениями, но никто не знает точно». Начинали мы делать все примерно в одно и то же время, там сначала была какая-то дичь на классах, потом они все упростили. Продвинулись они подальше. С другой стороны, в django-fab-deploy в несколько раз меньше исходного кода, он поменьше и попроще, и останется таким.
Похожие проекты много кто делает. По гитхабу/битбакету поискал недавно, и в djangopackages еще 11 штук аналогов добавил (разной степени проработанности), можно тут глянуть сравнительную табличку: djangopackages.com/grids/g/deployment
Актуальную документацию всегда можно найти тут: packages.python.org/django-fab-deploy
Репозиторий с исходным кодом и баг-трекером: bitbucket.org/kmike/django-fab-deploy
Подключайтесь: используйте, исправляйте, пишите замечания, предложения, как все улучшить и т.д.
Описание в статье относится к версии 0.4 и может устареть; читайте, по возможности, документацию.
Не обязательно пользоваться именно django-fab-deploy, можно писать свои скрипты с 0, использовать woven, buildout или что угодно. Только все же перед тем, как писать все с 0, лучше, понятно, сделать «домашнюю работу» и посмотреть, как реализованы существующие проекты.
Главный совет — автоматизируйте как-то процесс настройки сервера и выкладки изменений даже для простейших проектов, это не сложнее ручной настройки и многократно окупается в дальнейшем.
Существую разные подходы к этому процессу: специфичные для питона (fabric, buildout) или неспецифичные (puppet, Chef, наборы shell-скриптов и т.д.).
Подход fabric — локально выполняемый скрипт ходит по ssh на сервер и выполняет там команды. Этот подход довольно прямолинеен и прост в отладке, тем и хорош (обзор на хабре). Из разнообразных команд fabric постепенно вырисовался велосипед под названием django-fab-deploy. Это набор fabric-скриптов, который умеет настраивать серверы под Debian Lenny или Squeeze, а потом с минимальными усилиями разворачивать там django-проекты и управлять этими проектами в дальнейшем.
С выходом Debian Squeeze взялся за django-fab-deploy посерьезнее, поправил некоторые шероховатости и теперь, думаю, самое время об этом проекте рассказать. У проекта есть документация, тут будет краткий пересказ с лирическими отступлениями.
Общие принципы:
- проекты изолировны с помощью virtualenv;
- зависимости управляются с помощью requirements-файлов pip;
- все общение с сервером ведется по ssh и должно быть автоматизировано ( => повторяемо);
Серверная часть:
- поддерживаются Debian Lenny и Debian Squeeze;
- способ запуска python-кода: apache + mod_wsgi + nginx перед ними;
- на одном VPS/сервере может крутиться сколько угодно проектов, управляемых django-fab-deploy;
- один проект может быть выложен на несколько серверов (в том числе с разными настройками).
Главными критериями для выбора способа развертывания были стабильность/надежность, и тут связке apache+mod_wsgi+nginx на данный момент равных нет. Думаю, поддержку убунты добавить будет не сложно, но чего об этом говорить-то, раз поддержки убунты прямо сейчас нет (сам убунтой не пользуюсь).
Проекту хорошо бы хранится в системе контроля версий (сейчас поддерживается mercurial). Имеется полузаглушка с загрузкой/распаковкой tar.gz на случай, если проект не в VCS; она работает, но в продакшн-режиме я ее не проверял (незачем было), и есть вероятность, что проявятся какие-нибудь особенности.
Автоматизируем развертывание
Ниже описан базовый способ развертывания сервера, если он по каким-то причинам не подходит, то не страшно: django-fab-deploy — просто набор скриптов; их можно использовать по частям, или какие-нибудь полезности подсмотреть, или отправить патч, или просто статью почитать.
Предполагается, что у нас есть чистый Debian-сервер (можно и не «чистый», об этом позже), настроен ssh-доступ по публичному ключу к root.
Пожалуйста, не используйте VPS на OpenVZ, т.к. на них ограничивается VIRT вместо RSS и поэтому куча софта (в том числе апач и mysql+innodb) под OpenVZ ест гораздо больше памяти, чем под xen/kvm (в 10 раз — да легко).
Подготовка проекта
Джанго-проекты и так часто используют какую-нибудь разновидность трюка с 'local_settings.py', лежат в системе контроля версий, в репозитории имеют файлик с pip-зависимостями и папку с настройками для веб-сервера. Ничего кроме этого django-fab-deploy, по сути, и не требует. Дальше — детали.
1. Устанавливаем django-fab-deploy и его зависимости:
pip install django-fab-deploy pip install jinja2 pip install -e git+git://github.com/bitprophet/fabric.git#egg=Fabric-dev
django-fab-deploy не работает с Fabric 0.9.x, Fabric должен быть установлен с github'а.
2. Создаем файл fabfile.py в корне проекта. В этом файле должна быть одна или несколько функций, настраивающих параметры сервера. Ну и т.к. это обычный fabric-скрипт, там могут быть любые другие (специфичные для проекта) команды. Пример:
# my_project/fabfile.py
from fab_deploy import *
def my_site():
env.hosts = ['my_site@example.com']
env.conf = dict(
DB_PASSWORD = 'password',
PROCESSES = 2,
# раскомментировать, если на сервере Debian Squeeze; по умолчанию стоит значение 'lenny'
# OS = 'squeeze',
# раскомментировать, если проект не хранится в системе контроля версий (по умолчанию - 'hg')
# VCS = 'none',
)
update_env()
my_site()
Обратите внимание на env.hosts. Тут есть фишка: укажите в качестве пользователя (my_site) название своего проекта (оно должно быть правильным названием переменной в python — без тире и пробелов). Не страшно, если такого пользователя нет, django-fab-deploy сможет его создать и настроить ssh-доступ позже. В любом случае, иметь отдельного пользователя для каждого проекта — хорошая идея.
В env.conf применяются некоторые соглашения для упрощения всего. Например, название БД (DB_NAME) по умолчанию совпадает с названием экземпляра проекта (INSTANCE_NAME), которое, в свою очередь, совпадает с пользователем из env.hosts.
Чтобы узнать больше о том, что и как можно настраивать тут, см. документацию по fabfile api.
3. Создадим шаблоны настроек для веб-сервера и т.д.:
django-fab-deploy config_templates
Появится папка config_templates в корне проекта, там лежат шаблоны настроек. Проекты бывают разные, и часто настройкам потребуются правки — как минимум бегло прочтите их.
В шаблонах настроек можно использовать переменные, заключенные в {{ }} (шаблонизатор тут — jinja2). Эти переменные будут заменены на значения из словаря env.conf при выкладке шаблонов на сервер.
4. Создайте config.server.py в корне проекта. Этот файл станет файлом config.py на сервере. Пример:
# my_project/config.server.py
DEBUG = False
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': '{{ DB_NAME }}',
'USER': '{{ DB_USER }}',
'PASSWORD': '{{ DB_PASSWORD }}',
'HOST': '',
'PORT': '',
'OPTIONS': {
"init_command": "SET storage_engine=INNODB"
},
}
}
Создайте также config.py с локальными настройками для разработки. Импортируйте config.py в settings.py:
# Django settings for my_project project.
# ...
from config import *
# ...
Трюк широко известный, часто config.py называют также local_settings.py. Этот файл должен быть добавлен в игнорируемые в VCS (если VCS используется).
Как можно было заметить, config.server.py — тоже шаблон (как и файлы из папки config_templates), в него тоже будут подставляться переменные из env.conf.
5. Создайте папку 'reqs' в корне проекта. Пример такой папки можно получить, выполнив следующую команду из корня проекта:
django-fab-deploy example_reqs
В этой папке должны лежать текстовые файлы с pip-зависимостями. Один файл имеет особое значение: reqs/all.txt. Это главный файл с зависимостями, все пакеты оттуда будут установлены при развертывании. Там можно или все зависимости просто перечислить, или (лучше) подключать другие файлы с зависимостями через опцию “-r”.
Есть еще команда
django-fab-deploy generate_reqs
, которая создает папку reqs с одним файлом all.txt, в котором перечислены все установленные в локальном окружении питоньи пакеты (то, что показывает pip freeze).После того, как шаги 1-5 выполнены, проект должен выглядеть как-то так:
my_project ... config_templates ... reqs all.txt ... fabfile.py config.py config.server.py settings.py manage.py
Если все так, то проект готов.
Подготовка сервера
1. Если в env.hosts был указан несуществующий пользователь, то создадим его и настроим ssh-доступ по ключу, вручную или вот так (понадобится файл с вашим публичным ключом):
fab create_linux_account:"/home/kmike/.ssh/id_rsa.pub"
Проверяем, что ssh работает:
ssh my_site@example.com
2. Настроим БД. Если БД уже настроена вручную (например, проект уже работает), то ничего делать не нужно. django-fab-deploy сейчас умеет устанавливать mysql и создавать пустую базу под проект:
fab mysql_install fab mysql_create_db
mysql_install ничего не делает, если mysql уже установлен на сервер. Если mysql не установлен, то он устанавливается, а пароль для mysql-пользователя root выставляется в env.conf['DB_PASSWORD'].
mysql_create_db создает пустую базу с названием env.conf['DB_NAME'] (в нашем примере это будет имя пользователя из env.hosts).
Если используется не mysql или пользователь mysql — не root, то лучше сейчас все руками сделать. А еще лучше — автоматизировать (написать fabric-скрипт для этого) и отправить патч в django-fab-deploy.
3. Все, сервер готов. Можно скрестить пальцы и запустить команду из корня проекта:
fab full_deploy
Если все было сделано правильно, сайт должен заработать.
Эта команда:
- установит необходимые системные пакеты
- создаст virtualenv и установит туда питоньи зависимости
- настроит апач и nginx
- загрузит проект на сервер
- выполнит syncdb и migrate
Исходные коды будут лежать в ~/src/<INSTANCE_NAME>, virtualenv будет помещен в ~/envs/<INSTANCE_NAME>.
django-fab-deploy отключит сайты «default» для апача и nginx'а, а также станет командовать апачевским ports.conf (апач больше не будет слушать 80 порт). Если на сервере крутились другие сайты под апачем, то они станут недоступными из-за этого. Если наружу торчал только nginx, то все должно быть хорошо — django-fab-deploy ничего хитрого с сервером не делает.
Управление сервером
Залить изменения на сервер и применить их:
fab push
Еще пример (выложить изменения на сервер prod, при этом обновить зависимости и выполнить миграции):
fab prod push:pip_update,migrate
Обновить настройки веб-сервера:
fab setup_web_server
Обновить настройки джанги (config.server.py):
fab update_django_config
Полный список команд можно найти в документации. Если хочется чего-то более высокоуровнего (в духе — запустил fab redeploy и все сразу обновилось, и код, и настройки, и зависимости, и миграции выполнились) — можно легко написать свою fab-команду как обертку над базовыми командами. Если команда push делает слишком много (она, например, запускает тесты по умолчанию), то не стесняйтесь — гляньте на код и напишите в своем fabfile.py более подходящую версию. Если считаете какой-то такой эксперимент полезным и удачным — открывайте тикет в баг-трекере.
Аналоги
Наиболее близкий аналог django-fab-deploy — woven. Судя по всему, тоже отличная штука. Woven ориентирован на Ubuntu, Debian поддерживается примерно как Ubuntu в django-fab-deploy: «вроде должно работать с небольшими изменениями, но никто не знает точно». Начинали мы делать все примерно в одно и то же время, там сначала была какая-то дичь на классах, потом они все упростили. Продвинулись они подальше. С другой стороны, в django-fab-deploy в несколько раз меньше исходного кода, он поменьше и попроще, и останется таким.
Похожие проекты много кто делает. По гитхабу/битбакету поискал недавно, и в djangopackages еще 11 штук аналогов добавил (разной степени проработанности), можно тут глянуть сравнительную табличку: djangopackages.com/grids/g/deployment
Ссылки
Актуальную документацию всегда можно найти тут: packages.python.org/django-fab-deploy
Репозиторий с исходным кодом и баг-трекером: bitbucket.org/kmike/django-fab-deploy
Подключайтесь: используйте, исправляйте, пишите замечания, предложения, как все улучшить и т.д.
Описание в статье относится к версии 0.4 и может устареть; читайте, по возможности, документацию.
Не обязательно пользоваться именно django-fab-deploy, можно писать свои скрипты с 0, использовать woven, buildout или что угодно. Только все же перед тем, как писать все с 0, лучше, понятно, сделать «домашнюю работу» и посмотреть, как реализованы существующие проекты.
Главный совет — автоматизируйте как-то процесс настройки сервера и выкладки изменений даже для простейших проектов, это не сложнее ручной настройки и многократно окупается в дальнейшем.