Развертывание приложения Django на Heroku: можно ли вручную установить переменные среды в файле.env? Нужно ли устанавливать такие инструменты, как autoenv, heroku-config...?
Моя цель:
Я собираюсь следовать методологии "Приложения с двенадцатью факторами" для создания своего приложения Django на Heroku.
Вступление:
Я следую краткому руководству "Начало работы с Django on Heroku". На данный момент у меня следующая структура каталогов:
~/Projects/
hellodjango_rep/
.env (empty)
.git
.gitignore
Procfile
requirements.txt
hellodjango/
manage.py
hellodjango/
__init__.py
settings/
urls.py
wsgi.py
Я установил django-toolbelt, создал свое простое приложение Django, запустил процесс в моем Procfile... Казалось, все работает нормально, но проблемы начались, когда я настроил приложение для среды Heroku и добавил:
import dj_database_url
DATABASES['default'] = dj_database_url.config()
внизу моего файла settings.py.
Я отправил репозиторий своего приложения в Heroku, посетил приложение в своем браузере с $ heroku open
успешно, но локально: dj_database_url.config()
вернул пустой словарь.
Локально:
OS X 10.8.4
пип == 1.4.1
virtualenv == 1.10.1
virtualenvwrapper == 4.1.1
wsgiref ==0.1.2
Postgres.app работает на порт 5432
Переменные среды:
mac-pol:hellodjango_rep oubiga$ python
>>> import os
>>> os.environ
{
'PROJECT_HOME': '/Users/oubiga/Projects'...
'PATH': '/usr/local/heroku/bin:/usr/local/share/python:/usr/local/bin:/Applications/Postgres.app/Contents/MacOS/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/git/bin'...
'HOME': '/Users/oubiga'...
'WORKON_HOME': '/Users/oubiga/Envs'...
'VIRTUALENVWRAPPER_HOOK_DIR': '/Users/oubiga/Envs'...
'PWD': '/Users/oubiga/Projects/hellodjango_rep'
}
hellodjango_venv:
Джанго ==1.5.2
DJ-базы данных URL ==0.2.2
DJ-статические ==0.0.5
Джанго-Toolbelt ==0.0.1
gunicorn == 18,0
psycopg2 == 2.5.1
статические ==0,4
Это то, что у меня есть в моем файле wsgi.py:
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hellodjango.hellodjango.settings")
from django.core.wsgi import get_wsgi_application
from dj_static import Cling
application = Cling(get_wsgi_application())
Вот что у меня в файле manage.py:
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hellodjango.settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
Вот что у меня есть в моем Procfile:
web: gunicorn hellodjango.hellodjango.wsgi
Переменные среды:
(hellodjango_venv)mac-pol:hellodjango_rep oubiga$ python hellodjango/manage.py shell
>>> import os
>>> os.environ
{
'PROJECT_HOME': '/Users/oubiga/Projects'...
'PATH': '/Users/oubiga/Envs/hellodjango_venv/bin:/usr/local/heroku/bin:/usr/local/share/python:/usr/local/bin:/Applications/Postgres.app/Contents/MacOS/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/git/bin',
'HOME': '/Users/oubiga'...
'WORKON_HOME': '/Users/oubiga/Envs'...
'VIRTUAL_ENV': '/Users/oubiga/Envs/hellodjango_venv'...
'VIRTUALENVWRAPPER_HOOK_DIR': '/Users/oubiga/Envs'...
'PWD': '/Users/oubiga/Projects/hellodjango_rep'...
'DJANGO_SETTINGS_MODULE': 'hellodjango.settings'
}
На Heroku:
Переменные среды:
(hellodjango_venv)mac-pol:hellodjango_rep oubiga$ heroku run python hellodjango/manage.py shell
>>> import os
>>> os.environ
{
'DATABASE_URL': 'postgres://dbuser:dbpassword@ec2-184-73-162-34.compute-1.amazonaws.com:5432/dbname',
'HEROKU_POSTGRESQL_ORANGE_URL': 'postgres://dbuser:dbpassword@ec2-184-73-162-34.compute-1.amazonaws.com:5432/dbname',
'LIBRARY_PATH': '/app/.heroku/vendor/lib', 'PWD': '/app'...
'DJANGO_SETTINGS_MODULE': 'hellodjango.settings',
'PYTHONHOME': '/app/.heroku/python'...
'PYTHONPATH': '/app/'...
'DYNO': 'run.9068',
'LD_LIBRARY_PATH': '/app/.heroku/vendor/lib'...
'HOME': '/app', '_': '/app/.heroku/python/bin/python',
'PATH': '/app/.heroku/python/bin:/usr/local/bin:/usr/bin:/bin'...
}
(hellodjango_venv)mac-pol:hellodjango_rep oubiga$ heroku config
=== damp-dusk-5382 Config Vars
DATABASE_URL: postgres://dbuser:dbpassword@ec2-184-73-162-34.compute-1.amazonaws.com:5432/dbname
HEROKU_POSTGRESQL_ORANGE_URL: postgres://dbuser:dbpassword@ec2-184-73-162-34.compute-1.amazonaws.com:5432/dbname
Исследование:
Конфигурация магазина в среде: из приложения "Двенадцать факторов"
@adamwiggins писал:
Двенадцатифакторное приложение хранит конфигурацию в переменных окружения... Варианты Env легко переключать между развертываниями без изменения кода; в отличие от конфигурационных файлов.
dj_database_url.config()
возвращает пустой объект: из форумов Heroku
@chrisantonick ответил:
... dj_database_url.config() получает учетные данные Postgres из переменных среды Heroku. Но на вашем локальном компьютере эти переменные отсутствуют. Вы должны поместить их в свой скрипт оболочки /venv/bin/activ... поместите туда переменные. что-то вроде
DATABASE_URL = "ххх"
экспорт DATABASE_URL
Для каждой вещи это нужно. Затем... "деактивировать"... и... "активировать" снова, чтобы перезапустить его.
Начало работы с инструкциями Django и Heroku Возникла ошибка Неправильно настроенная: из форумов Heroku
@jwpe ответил:
... dj-database-url - отличная утилита, так как она позволяет вам использовать точно такой же код settings.py в ваших средах разработки и производства, как это рекомендовано в "12 принципах приложения"... what dj_database_url.config() выполняет поиск переменной среды DATABASE_URL, а затем анализирует ее в предпочтительном формате Django... если вы не создали и не повысили базу данных postgres на Heroku, DATABASE_URL не будет присутствовать, и будет выдана ошибка ImproperlyConfigured, Установка значения по умолчанию для dj_database_url.config() в качестве URL-адреса вашей локальной БД - один из способов убедиться, что ваше приложение будет работать в среде разработки. Однако это не обязательно единственный путь. Возможно, лучшей альтернативой является ручная установка DATABASE_URL в вашем локальном файле.env. Затем, когда ваше приложение запускается локально с помощью Foreman, оно будет загружено в качестве переменной среды, и dj_database_url найдет его. Таким образом, ваш.env будет содержать:
DATABASE_URL=postgres://user:pass@localhost/dbname
Это означает, что в
settings.py
вам нужно только иметь:
DATABASES['default']= dj_database_url.config()
... Преимущество использования локальной переменной среды вместо единственной жестко заданной по умолчанию заключается в том, что ваш код будет работать в любой среде, в которой установлен DATABASE_URL. Если вы меняете имя своей локальной БД или хотите запустить свой код на другом компьютере разработчика, вам нужно только обновить файл.env вместо того, чтобы возиться с settings.py.
Как управлять настройками производства / постановки / разработки Django?: из форумов Heroku
@rdegges ответил:
... пытаясь заставить ваше приложение вести себя так, чтобы:
- Когда вы запускаете приложение на своем ноутбуке, оно использует ваш локальный сервер Postgres.
- Когда вы запускаете приложение в своем промежуточном приложении Heroku, оно использует аддон сервера Postgres.
- Когда вы запускаете приложение в своем производственном приложении Heroku, оно использует аддон сервера Postgres.
Лучший способ сделать это - использовать переменные среды!... Переменные среды - это самый элегантный (и масштабируемый) способ обработки конфигурации приложения между различными средами... Вместо того, чтобы иметь много файлов настроек, определите один файл: settings.py и он использует переменные среды для получения служебной информации и учетных данных... В Heroku вы можете установить переменные среды вручную, выполнив:
$ heroku config:set SOME_VARIABLE=some_value
... всегда есть отличный инструмент autoenv Кеннета Рейтца. Это позволяет вам определить простой файл.env в каталоге вашего проекта... И каждый раз, когда вы входите в каталог вашего проекта, эти переменные среды будут автоматически устанавливаться, так что вам не нужно делать ничего особенного! Просто запустите ваш проект, и все будет работать как положено:
python manage.py runserver
В качестве первой попытки:
Я вручную установил DATABASE_URL
в моем файле.env: DATABASE_URL=postgres://dbuser:dbpassword@ec2-184-73-162-34.compute-1.amazonaws.com:5432/dbname
Но когда я бегу $ foreman start
команда:
(hellodjango_venv)mac-pol:hellodjango_rep oubiga$ foreman start
17:25:39 web.1 | started with pid 319
17:25:39 web.1 | 2013-09-11 17:25:39 [319] [INFO] Starting gunicorn 18.0
17:25:39 web.1 | 2013-09-11 17:25:39 [319] [INFO] Listening at: http://0.0.0.0:5000 (319)
17:25:39 web.1 | 2013-09-11 17:25:39 [319] [INFO] Using worker: sync
17:25:39 web.1 | 2013-09-11 17:25:39 [322] [INFO] Booting worker with pid: 322
и попытался открыть мое приложение в браузере http://0.0.0.0:5000
:
17:26:59 web.1 | 2013-09-11 10:26:59 [322] [ERROR] Error handling request
17:26:59 web.1 | Traceback (most recent call last):
17:26:59 web.1 | File "/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/gunicorn/workers/sync.py", line 131, in handle_request
17:26:59 web.1 | respiter = self.wsgi(environ, resp.start_response)
17:26:59 web.1 | File "/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/dj_static.py", line 59, in __call__
17:26:59 web.1 | return self.application(environ, start_response)
17:26:59 web.1 | File "/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 236, in __call__
17:26:59 web.1 | self.load_middleware()
17:26:59 web.1 | File "/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/django/core/handlers/base.py", line 53, in load_middleware
17:26:59 web.1 | raise exceptions.ImproperlyConfigured('Error importing middleware %s: "%s"' % (mw_module, e))
17:26:59 web.1 | ImproperlyConfigured: Error importing middleware django.contrib.auth.middleware: "dlopen(/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/psycopg2/_psycopg.so, 2): Library not loaded: @loader_path/../lib/libssl.1.0.0.dylib
17:26:59 web.1 | Referenced from: /Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/psycopg2/_psycopg.so
17:26:59 web.1 | Reason: image not found"
Тем не мение, dj_database_url.config()
вернулся:
{
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'dbname',
'HOST': 'ec2-23-21-196-147.compute-1.amazonaws.com',
'USER': 'dbuser',
'PASSWORD': 'dbpassword',
'PORT': 5432
}
В качестве второй попытки:
Я вручную установил DATABASE_URL
в моем.env файле меняют хост. Я заменил "ec2-184-73-162-34.compute-1.amazonaws.com:5432" на "localhost:5000". $ deactivate
а потом $ workon hellodjango_venv
снова.
DATABASE_URL=postgres://dbuser:dbpassword@localhost:5000/dbname
Но когда я бегу $ foreman start
команда:
(hellodjango_venv)mac-pol:hellodjango_rep oubiga$ foreman start
17:38:41 web.1 | started with pid 687
17:38:41 web.1 | 2013-09-11 17:38:41 [687] [INFO] Starting gunicorn 18.0
17:38:41 web.1 | 2013-09-11 17:38:41 [687] [INFO] Listening at: http://0.0.0.0:5000 (687)
17:38:41 web.1 | 2013-09-11 17:38:41 [687] [INFO] Using worker: sync
17:38:41 web.1 | 2013-09-11 17:38:41 [690] [INFO] Booting worker with pid: 690
и попытался открыть мое приложение в браузере http://0.0.0.0:5000
:
17:38:46 web.1 | 2013-09-11 10:38:46 [690] [ERROR] Error handling request
17:38:46 web.1 | Traceback (most recent call last):
17:38:46 web.1 | File "/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/gunicorn/workers/sync.py", line 131, in handle_request
17:38:46 web.1 | respiter = self.wsgi(environ, resp.start_response)
17:38:46 web.1 | File "/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/dj_static.py", line 59, in __call__
17:38:46 web.1 | return self.application(environ, start_response)
17:38:46 web.1 | File "/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 236, in __call__
17:38:46 web.1 | self.load_middleware()
17:38:46 web.1 | File "/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/django/core/handlers/base.py", line 53, in load_middleware
17:38:46 web.1 | raise exceptions.ImproperlyConfigured('Error importing middleware %s: "%s"' % (mw_module, e))
17:38:46 web.1 | ImproperlyConfigured: Error importing middleware django.contrib.auth.middleware: "dlopen(/Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/psycopg2/_psycopg.so, 2): Library not loaded: @loader_path/../lib/libssl.1.0.0.dylib
17:38:46 web.1 | Referenced from: /Users/oubiga/Envs/hellodjango_venv/lib/python2.7/site-packages/psycopg2/_psycopg.so
17:38:46 web.1 | Reason: image not found"
Этот раз, dj_database_url.config()
вернулся:
{
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'dbname',
'HOST': 'localhost',
'USER': 'dbuser',
'PASSWORD': 'dbpassword',
'PORT': 5000
}
В качестве третьей попытки:
Я установил autoenv mac-pol:~ oubiga$ pip install autoenv
Из этой кулинарной книги Кеннет Рейтц написал:
use_env() {
typeset venv
venv="$1"
if [[ "${VIRTUAL_ENV:t}" != "$venv" ]]; then
if workon | grep -q "$venv"; then
workon "$venv"
else
echo -n "Create virtualenv $venv now? (Yn) "
read answer
if [[ "$answer" == "Y" ]]; then
mkvirtualenv "$venv"
fi
fi
fi
}
в моем.bashrc файле.
я бегу $ foreman start
команда:
(hellodjango_venv)mac-pol:hellodjango_rep oubiga$ foreman start
18:11:57 web.1 | started with pid 1104
18:11:57 web.1 | 2013-09-11 18:11:57 [1104] [INFO] Starting gunicorn 18.0
18:11:57 web.1 | 2013-09-11 18:11:57 [1104] [INFO] Listening at: http://0.0.0.0:5000 (1104)
18:11:57 web.1 | 2013-09-11 18:11:57 [1104] [INFO] Using worker: sync
18:11:57 web.1 | 2013-09-11 18:11:57 [1107] [INFO] Booting worker with pid: 1107
и попытался открыть мое приложение в браузере http://0.0.0.0:5000
: Это сработало!
^CSIGINT received
18:12:06 system | sending SIGTERM to all processes
18:12:06 web.1 | 2013-09-11 11:12:06 [1107] [INFO] Worker exiting (pid: 1107)
SIGTERM received
18:12:06 web.1 | 2013-09-11 18:12:06 [1104] [INFO] Handling signal: int
18:12:06 web.1 | 2013-09-11 18:12:06 [1104] [INFO] Shutting down: Master
18:12:06 web.1 | exited with code 0
Но, dj_database_url.config()
снова возвращает пустой словарь.
В качестве последней попытки:
Мне было любопытно python manage.py runserver
Команда и я проверил это.
(hellodjango_venv)mac-pol:hellodjango_rep oubiga$ foreman run python hellodjango/manage.py runserver
Validating models...
0 errors found
September 11, 2013 - 18:42:37
Django version 1.5.2, using settings 'hellodjango.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
и попытался открыть мое приложение в браузере http://127.0.0.1:8000/
: Это не сработало!
ImportError: No module named hellodjango.urls
был поднят.
Я заменил ROOT_URLCONF = 'hellodjango.hellodjango.urls'
в моем файле settings.py ROOT_URLCONF = 'hellodjango.urls'
и это наконец сработало.
Как и ожидалось, dj_database_url.config()
вернул пустой словарь.
Так:
Теперь я чувствую себя немного ошеломленным. Боюсь, что я неправильно понимаю некоторые основные концепции здесь.
- Какой смысл использовать gunicorn вместо сервера разработки Django?
- Почему
dj_database_url.config()
иногда возвращать полностью заполненный словарь, а иногда пустой? - Можно ли вручную установить переменные среды в файле.env? Нужно ли устанавливать такие инструменты, как autoenv, heroku-config...?
Заранее спасибо.
2 ответа
Я также застрял с postgres, вот что я сделал в settings.py, чтобы добавить локальные настройки:
DATABASES = {
'default': dj_database_url.config(default='postgres://<user>:<password>@<host>/<dbname>')
}
Конечно, вы должны создать базу данных после шагов postgres. Решение было от https://discussion.heroku.com/t/dj-database-url-config-is-returning-an-empty-object/55/9
Могу помочь с третьим вопросом в вашем посте:
«Могу ли я вручную установить переменные среды в файле .env? Нужно ли мне устанавливать такие инструменты, как autoenv, heroku-config...?»
Я столкнулся с подобной путаницей при развертывании моего приложения django на героку и надеюсь, что это поможет вам или кому-то еще.
Локально:
Я использовал django-environ, чтобы установить переменные среды локально. Я установил все переменные в файле .env,
В файле settings.py я импортировал среду, добавил это в начало файла:
env = environ.Env( # set casting, default value DEBUG=(bool, False) )
а затем добавил «окружение» в список INSTALLED_APPS. Наконец, я получил переменные среды в этом формате:
'NAME': os.environ['NAME'], 'USER': os.environ['USER'], 'PASSWORD': os.environ['PASSWORD']
Удаленно:
я использовал heroku config:set SECRET_KEY='whateveryoursecretekeyis'
Если вы не уверены, какие у вас учетные данные для базы данных heroku, поскольку они отличаются от того, что вы используете локально, вы можете запустить
Для меня, как для новичка, одна проблема заключалась в том, что вам нужно быть уверенным, что любые переменные, которые вы устанавливаете в своем файле settings.py, объявляются как переменные среды локально и удаленно.
Еще одна вещь, которая может помочь вам или кому-то еще в поиске этого вопроса, заключается в том, что если бы вы были похожи на меня и сначала создали свое приложение django (имеется в виду редактирование представлений, построение моделей и т. д.), а затем начали работу по его развертыванию на героку, вы можете захотеть начните сначала, воссоздайте простое базовое приложение django (бабербоны с целевой страницей ракетного корабля) и разверните его на героку, чтобы убедиться, что конвейер работает.
Затем, после того, как вы убедитесь, что ваше приложение работает как локально, так и удаленно, и отредактировали переменные среды и настроили правильную базу данных для вашего проекта (например, может быть postgres вместо базы данных по умолчанию, которую использует django), вы можете вернуться и заполните свои модели и представления.
Надеюсь, это поможет кому-то!
Также только что заметил, что ваш procfile кажется отключенным.
Вместо:
web: gunicorn hellodjango.hellodjango.wsgi
Вы хотели бы:
web: gunicorn hellodjango.wsgi
Так как название проекта hellodjango.