Статьи

Развертывание приложения Django в dotCloud

Как я упоминал в недавнем сообщении в блоге , за 11 месяцев, прошедших с того момента, как я написал свой первый пост на dotCloud , я сейчас там работаю. Помимо меня, работающего там, в dotCloud было много других изменений , и я хотел потратить время, чтобы обновить свой оригинальный пост, чтобы он был актуальным и имел всю последнюю информацию. Я собираюсь полностью переписать старый пост здесь с обновленной информацией и оставить старый для потомков.

Цель dotCloud — предоставить набор различных независимых сервисов, которые вы можете использовать в качестве строительных блоков для создания вашего приложения. Если вам нужна база данных, выберите один из множества поддерживаемых ими. Нужно приложение, которое использует Django или Rails на внешнем интерфейсе, и Java на серверном, это нормально, вы тоже можете это сделать. Они понимают, что большинство разработчиков не придерживаются одного стандартного технологического стека для всех своих приложений, поэтому это дает вам гибкость в использовании лучшего инструмента для работы. Это также дает вам прекрасную возможность попробовать новые сервисы и посмотреть, как они работают, без необходимости устанавливать, настраивать и поддерживать сервис только для тестирования.

Я собираюсь пройти через шаги, которые потребовались для установки моего блога на dotCloud, и, надеюсь, по пути ответить на некоторые распространенные вопросы.

Документация

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

http://docs.dotcloud.com/firststeps/platform-overview/

http://docs.dotcloud.com/tutorials/python/django/

http://docs.dotcloud.com/services/mysql/

http://docs.dotcloud.com/services/mysql-masterslave/

Первые шаги:

Как и все классные сервисы в наши дни, dotCloud использует CLI на основе Python, поэтому прежде чем мы сможем начать, нам нужно установить клиент dotCloud и настроить его так, чтобы мы могли начать его использовать.

# create my dotcloud virtual environment.
$ mkvirtualenv dotcloud

# install dotcloud client using pip
$ pip install dotcloud

# create our application called blog
$ dotcloud create blog

#enter api key that we got from: http://www.dotcloud.com/account/settings when prompted
#<key goes here>

# if you were not prompted to enter your key you can run this command, and it will let you enter your API key again.
$ dotcloud register

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

# go into projects directory
cd ~/projects

# forked kencochranenet to kencochranenet_dotcloud, now clone that. locally
git clone git://github.com/kencochrane/kencochranenet_dotcloud.git kencochranenet_dotcloud

# go into the new directory.
cd kencochrane_dotcloud

 Прочтение документации говорит мне, что мне нужно создать файл wsgi.py и поместить его в корень моего проекта. Используя http://docs.dotcloud.com/tutorials/python/django/#wsgi-py в качестве шаблона, я создал свой файл wsgi.py ниже. У меня были проблемы с шаблоном по умолчанию, и мне нужно было добавить каталог в sys.path, чтобы wsgi мог правильно найти мои приложения django. Вот мой готовый файл.

import os
import sys

# Ken added this, only thing that is different from the example template (not counting settings file name)
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__),'mysite')))
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'

import django.core.handlers.wsgi
djangoapplication = django.core.handlers.wsgi.WSGIHandler()
def application(environ, start_response):
    if 'SCRIPT_NAME' in environ:
        del environ['SCRIPT_NAME']
    return djangoapplication(environ, start_response)

DotCloud использует файлы требований PIP для управления зависимостями вашего проекта. У нас уже есть наш файл требований к пипсам, где он должен быть и назван правильно, поэтому нам не нужно ничего делать, но если бы у нас его не было, нам нужно было бы создать его, поместить в корень и вызвать его requirements.txt

Сервисы

Когда мы добавляем сервис в наш стек развертывания, dotCloud предоставляет нам соответствующую информацию о соединении в файле с именем /home/dotcloud/environment.json, который доступен для нас в нашем контейнере развертывания. Это позволяет нам не кодировать имя пользователя / пароль и URL сервера в нашем файле settings.py, а также делает его немного более безопасным для нас, поскольку нам не нужно иметь эту информацию в нашем исходном репозитории.

Вот как мы это используем. В верхней части вашего файла settings.py вам нужно добавить следующее. сниппет.

