読者です 読者をやめる 読者になる 読者になる

orangain flavor

じっくりコトコト煮込んだみかん2。知らないことを知りたい。

HerokuにDjangoアプリケーションをデプロイしてもcollectstaticが実行されないことがある

heroku django

【2014年6月3日追記】この後、ビルド時にデフォルトで環境変数を参照できるようになったため、現在この問題は発生しません。 user-env-compileも廃止されました。

See: App environment available in all builds | Heroku Dev Center

はじめに

Heroku では、Djangoの静的ファイル(画像・CSS・JSなど)をサーブするために、dj-static を使うようガイドがあります。大規模なアプリケーションであればCDNの利用を検討するべきですが、ある程度までは問題ないようです。

Getting Started with Django on Heroku | Heroku Dev Center

しかし、python manage.py collectstatic の実行にconfig(環境変数)の値を必要とする場合、デプロイ時にcollectstaticが実行されないことがあります。

この条件に当てはまると、静的ファイルがサーブされず画像が表示されないといった問題が起こります。

問題が起きたケース

settings.py に以下のように書いたらこの問題が発生しました。

import os
SECRET_KEY = os.environ.get('SECRET_KEY') 

これは、秘密にすべきSECRET_KEYの値をソースコードリポジトリに格納せず、代わりにconfig(環境変数)を使うというTwelve-Factor Appでも推奨されている方法 です。

このプロジェクトをデプロイすると以下のようになり、特にエラーも出ないままcollectstaticが実行されませんでした。

$ git push heroku master
Fetching repository, done.
Counting objects: 7, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 350 bytes, done.
Total 4 (delta 3), reused 0 (delta 0)

-----> Python app detected
-----> No runtime.txt provided; assuming python-2.7.4.
-----> Using Python runtime (python-2.7.4)
-----> Installing dependencies using Pip (1.3.1)
       Cleaning up...

-----> Discovering process types
       Procfile declares types -> web

-----> Compressing... done, 32.9MB
-----> Launching... done, v12
http://xxxxx.herokuapp.com deployed to Heroku

To git@heroku.com:xxxxx.git
   xxxxxx..yyyyyy master -> master

なお、使用したDjangoのバージョンは1.6.1、HerokuのStackはCedarです。

原因

この問題は、以下の理由が複合して発生します。

  • Herokuへのデプロイ時にはconfig(環境変数)の値を参照できない。
  • SECRET_KEYが空だとINSTALLED_APPSに列挙されたアプリケーションのインポートに失敗するため、Djangoのコアに含まれないコマンドは実行できない。
  •  Herokuへのデプロイ時にcollectstaticのdry-runが失敗すると、エラーを出すことなくcollectstaticの実行はスキップされる。

Herokuのドキュメントでも以下のように書いてありました。

 Normally, application configuration isn’t available when your application is being compiled. This can be a problem with, for example, using collectstatic to upload files to S3 with Django-Storages.

If your application needs access to runtime configuration during the build, you can turn it on with user-env-compile:

Django and Static Assets | Heroku Dev Center

対策

上で引用したドキュメントにあるように、以下のコマンドを実行すると解決します。このコマンドを実行すると、デプロイ時にconfig(環境変数)の値を参照できるようになります。

heroku labs:enable user-env-compile

なお、これは実験的な機能 のため将来使えなくなるかもしれません。

まとめ

Herokuのデフォルトの設定では、デプロイ時にconfig(環境変数)を参照できず、問題が起きる可能性があります。自分でBuildpack を書く場合などにも気をつける必要があります。

なお、Herokuのファイルシステム では、デプロイ後に書き込んだファイルは書き込んだプロセスからしか見えません。このため、手動でheroku run python manage.py collectstaticを実行しても、Webサーバーのプロセスからは見えないため効果がありません。

余談ですが、dj-staticが依存する static はPython 3に対応していないため、Herokuがガイドする方法はPython 3では動きません。対応しようとする動き はありますが、難しいみたいです。今後HerokuにおけるPython/Djangoのサポート状況がもう少し良くなることを期待したいです。

参考サイト