如何检测Heroku的环境?

问题描述 投票:0回答:8

我有一个 Django Web 应用程序,我想检查它是否在 Heroku 堆栈上运行(用于有条件启用调试等)有没有简单的方法可以做到这一点?也许是环境变量?

我知道我也可以用另一种方式来做——也就是说,让它检测它是否在开发人员机器上运行,但这“听起来不对”。

python django deployment heroku environment
8个回答
27
投票

ENV var 似乎是最明显的方法。要么查找您知道存在的 ENV 变量,要么设置您自己的:

on_heroku = False
if 'YOUR_ENV_VAR' in os.environ:
  on_heroku = True

更多信息请访问:http://devcenter.heroku.com/articles/config-vars


19
投票

与尼尔的建议类似,我会执行以下操作:

debug = True
if 'SOME_ENV_VAR' in os.environ:
    debug = False

我见过有些人使用

if 'PORT' in os.environ:
但不幸的是,当你在本地运行
foreman start
时,PORT 变量是存在的,因此无法区分使用 foreman 进行本地测试和在 Heroku 上进行部署。

我还建议使用以下环境变量之一:

  1. Heroku 开箱即用(而不是您自己设置和检查)
  2. 在您当地的环境中不太可能找到

在发布之日,Heroku 有以下环境变量:

['PATH', 'PS1', 'COLUMNS', 'TERM', 'PORT', 'LINES', 'LANG', 'SHLVL', 'LIBRARY_PATH', 'PWD', 'LD_LIBRARY_PATH', 'PYTHONPATH', 'DYNO', 'PYTHONHASHSEED', 'PYTHONUNBUFFERED', 'PYTHONHOME', 'HOME', '_']

我通常会选择

if 'DYNO' in os.environ:
,因为它似乎是 Heroku 最具特色的(还有谁会使用术语 dyno,对吧?)。

而且我也更喜欢将其格式化为 if-else 语句,因为它更明确:

if 'DYNO' in os.environ:
    debug = False
else:
    debug = True

16
投票

首先在heroku上设置环境变量

ON_HEROKU

$ heroku config:set ON_HEROKU=1

然后在

settings.py

import os

# define if on heroku environment
ON_HEROKU = 'ON_HEROKU' in os.environ

3
投票

在这里阅读更多相关信息:https://devcenter.heroku.com/articles/config-vars

我的解决方案:

$ heroku config:set HEROKU=1

这些环境变量是持久的 - 它们将在部署和应用程序重新启动时保持不变 - 因此除非您需要更改值,否则您只需设置一次。

然后您可以测试它在您的应用程序中的存在。:

>>> 'HEROKU' in os.environ
True

2
投票

最可靠的方法是如上所述设置环境变量。 如果这是不可能的,您可以在文件系统中查找一些迹象,但它们可能不是/不是万无一失的

  • Heroku 实例都具有路径

    /app
    - 正在运行的文件和脚本也将位于该路径下,因此您可以检查该目录是否存在和/或脚本是否正在从该目录下运行。

  • 有一个空目录

    /etc/heroku

  • /etc/hosts
    可能添加了一些与heroku相关的域
    
    ~ $ cat /etc/hosts
    <snip>.dyno.rt.heroku.com
    

其中任何一个都可能随时发生变化

您的里程可能会有所不同


1
投票

DATABASE_URL
环境变量

in_heroku = False
if 'DATABASE_URL' in os.environ:
    in_heroku = True

我认为您需要为您的应用程序启用数据库:

heroku addons:create heroku-postgresql:hobby-dev

但它是免费的,而且很可能你无论如何都会做。

Heroku 在运行其应用程序时提供此环境变量,特别是用作:

import dj_database_url
if in_heroku:
    DATABASES = {'default': dj_database_url.config()}
else:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        }
    }

并非万无一失,因为该变量可能是在本地定义的,但对于简单的情况来说很方便。

heroku run env

还可能显示其他可能的变量,例如:

  • DYNO_RAM
  • WEB_CONCURRENCY

但我不确定这些是否有像

DATABASE_URL
这样的记录。


0
投票

简短版本:检查时区是否为UTC/GMT:

