Pull to refresh

Автоматизируем выкладку django-проектов на сервер

Django *
Настраивать VDS'ки для выкладки django-проектов довольно утомительно бывает, да и легко что-то забыть (т.к. делаешь это не каждый день). Гораздо лучше, когда этот процесс автоматизирован: с меньшими усилиями можно получить правильно настроенный проект и набор команд для работы с ним.

Существую разные подходы к этому процессу: специфичные для питона (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, лучше, понятно, сделать «домашнюю работу» и посмотреть, как реализованы существующие проекты.

Главный совет — автоматизируйте как-то процесс настройки сервера и выкладки изменений даже для простейших проектов, это не сложнее ручной настройки и многократно окупается в дальнейшем.
Tags:
Hubs:
Total votes 49: ↑47 and ↓2 +45
Views 12K
Comments Comments 30