在 cloudControl 部署中调试 Django `collectstatic` 时出现问题

Problems debugging Django `collectstatic` in a cloudControl deployment

我有一个部署到 cloudControl 的 Django 应用程序。配置是标准的,push/deploy 没有(明显的)错误发生。

但是 collectstatic step 没有被执行:它默默地失败了(我没有看到 -----> Collecting static files 消息)。部署后,应用程序的静态文件夹为空,因此您不断收到 500 个服务器错误。

我可以通过更改Procfile来解决它,但它也不一致:

web: python manage.py collectstatic --noinput; gunicorn app.wsgi:application --config gunicorn_cnf.py --bind 0.0.0.0:${PORT:-5000}`

collectstatic 在本地正常工作,如果我 运行 cctrlapp app/deployment run "python manage.py collectstatic --noinput" 也没有显示任何错误:

669 static files copied to '/srv/www/staticfiles/static', 669 post-processed.

但是/srv/www/staticfiles/static是空的。


我怎么知道为什么在推送阶段没有执行 collectstatic?

我已经能够使用 custom python buildpack 调试问题,所以这里是答案以供进一步参考。

问题出在 settings.py 文件中。我在这个文件中做的第一件事是检查我们是在 cloudControl 环境中还是在本地环境中。我这样做是为了寻找 CRED_FILE 环境变量(与 what is suggested 没有太大区别):如果没有找到变量,我会加载一个本地 JSON 文件,该文件模仿用于开发的凭据变量:

try:
    cred_file = os.environ['CRED_FILE']
    DEBUG = False

except KeyError:
    cred_file = os.path.join(BASE_DIR, 'creds.json')
    DEBUG = True

了解环境后,我可以有不同的 INSTALLED_APPSrequirements.txt 文件在生产和开发中也略有不同)或更改一些设置。

现在有个坏消息:在推送阶段没有 CRED_FILE 可用。

所以我试图加载未安装的应用程序(因为它们仅在开发要求文件中,如 coveragedjango-debug-toolbar)或使用未设置的凭据(creds.json 当然不会上传到存储库:仅上传带有虚拟值的 TXT 作为参考)。这就是为什么 collectstatic 在推送阶段默默失败的原因。

这是我的解决方案(只要您的存储库中有虚拟凭据文件,它就会起作用):

try:
    cred_file = os.environ['CRED_FILE']
    DEBUG = False

except KeyError:
    if os.path.exists(os.path.join(BASE_DIR, 'creds.json')):
        cred_file = os.path.join(BASE_DIR, 'creds.json')
        DEBUG = True
    else:
        cred_file = os.path.join(BASE_DIR, 'creds.json.txt')
        DEBUG = False

collectstatic 不使用凭据,因此您可以在 creds.json.txt 文件中包含任何内容。不是很干净,但现在可以按预期工作了。


编辑

正如@pst 在评论中指出的那样,有一个环境变量可以知道构建包是否为 运行,因此我们也可以使用该变量来加载所需的凭据并设置 DEBUG

if 'CRED_FILE' in os.environ:
    cred_file = os.environ['CRED_FILE']
    DEBUG = False

elif 'BUILDPACK_RUNNING' in os.environ:
    cred_file = os.path.join(BASE_DIR, 'creds.json.txt') 
    DEBUG = False

else:
    cred_file = os.path.join(BASE_DIR, 'creds.json')
    DEBUG = True