将环境变量中的 Django SECRET_KEY 传递给 Dockerized gunicorn
Posted
技术标签:
【中文标题】将环境变量中的 Django SECRET_KEY 传递给 Dockerized gunicorn【英文标题】:Pass Django SECRET_KEY in Environment Variable to Dockerized gunicorn 【发布时间】:2019-05-03 00:15:06 【问题描述】:一些背景
最近我遇到了一个问题,即尽管 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 中硬编码密钥是否可以接受(似乎对我来说不是)?
是否有在 Dockerized 应用程序中处理密钥的“最佳实践”?
如果事实证明它与环境变量一样安全,我总是可以返回 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"]
【问题讨论】:
【参考方案1】:我将从为什么它不能按原样工作开始,然后讨论你必须继续前进的选项:
在容器的构建过程中,一条 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 不变而无需更改它。
【讨论】:
你会说这样设置我的secret_key 比我以前的JSON 方法更好吗?另外,正如我所提到的,在使用 docker 的 ENV 命令为 DJANGO_SETTINGS_MODULE 设置环境变量时,我遇到了 gunicorn 的问题。这个问题会以同样的方式影响我在这里使用 secret_key 吗? 您似乎在两个地方指定了 DJANGO_SETTINGS_MODULE。我不知道当你遇到这个问题时你的东西是什么样子的,但是 Docker 肯定会为容器化进程设置环境变量。 因为这个问题,我现在将它设置在两个地方哈哈。在它不在 CMD 中之前,django 正在运行基本设置文件而不是环境变量中的那个。 gunicorn 没有从容器继承值。以上是关于将环境变量中的 Django SECRET_KEY 传递给 Dockerized gunicorn的主要内容,如果未能解决你的问题,请参考以下文章
使用加密的 SECRET_KEY 作为环境变量的 GitHub Actions 不起作用
尽管 SECRET_KEY 错误,但部署在 Heroku 上的 Django 应用程序仍然有效