Django 在部署到 Elastic Beanstalk 时看不到环境变量
Posted
技术标签:
【中文标题】Django 在部署到 Elastic Beanstalk 时看不到环境变量【英文标题】:Django doesn't see environment variables when deployed to Elastic Beanstalk 【发布时间】:2017-04-07 18:52:18 【问题描述】:我正在尝试在 Elastic Beanstalk 上设置 Django/DRF 应用程序,但无论出于何种原因,Django 都无法看到所需的环境变量。当我登录时,我可以使用
很好地看到它们$ eb ssh
$ cat /opt/python/current/env
我也可以看到,除了涉及RDS比较敏感的,直接用$eb printenv
就可以了。
所有似乎都已设置并正常工作。但是,Django 喜欢在启动时立即读取环境,而且似乎还没有设置环境变量。我已经尝试在settings.py
中简单地插入print(os.environ)
,当我这样做时,我发现了一大堆我不需要的环境变量(即'SUPERVISOR_GROUP_NAME': 'httpd'
),而我没有设置自己,比如DJ_SECRET_KEY
。
我已经更改了代码以在加载设置时报告特定环境变量的缺失,并且从最近的运行中,它生成了以下内容:
[Wed Nov 23 15:56:38.164153 2016] [:error] [pid 15708] DJ_SECRET_KEY not in environment; falling back to hardcoded value.
[Wed Nov 23 15:56:38.189717 2016] [:error] [pid 15708] RDS_DB_NAME not in environment; falling back to sqlite
[Wed Nov 23 15:56:38.189751 2016] [:error] [pid 15708] AWS_STORAGE_BUCKET_NAME not in environment; falling back to local static storage.
同样,这些变量是在设置中设置的,它们会与 EB 提供的任何其他报告工具一起显示。它们只是没有及时设置好让 Django 在启动并读取 settings.py
时读取它们。
This 看起来非常接近这个问题,但实际上并不相同:我知道在 ssh 进入 eb 实例时如何查看/加载环境变量到 shell;当我需要他们进行实际项目时,他们只是没有出现。
This 几乎正是我遇到的问题,但接受的正确答案对我来说毫无意义,投票最多的答案也不适用;这些文件已经在 git 中了。
我应该如何配置才能让 Django 看到环境变量?
【问题讨论】:
不确定 Elastic Beanstalk,但我在使用 Apache/nginx 设置 Django 项目时遇到了类似的问题。而且我必须在他们的配置文件中设置环境变量。可能在这里应该适用。 你想完成什么? @Gustaf 我正在尝试使用环境变量来配置 Django。例如,给定一个关联的 RDS 实例,EB 会自动设置几个变量,例如RDS_DB_NAME
,通过这些变量可以连接到该数据库。问题是这些变量在 Django 读取它们时没有设置。一个解决方案可能是我们可以延迟 WSGI 初始化直到环境变量全部设置的方法。它们最终都会被设置好,但显然还不够快。
我无法在此处格式化正确的评论,因此我将其作为答案。我希望它有所帮助,即使它不是您问题的确切答案。
【参考方案1】:
鉴于 EB 将所有这些环境变量作为 bash 脚本存储在规范位置,我最终只是让 bash 执行脚本,并根据解析结果更新环境。
我与settings.py
并行创建了文件get_eb_env.py
。其主要内容:
import os
import subprocess
ENV_PATH = '/opt/python/current/env'
def patch_environment(path=ENV_PATH):
"Patch the current environment, os.environ, with the contents of the specified environment file."
# mostly pulled from a very useful snippet: http://***.com/a/3505826/504550
command = ['bash', '-c', 'source path && env'.format(path=path)]
proc = subprocess.Popen(command, stdout=subprocess.PIPE, universal_newlines=True)
proc_stdout, _ = proc.communicate(timeout=5)
# proc_stdout is just a big string, not a file-like object
# we can't iterate directly over its lines.
for line in proc_stdout.splitlines():
(key, _, value) = line.partition("=")
os.environ[key] = value
然后,我只需在我的settings.py
的头部附近导入并调用patch_environment()
。
【讨论】:
这就像一个魅力。只有一件事:在我运行 python 2.7.12 的 EB 中,proc.communicate
不采用 timeout
参数。你有什么解释吗?尽管如此,你还是让我开心。
我为此运行了 Python 3.4; timeout
参数是在 Python 3.2 中引入的 IIRC。如果您在早期的 Python 中需要该功能,您可以考虑使用subprocess32 backport。
天啊,你是我的救星。现在是 2019 年,亚马逊仍然没有解决这个问题!【参考方案2】:
我解决了修改密钥“DJANGO_AWS_SECRET_ACCESS_KEY”的问题,因为 DJANGO 生成了一个带引号 (`) 的密钥并将其解释为命令。
【讨论】:
【参考方案3】:这并不是你想要的,但我希望这能解决你的问题。
我在设置中使用了很多环境变量。我认为 Elastic Beanstalk 在运行容器命令等之前设置了所有内容,然后变量不可用,这就是您的日志记录显示它们为空的原因。但是你真的需要他们那个时候的变量吗?
您不能将所需的任何本地开发设置放入 local_settings.py 并使其不受版本控制。
我们是这样使用它们的。
if 'DB_HOST' in os.environ:
DATABASES =
'default':
'ENGINE': 'django.db.backends.mysql',
'NAME': 'ebdb',
'USER': 'ebroot',
'PASSWORD': 'ebpassword',
'HOST': os.environ['DB_HOST'],
'PORT': '3306',
try:
from local_settings import *
except ImportError:
pass
它们在您运行 container_commands 时也可用:
container_commands:
01_do_something:
command: "do_something_script_$PARAM1.sh"
【讨论】:
我们确实需要环境变量。您的示例确切地说明了原因。我在settings.py
中有一些非常相似的东西,除了它回退到 Sqlite DB 而不是 localhost 上的 MySql。将此设置部署到 EB always 最终会运行 Sqlite,而不是正确连接到共享数据库。这不是我们想要的生产环境行为!
那么别无其他,我们有一个本地设置文件。让我更新我的答案。以上是关于Django 在部署到 Elastic Beanstalk 时看不到环境变量的主要内容,如果未能解决你的问题,请参考以下文章
Django 在部署到 Elastic Beanstalk 时看不到环境变量
使用 WhiteNoise 在生产模式下将 django 部署到 Elastic Beanstalk
将 Django 应用程序部署到 Amazon AWS Elastic Beanstalk 时遇到问题
在移动设备或台式计算机之间部署到 aws elastic beanstalk 的 django 网站是不是有区别?