【问题标题】:How to pass shell environment variable to Supervisor program?如何将 shell 环境变量传递给 Supervisor 程序?
【发布时间】:2018-02-04 18:46:54
【问题描述】:

我有一个在 Gunicorn 上运行的 Django 应用程序,由 Ansible 管理的 SupervisorD 管理。

我希望 Django 从环境中读取 DJANGO_SECRET_KEY 变量,因为我不想将我的密钥存储在配置文件或 VCS 中。为此,我从settings.py 的环境中读取了密钥:

SECRET_KEY = os.environ['DJANGO_SECRET_KEY']

看着Supervisor docs 它说:

注意子进程将继承用于启动“supervisord”的shell的环境变量,除了这里被覆盖的那些。请参阅子流程环境。

这是我的supervisor.conf

[program:gunicorn]
command=/.../.virtualenvs/homepage/bin/gunicorn homepage.wsgi -w 1 --bind localhost:8001 --pid /tmp/gunicorn.pid
directory=/.../http/homepage

当我设置变量并从 shell 运行 Gunicorn 命令时,它启动得很好:

$ DJANGO_SECRET_KEY=XXX /.../.virtualenvs/homepage/bin/gunicorn homepage.wsgi -w 1 --bind localhost:8001 --pid /tmp/gunicorn.pid

但是,当我在 shell 中设置变量并重新启动 Supervisor 服务时,我的应用程序无法启动,并出现关于未找到变量的错误:

$ DJANGO_SECRET_KEY=XXX supervisorctl restart gunicorn
gunicorn: ERROR (not running)
gunicorn: ERROR (spawn error)

查看 Supervisor 错误日志:

  File "/.../http/homepage/homepage/settings.py", line 21, in <module>
    SECRET_KEY = os.environ['DJANGO_SECRET_KEY']
  File "/.../.virtualenvs/homepage/lib/python2.7/UserDict.py", line 40, in __getitem__
    raise KeyError(key)
KeyError: 'DJANGO_SECRET_KEY'
[2017-08-27 08:22:09 +0000] [19353] [INFO] Worker exiting (pid: 19353)
[2017-08-27 08:22:09 +0000] [19349] [INFO] Shutting down: Master
[2017-08-27 08:22:09 +0000] [19349] [INFO] Reason: Worker failed to boot.

我也试过重启supervisor服务,还是出现同样的错误:

$ DJANGO_SECRET_KEY=XXX systemctl restart supervisor
...
INFO exited: gunicorn (exit status 3; not expected)

我的问题是如何让 Supervisor 将环境变量“传递”给它的子进程?

【问题讨论】:

  • 这完全是错误的方式。主管不在您的用户 ID 下运行。您应该在主管配置中设置变量,而不是相反。
  • @DanielRoseman 我在 VCS 中有我的主管配置,所以我无法将我的密钥放入其中。
  • 读取DJANGO_SECRET_KEY 环境变量与主管配置无关。不知道你是怎么做的,但你可以使用os.environ.get('DJANGO_SECRET_KEY') 在我们的 django 设置文件中赋值。你也可以使用像django-environ这样的包。
  • @demonno 我已经在 Django 的 settings.py 中有 os.environ.get('DJANGO_SECRET_KEY')。问题是 Gunicorn 进程从 Supervisor 启动时未设置此变量。

标签: django ansible environment-variables supervisord secret-key


【解决方案1】:

创建与此类似的可执行文件并尝试手动启动它。 即在/home/user/start_django.sh下方创建文件并复制脚本

您需要填写DJANGODIR并根据您的情况进行其他调整。此外,您可能需要相应地调整权限。

#!/bin/bash

DJANGODIR=/.../.../..
ENVBIN=/.../.virtualenvs/homepage/bin/bin

# Activate the virtual environment
cd $DJANGODIR
source $ENVBIN/activate

DJANGO_SECRET_KEY=XXX
#define other env variables if you need

# Start your Django
exec gunicorn homepage.wsgi -w 1 --bind localhost:8001 --pid /tmp/gunicorn.pid

如果它是手动启动的,那么只需在你的 conf 中使用这个文件。

[program:django_project]
command = /home/user/start_django.sh
user = {your user}
stdout_logfile = /var/log/django.log
redirect_stderr = true
# you can also try to define enviroment variables in this conf
environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8,DJANGO_SECRET_KEY=XXX

可能有用的参考资料,

【讨论】:

  • 嗯,那我该如何管理start_django.sh?我不能把它放在版本控制中,因为它包含一个密钥。我本可以轻松地将我的密钥放入settings.pysupervisor.conf,但问题是这些文件也受版本控制。
  • 我认为可以在提议的 bash 脚本中添加一行,该脚本从外部文件导出 env 变量(版本控制未跟踪)。但我个人更喜欢使用django-environ,它可以配置为从.env文件中读取所有变量。
【解决方案2】:

好吧,我自己想通了。原来 ansible 有一个叫做 Vault 的功能,它正是用于这种工作 - 加密密钥。

现在我将保管的密钥添加到 ansible 的 host_vars,请参阅: Vault: single encrypted variableInventory: Splitting out host and group specific data

我在我的 ansible playbook 中添加了一个任务,将密钥文件从 ansible vault 复制到服务器:

- name: copy django secret key to server
  copy: content="{{ django_secret_key }}" dest=/.../http/homepage/deploy/django_secret_key.txt mode=0600

并让 Django 从该文件中读取秘密:

with open(os.path.join(BASE_DIR, 'deploy', 'django_secret_key.txt')) as secret_key_file:
    SECRET_KEY = secret_key_file.read().strip()

如果有人有更简单/更好的解决方案,请发布,我会接受它作为答案。

【讨论】:

    猜你喜欢
    • 2017-03-06
    • 2017-05-02
    • 2013-11-08
    • 2016-07-31
    • 1970-01-01
    • 2013-12-29
    • 2016-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多