import json
with open('/home/dotcloud/environment.json') as f:
  env = json.load(f)

После того, как мы добавили это в файл settings.py, теперь у нас есть переменная env, в которой есть все необходимые нам настройки env.

Вы можете пойти немного дальше, добавив некоторый пользовательский код, чтобы проверить, существует ли файл environment.json, и если он существует, вы знаете, что работаете, поэтому используйте эту настройку или, если нет, то вы должны быть в локальном режиме, поэтому используйте ваши локальные настройки. Если вы хотите стать действительно крутым, вы можете иметь свой собственный json-файл, который имеет аналогичную настройку для локальной разработки, и если он не находит dotcloud, он может найти свой собственный и загрузить из него свои настройки. Это позволит вам использовать один и тот же файл настроек как для production, так и для dev, с небольшим количеством кода вверху для загрузки правильного env-файла.

База данных

Большинству приложений нужна база данных, и этот блог ничем не отличается. Вот как мы настраиваем нашу базу данных для работы с нашим блогом на dotcloud. Мы собираемся использовать mysql для нашей базы данных. С Django вам нужно установить настройки базы данных в вашем settings.py. Вот как мы устанавливаем соединение с базой данных MySQL в нашем файле settings.py. Обратите внимание, что имя базы данных не взято из env, вы выбираете это самостоятельно.

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'blogdb',
        'USER': env['DOTCLOUD_DB_MYSQL_LOGIN'],
        'PASSWORD': env['DOTCLOUD_DB_MYSQL_PASSWORD'],
        'HOST': env['DOTCLOUD_DB_MYSQL_HOST'],
        'PORT': int(env['DOTCLOUD_DB_MYSQL_PORT']),
    }
}

Создать базу данных

dotCloud предоставляет вам собственную выделенную базу данных с полным доступом к корневому каталогу. С великой властью приходит великая ответственность. Одна из этих обязанностей заключается в том, что вам нужно создавать собственные схемы базы данных и самих пользователей. Что означает, что вам обычно нужно сделать что-то подобное.

# connect to dotcloud mysql server instance
$ dotcloud run blog.db -- mysql -u root -p

# mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 34
Server version: 5.1.41-3ubuntu12.10 (Ubuntu)

# create the user and database and give user permissions to database.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> create database blogdb;
Query OK, 1 row affected (0.00 sec)

mysql> create user 'blog_username' identified by 'strong_password';
Query OK, 0 rows affected (0.05 sec)

