django - 将环境变量中的 Django SECRET_KEY 传递给 Dockerized gunicorn

标签 django docker environment-variables gunicorn secret-key

一些背景

最近我遇到了一个问题,尽管 DJANGO_SETTINGS_MODULE 被设置为不同的设置文件,但我的 Django 应用程序仍在使用基本设置文件。原来问题是gunicorn没有继承环境变量,解决办法是添加-e DJANGO_SETTINGS_MODULE=sasite.settings.production到我调用 gunicorn 的 Dockerfile CMD 条目。

问题

我在处理应用程序中的 SECRET_KEY 时遇到了问题。我将它设置在一个环境变量中,虽然我以前将它存储在一个 JSON 文件中,但这似乎不太安全(如果我错了,请纠正我)。

问题的另一部分是,在使用 gunicorn 时,它不会继承通常在容器上设置的环境变量。如上所述,我在 DJANGO_SETTINGS_MODULE 中遇到了这个问题。我想 gunicorn 也会有 SECRET_KEY 的问题。解决这个问题的方法是什么?

我目前的做法

我在环境变量中设置了 SECRET_KEY 并将其加载到 django 设置文件中。我在包含 export SECRET_KEY=<secretkey> 的文件“app-env”中设置值,Dockerfile 包含 RUN source app-env为了在容器中设置环境变量。

后续问题

使用 Dockerfile 命令 ENV 设置环境变量 SECRET_KEY 而不是获取文件会更好吗?在这样的 Dockerfile 中对 key 进行硬编码是否可以接受(对我来说似乎不是这样)?

在 Dockerized 应用程序中处理 key 是否有“最佳实践”?

如果结果证明它与环境变量一样安全,我总是可以回到 JSON。但是弄清楚人们如何处理 SECRET_KEY 和 gunicorn 的环境变量问题仍然会很好。

代码

这是 Dockerfile:

FROM python:3.6
LABEL maintainer x@x.com

ARG requirements=requirements/production.txt
ENV DJANGO_SETTINGS_MODULE=sasite.settings.production_test

WORKDIR /app

COPY manage.py /app/
COPY requirements/ /app/requirements/ 

RUN pip install -r $requirements

COPY config config
COPY sasite sasite
COPY templates templates
COPY logs logs
COPY scripts scripts

RUN source app-env

EXPOSE 8001

CMD ["/usr/local/bin/gunicorn", "--config", "config/gunicorn.conf", "--log-config", "config/logging.conf", "-e", "DJANGO_SETTINGS_MODULE=sasite.settings.production_test", "-w", "4", "-b", "0.0.0.0:8001", "sasite.wsgi:application"]

最佳答案

我将从为什么它不能按原样工作开始,然后讨论您必须继续前进的选项:

在容器的构建过程中,单个 RUN 指令作为其自己的独立容器运行。对于后续层,仅捕获对该容器写入层的文件系统的更改。这意味着您的 source app-env命令运行并退出,并且可能不会对磁盘​​进行任何更改,从而使该 RUN 行成为空操作。

Docker 允许您在构建时使用 ENV 指令指定环境变量,您已使用 DJANGO_SETTINGS_MODULE 变量完成此操作。我不一定同意 SECRET_KEY 应该在此处指定,尽管在 Dockerfile 中放置开发所需的值可能没问题。

SECRET_KEY对于不同的环境(暂存和生产),变量可能会有所不同,那么在运行时设置该变量可能是有意义的。例如:

docker run -d -e SECRET_KEY=supersecretkey mydjangoproject
-e选项是 --env 的缩写.此外,还有 --env-file您可以传入一个包含变量和值的文件。如果您不使用 docker cli 直接,那么您的 docker 客户端也应该能够在那里指定这些(例如 docker-compose 允许您在 yaml 中指定这两个)

在这种特定情况下,由于容器内有一些东西知道需要哪些变量,因此可以在运行时调用它。有两种方法可以实现这一点。首先是将CMD改成这样:
CMD source app-env && /usr/local/bin/gunicorn --config config/gunicorn.conf --log-config config/logging.conf -e DJANGO_SETTINGS_MODULE=sasite.settings.production_test -w 4 -b 0.0.0.0:8001 sasite.wsgi:application

这使用了 CMD 的 shell 封装语法,而不是 exec 语法。这意味着 CMD 的整个参数将在/bin/sh -c ""中运行

shell 将处理运行 source app-env然后你的 gunicorn 命令。

如果您需要在运行时更改命令,您需要记住指定 source app-env &&在需要的地方,这让我想到了另一种方法,即使用 ENTRYPOINT 脚本

Docker 中的 ENTRYPOINT 功能允许您在容器首次启动时处理任何必要的启动步骤。考虑以下入口点脚本:
#!/bin/bash
cd /app && source app-env && cd - && exec "$@"

这将明确地 cd 到 app-env 所在的位置,获取它,cd 回到 oldpwd 所在的位置,然后执行命令。现在,您可以在运行时覆盖此图像的命令和工作目录,并使 app-env 文件中指定的任何变量处于事件状态。要使用此脚本,您需要将它添加到镜像中的某个位置并确保它是可执行的,然后使用 ENTRYPOINT 指令在 Dockerfile 中指定它:
ADD entrypoint.sh /entrypoint.sh
RUN chmod a+x /entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]

使用入口点策略,您可以保持 CMD 不变,而无需更改它。

关于django - 将环境变量中的 Django SECRET_KEY 传递给 Dockerized gunicorn,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53564333/

相关文章:

ruby-on-rails - 我如何在Rails应用程序中看到ENV变量?

python - Django 获取客户端的域名/主机名

python - Django ImportError : No module named tango_with_django_project. 设置

c# - Ubuntu 服务器上 Azure Docker 上的 ASP.NET 5

mysql - 使用 Node+MySql Docker 容器登录注册表单

c++ - qt creator可以使用环境变量吗?

python - Django-Simple-Captcha 添加CSS

python - 如何在 Django 中大规模管理 View 、URL 和模型?

docker - Docker在生产中

log4net - 如果运行某台机器,将 Log4Net 配置为不使用 smtp appender