if not 'ORIGINAL_TIMEZONE' in os.environ:
    f = os.popen('date +%Z')
    tz = f.read().upper()
    os.environ['ORIGINAL_TIMEZONE']=tz


tz = os.environ['ORIGINAL_TIMEZONE']
if tz != '' and (not 'utc' in tz.lower()) and (not 'gmt' in tz.lower()):
    print 'Definitely not running on Heroku (or in production in general)'
else:
    print 'Assume that we are running on Heroku (or in production in general)'

这比

if tz=='UTC\n'
更保守:如果有疑问,请假设我们正在生产。请注意,我们将时区保存到环境变量中,因为
settings.py
可能会执行多次。事实上,开发服务器执行了两次,第二次系统时区已经是“UTC”(或者
settings.TIMEZONE
中的任何内容)。

长版:

绝对确保我们永远不会使用

DEBUG=True
在 Heroku 上运行,并且即使使用
DEBUG=False
,我们也不会在 Heroku 上运行开发服务器。来自
settings.py

RUNNING_DEV_SERVER = (len(sys.argv) > 1) and (sys.argv[1] == 'runserver')

DEBUG = RUNNING_DEV_SERVER

TEMPLATE_DEBUG = DEBUG

# Detect the timezone
if not 'ORIGINAL_TIMEZONE' in os.environ:
    f = os.popen('date +%Z')
    tz = f.read().upper()
    os.environ['ORIGINAL_TIMEZONE']=tz
    print ('DEBUG: %d, RUNNING_DEV_SERVER: %d, system timezone: %s ' % (DEBUG, RUNNING_DEV_SERVER, tz))


if not (DEBUG or RUNNING_DEV_SERVER):
    SECRET_KEY = os.environ['SECRET_KEY']
else:
    print 'Running in DEBUG MODE! Hope this is not in production!'

    SECRET_KEY = 'DEBUG_INSECURE_SECRET_KEY_ae$kh(7b%$+a fcw_bdnzl#)$t88x7h2-p%eg_ei5m=w&2p-)1+'

    # But what if we are idiots and are still somehow running with DEBUG=True in production?!
    # 1. Make sure SECRET_KEY is not set
    assert not SECRET_KEY in os.environ
    # 2. Make sure the timezone is not UTC or GMT (indicating production)

    tz = os.environ['ORIGINAL_TIMEZONE']
    assert tz != '' and (not 'UTC' in tz) and (not 'GMT' in tz)

    # 3. Look for environment variables suggesting we are in PROD
    for key in os.environ:
        for red_flag in ['heroku', 'amazon', 'aws', 'prod', 'gondor']:
            assert not red_flag in key.lower()
            assert not red_flag in os.environ[key].lower()

如果您确实想在 Heroku 上运行开发服务器,我建议您添加一个环境变量,指定可以执行此操作的日期。然后仅当该日期是今天时才继续。这样,您必须在开始开发工作之前更改此变量,但如果您忘记取消设置它,第二天您仍然可以防止在生产中意外运行它。当然,如果您想超级保守,您也可以指定例外情况时的 1 小时窗口。

最后,如果您决定采用上面建议的方法,那么同时安装 django-security,将

djangosecurity
添加到
INSTALLED_APPS
,然后添加到
settings.py
的末尾:

if not (DEBUG or RUNNING_DEV_SERVER):
    ### Security
    SECURE_SSL_REDIRECT = True
    SECURE_CONTENT_TYPE_NOSNIFF = True

    SECURE_HSTS_SECONDS = 86400000
    SECURE_HSTS_INCLUDE_SUBDOMAINS = True
    SECURE_BROWSER_XSS_FILTER = True

    SESSION_COOKIE_SECURE = True
    SESSION_COOKIE_HTTPONLY = True
    CSRF_COOKIE_HTTPONLY = True # May have problems with Ajax
    CSRF_COOKIE_SECURE = True

0
投票

无需设置自己的配置变量。

这里使用的最好的一个是

$DYNO
。它已记录在案,并且始终由 Heroku 在构建时和运行时设置。

Heroku Labs Dyno Metadata提供了一些其他选项,但它们仅在 Dyno Metadata 打开时设置。)

© www.soinside.com 2019 - 2024. All rights reserved.