mysql> grant all on blogdb.* to 'blog_user'@'%';
Query OK, 0 rows affected (0.04 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql> exit;Bye
Shared connection to database closed.

Это выглядит знакомо? У меня есть это здесь на случай, если вы захотите сделать это далеко.

Чтобы упростить задачу, мы собираемся создать небольшой скрипт на python, который проверит, создана ли наша база данных, и если нет, он создаст ее для нас. Это позволит нам не входить в нашу базу данных и делать это вручную перед развертыванием. Файл называется createb.py, и вот как он выглядит. Этот скрипт для MySQL. Если вам нужна база данных postgreSQL, вы можете использовать ее в качестве шаблона и изменить ее так, чтобы она работала с postgreSQL.

import MySQLdb
import os
from wsgi import *

def create_dbs(names):
    print("create_dbs: let's go.")
    django_settings = __import__(os.environ['DJANGO_SETTINGS_MODULE'], fromlist='DATABASES')
    print("create_dbs: got settings.")
    databases = django_settings.DATABASES
    for name, db in databases.iteritems():
        if name in names and db['ENGINE'].endswith('mysql'):
            host = db['HOST']
            user = db['USER']
            password = db['PASSWORD']
            port = db['PORT']
            db_name = db['NAME']
            print 'creating database %s on %s' % (db_name, host)
            db = MySQLdb.connect(user=user,
                                passwd=password,
                                host=host,
                                port=port)
            cur = db.cursor()
            print("Check if database is already there.")
            cur.execute("""SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
                         WHERE SCHEMA_NAME = %s""", (db_name,))
            results = cur.fetchone()
            if not results:
                print("Database %s doesn't exist, lets create it." % db_name)
                sql = """CREATE DATABASE IF NOT EXISTS %s """ % (db_name,)
                print("> %s" % sql)
                cur.execute(sql)
                print(".....")
            else:
                print("database already exists, moving on to next step.")


if __name__ == '__main__':
    import sys
    print("create_dbs start")
    create_dbs(sys.argv[1:])
    print("create_dbs all done")

Добавление кеша

Так как большая часть содержимого блога не сильно меняется, это отличный кандидат для кеширования. Итак, мы собираемся воспользоваться встроенными в Django способами кеширования и добавить немного кеширования в наш блог. Обычно для кэширования я использую memcached , но поддержка memcached в dotCloud сейчас ограничена. Причина, по которой он ограничен, заключается в том, что в memcached нет встроенного механизма аутентификации, и для обеспечения его безопасности необходимо запустить специальную версию memcached, которая поддерживает SASL.и большинство клиентов memcached не поддерживают это. Поэтому вместо развертывания небезопасной службы они решили не поддерживать ее полностью. Есть способы использовать его, но он включает в себя все виды сложных правил брандмауэра и запуска чего-то вроде stunnel. Так что это возможно, но это не очень чисто.

Вместо этого они рекомендуют вам использовать Redis , Redis обладает теми же возможностями кэширования, что и memcached, и намного больше, включая аутентификацию. Итак, мы собираемся использовать Redis для нашего кэша. Чтобы использовать Redis, нам нужно добавить библиотеку Redis, потому что поддержка кэширования Redis не встроена в Django. В ваш файл needs.txt вам нужно добавить django-redis == 1.4.5, чтобы библиотеки были доступны для использования Django.

После того, как вы установили библиотеку, вам нужно будет добавить эти настройки в ваш файл settings.py, чтобы django знал, какой сервер redis и пароль использовать.

CACHES = {
    'default': {
        'BACKEND': 'redis_cache.cache.RedisCache',
        'LOCATION': env['DOTCLOUD_CACHE_REDIS_HOST']+':'+env['DOTCLOUD_CACHE_REDIS_PORT'],
        'OPTIONS': {
            'DB': 1,
            'PASSWORD': env['DOTCLOUD_CACHE_REDIS_PASSWORD'],
            'PARSER_CLASS': 'redis.connection.HiredisParser'
        },
    },
}

# we also are going to use redis for our session cache as well.
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'

Для получения дополнительной информации об использовании Redis в качестве кеша для Django, посмотрите эти ссылки.

Джанго Админ

Нам также нужен простой способ создать нашу учетную запись администратора django. Для этого у меня есть скрипт mkadmin.py. При этом пароль по умолчанию будет «P @ s $ w0rd1 ». После того , как вы установили свой код, вам нужно будет войти в учетную запись администратора и изменить свой пароль на более безопасный.

#!/usr/bin/env python
from wsgi import *
from django.contrib.auth.models import User
u, created = User.objects.get_or_create(username='admin')
if created:
    u.set_password('P@s$w0rd1')
    u.is_superuser = True
    u.is_staff = True
    u.save()

СМИ

Нам нужно поместить наши статические и мультимедийные файлы в следующие места: static = / home / dotcloud / data / static / и media = / home / dotcloud / data / media / . В связи с этим нам необходимо убедиться, что мы изменили наш файл settings.py и настроили файл nginx.conf для сопоставления с правильными местоположениями. Вот изменения файла settings.py.

# media settings
MEDIA_ROOT = '/home/dotcloud/data/media/'
MEDIA_URL = '/media/'

# static settings
STATIC_ROOT = '/home/dotcloud/data/static/'
STATIC_URL = '/static/'

# admin prefix
ADMIN_MEDIA_PREFIX = '/static/admin/'

Вот это nginx.conf

location /media/ { root /home/dotcloud/data ; }
location /static/ { root /home/dotcloud/data ; }

После установки

Мы собираемся создать сценарий postinstall для обработки всех задач, которые нам нужно выполнить после установки нашего кода на сервере. Это то, что будет называться нашими файлами creatb.py и mkadmin.py сверху, а также синхронизация нашей базы данных, запуск миграций и запуск collectstatic для перемещения всех статических файлов в нужные места.

#!/bin/sh
python createdb.py default
python mysite/manage.py syncdb --noinput
python mysite/manage.py migrate
python mkadmin.py
mkdir -p /home/dotcloud/data/media /home/dotcloud/data/static
python mysite/manage.py collectstatic --noinput

 Не забудьте убедиться, что ваши сценарии postinstall, createb.py и mkadmin.py являются исполняемыми.

# make the script executable.
$ chmod +x postinstall createdb.py mkadmin.py

dotcloud.yml

Теперь, когда структура проекта нашего приложения полностью настроена и настроена так, как этого хочет dotCloud, мы можем настроить наш стек развертывания. Это делается с помощью файла с именем dotcloud.yml. Для получения дополнительной информации о файле dotcloud.yml перейдите по этой ссылке: http://docs.dotcloud.com/guides/build-file/

www:
  type: python
db:
  type: mysql
cache:
  type: redis

Это говорит нам о том, что нам нужны 3 службы, служба python www, служба mysql db и служба redis cache. Это очень простая настройка, и вы можете сделать ее намного сложнее в зависимости от того, чего хотите достичь. Обратите внимание, что это не настроено для высокой доступности, потому что ни один из экземпляров не масштабируется. См. Раздел о масштабировании ниже для получения дополнительной информации. Если вы работаете в производственном приложении на dotCloud, рекомендуется масштабировать все ваши службы таким образом, чтобы они могли противостоять сбоям сервера EC2 и другим непредвиденным проблемам.

развертывание

Теперь мы готовы развернуть наше приложение Django, но прежде чем идти дальше, важно знать следующее. Dotcloud обратит внимание на ваши файлы .gitignore. Если у вас есть файл настроек в вашем файле .gitignore, чтобы он не сохранялся в репозитории, он не перенесет эти изменения в облако. Вам нужно будет удалить его из .gitignore, чтобы получить эти файлы. Также важно помнить, что передаются только зафиксированные изменения, поэтому не забудьте зафиксировать их. Если вы хотите быть хитрым, вы можете использовать скрипт постустановки, чтобы вытащить файл из безопасного места и установить его таким образом, если вы хотите сделать вещи сверхбезопасными.

Все настроено, поэтому все, что нам нужно сделать, это переместить наше приложение в dotCloud.

# push out your changes to the server
$ dotcloud push blog .

Сервисная информация

Как только вы отправите свой код в dotCloud, вы можете увидеть, как он выглядит, запустив команду info.

# get the information about our new services
$ dotcloud info blog
cache:
    config:
        redis_password: <password>
        redis_replication: true
    instances: 1
    type: redis
db:
    config:
        mysql_masterslave: true
        mysql_password: <password>
    instances: 1
    type: mysql
www:
    config:
        static: static
        uwsgi_processes: 4
    instances: 1
    type: python
    url: <url was here>

пересчет

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

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

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

Высокая доступность означает, что у вас одновременно запущено более одной службы, поэтому, если у одной из служб возникнет проблема, другая воспользуется слабым местом. Это поможет избежать простоев при возникновении сбоев (сбой экземпляра EC2). В идеале при работе в производстве все ваши службы должны масштабироваться для обеспечения высокой доступности.

Существует два вида услуг: с сохранением состояния и без сохранения состояния. Службы с состоянием — это службы, которые хранят постоянные данные. Примерами сервисов с отслеживанием состояния являются mysql, redis, postgresql, solr, MongoDB и RabbitMQ.

Горизонтально Высокая доступность, масштабирующая службу с отслеживанием состояния в dotCloud, означает создание настройки master / slave, которая может автоматически переключать slave с master, если у master есть какие-либо проблемы. dotCloud поддерживает масштабирование HA на MySQL, Redis и MongoDB.

Масштабируемые сервисы такого масштаба

  • MySQL: 2 (ведущий / ведомый)
  • Redis: 2 (ведущий / ведомый)
  • mongodb: 3 или 5 (с использованием наборов реплик)

Масштабирование без сохранения состояния и одной из поддерживаемых служб с сохранением состояния выполняется одинаково. Вы просто запустите команду командной строки масштаба.

$ dotcloud scale app db=2

 

Для приложений без сохранения состояния вы ограничены установленным количеством единиц масштабирования, если только вы не находитесь на корпоративном плане. Если вам нужно приложение с большим количеством единиц измерения, вам следует связаться с dotCloud и сообщить им, что вы планируете делать, и они посоветуют вам, как лучше всего достичь ваших целей.

Ссылка: http://docs.dotcloud.com/guides/scaling/

Резервные копии базы данных

То, что вы размещаете свое приложение на dotCloud, не означает, что вы не должны делать резервные копии своих данных. Самые важные данные для резервного копирования — это ваша база данных. К счастью, dotCloud позволяет легко создавать резервные копии вашей базы данных. Вот очень полезное руководство по настройке резервных копий базы данных здесь: http://docs.dotcloud.com/guides/backups/

Электронное письмо

Если вам нужно отправить или получить электронное письмо от вашего приложения, вы можете сделать это для. Поскольку dotCloud работает на EC2, а EC2 — популярное место, откуда СПАМЕРЫ отправляют СПАМ, лучше всего использовать стороннего поставщика электронной почты для отправки ваших электронных писем за вас. Популярными являются MailGun , SendGrid , CritSend и Amazon SES .

Вы можете настроить это несколькими способами. Первый способ — самый простой из возможных, он позволяет настроить параметры SMTP для каждой службы. Вы бы сделали это так (см. Ниже). Вы можете вручную установить параметры SMTP для этой службы, и когда вашему приложению потребуется отправить электронное письмо, оно будет использовать эти параметры. Это самая простая установка, но у этого подхода есть свои недостатки. Вам нужно будет установить это для каждой службы, если у вас есть более одной, которая будет дублироваться везде. Также, если вы хотите изменить настройки, вам нужно будет уничтожить ваш сервис и воссоздать его, поскольку эти конфиги могут быть установлены только один раз при создании сервиса.

www:
  type: python
  config:
    smtp_server: smtp.mailgun.org
    smtp_port: 25
    smtp_username: [email protected]
    smtp_password: YourMailGunPassword 

A better approach would be to use dotCloud’s SMTP service. The SMTP service is built to receive emails from your services and forward them to the appropriate location. It is best to use a 3rd party email provider, but you can also use the typical poor mans solution, where you use gmail to send your emails. Be careful when using gmail, because you aren’t aloud to send a lot of emails via gmail, once you hit your daily limit you will be blocked, so this is fine for a few emails a day, don’t trust it for everyday stuff. Also, the emails will always be coming from your gmail address, fine for system emails, but not if you are trying to run a legit business.

Here is an example using mailgun.

mailer:
  type: smtp
  config:
    smtp_relay_server: smtp.mailgun.org
    smtp_relay_port: 587
    smtp_relay_username: [email protected]
    smtp_relay_password: YourMailgunPassword
 

Here is an example using gmail.

mailer:
  type: smtp
  config:
    smtp_relay_server: smtp.gmail.com
    smtp_relay_port: 587
    smtp_relay_username: [email protected]
    smtp_relay_password: Your_Gmail_Password

Once you have these all setup, they will be available in your environment.json file.

If you want to receive email, it is best to use a service like MailGun .

Links:

Cron jobs

If your app needs to run cron jobs, follow the steps in this guide: http://docs.dotcloud.com/guides/periodic-tasks/

Celery

This blog doesn’t really have a need for celery, but dotCloud does support it. For more information follow this link: http://docs.dotcloud.com/tutorials/python/django-celery/

S3FS

If you store data on s3 you can mount your s3 bucket so that you can have access to s3 from your application, just like it was a local directory on your container. This is helpful for storing files that are uploaded by your visitors, or to share files between different web processes. Follow these instructions to set it up: http://docs.dotcloud.com/guides/s3fs/

Logs

If you need to look at the logs to see how it is going you can do it two ways. The first way will tail your logs for you to your console.

# look at logs of your service, it will tail them to your console. ctrl-c to stop.
$ dotcloud logs blog.www

 Or login via ssh and look at your logs.

# Open up a shell
$ dotcloud ssh blog.www

 Here are the ones you most likely care about.

# nginx access and error logs.
/var/log/nginx/<app_name>.{access,error}.log

# wsgi error logs
/var/log/supervisor/uswgi.log

Restart Service

If you need to restart your service just issue this command.