Развертывание приложения 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.

Другие вопросы по тегам