【问题标题】:How can I detect Heroku's environment?如何检测 Heroku 的环境?
【发布时间】:2012-03-12 02:40:03
【问题描述】:

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

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

【问题讨论】:

    标签: python django deployment heroku environment


    【解决方案1】:

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

    • Heroku 实例都具有路径 /app - 正在运行的文件和脚本也将在此路径下,因此您可以检查目录是否存在和/或脚本是否从以下路径运行它。

    • 有一个空目录/etc/heroku

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

    其中任何一个都可以而且可能随时改变

    您的里程可能会有所不同

    【讨论】:

      【解决方案2】:

      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 这样记录在案。

      【讨论】:

      • @Downvoters 请解释一下,以便我学习和改进信息 ;-)
      • 环境变量DATABASE_URL 变得越来越普遍,并且不仅仅由 Heroku 使用。随着时间的推移,它越来越不可能准确。
      【解决方案3】:

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

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

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

      【讨论】:

      • 谢谢,我还没有注意到您可以这样设置环境变量。这似乎是正确的做法。
      • 快捷方式:on_heroku = 'DYNO' in os.environ
      • 不要按照 tincho 的建议在 os.environ 中使用 on_heroku = 'DYNO'。在某些 buildpack 操作期间未设置该环境变量,例如当 collectstatic 自动运行 django 构建时。这几乎是不可能调试的——你最好使用上述解决方案。
      • os.environ.get('YOUR_ENV_VAR') 不是建议的检查环境变量是否存在的方法吗?
      【解决方案4】:

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

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

      我看到有些人使用if 'PORT' in os.environ:,但不幸的是,当您在本地运行foreman start 时,PORT 变量存在,因此无法区分使用工头进行本地测试和在 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
      

      【讨论】:

      • 为了安全起见,如果您确实这样做,默认情况下您可能应该是DEBUG=False。可能是DEBUG=False; if not 'DYNO' in os.environ: debug=True 之类的?
      【解决方案5】:

      短版:检查时区是否为 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
      

      【讨论】:

        【解决方案6】:

        首先在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
        

        【讨论】:

        • 我更喜欢DYNO 解决方案(或在Web UI 上设置,而不是config:set),因为这也是heroku local 上的True,这意味着我们不能使用它测试是否在本地主机上运行。
        • @OllieFord 我在heroku local 上没有得到DYNO,所以我不得不在我的.env 中明确添加DYNO=Dummy(任何值都可以,因为我们只检查是否存在环境变量)
        【解决方案7】:

        在此处了解更多信息:https://devcenter.heroku.com/articles/config-vars

        我的解决方案:

        $ heroku config:set HEROKU=1
        

        这些环境变量是持久的——它们会在部署和应用重启时保持不变——所以除非你需要更改值,否则你只需要设置一次。

        然后你可以在你的应用中测试它的存在。:

        >>> 'HEROKU' in os.environ
        True
        

        【讨论】:

        • 简单而有效:)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-18
        • 2016-03-31
        • 2015-01-01
        相关资源
        最近更新 更多