親バカエンジニアのナレッジ帳

webのエンジニアをやっており、日頃の開発で詰まったことや書き残しておきたいことを載せています。育児のイロハという育児サイト(https://ikujip.jp)の開発も行っているため、その開発で使用されている技術についても掲載しています。

Djangoを本番環境に反映

Djangoを本番環境へデプロイ

Djangoのwebアプリケーションを開発し、いよいよ本番環境にデプロイ!というフェーズになった時、詰まることはたくさんあると思います。
あくまで私の主観ですが、Djangoは他の言語やフレームワークに比べて若干本番の環境構築など手順は多めだと思います。
備忘録として手順を残しましたので、参考にしていただければと思います。

バージョン情報は以下
Python 2.7.10
Django 1.9.6
CentOS 6.8
Apache 2.2.15
※サーバ操作はすべてrootユーザで行ってます。

本番環境設定手順

Apache関係の必要モジュールのインストール

まずは、Apacheなど必要モジュールをyumでインストールして起動させます。

yum -y install httpd httpd-devel mod_wsgi
service httpd start

ここでmod_wsgiというちょっと見慣れないモジュールが出てきましたが、これはApacheWSGIを動作させるためのモジュールです。
そもそもWSGIって何?と思われる方もいるかもしれませんが、こちらはWeb Server Gateway Interface (ウィズギー)の略で、PythonのWebアプリケーションとWebサーバを接続するためのインターフェースです。
簡単に言えば、ApachePythonのアプリケーションを動かすためにはこのモジュールが間になければいけません。

ちなみにDjangoではプロジェクトを作成した段階で、デフォルトでwsgi.pyというファイルが作成されます。
のちほどそのファイルも修正を加えることになりますが、WSGIApacheとの接続に必要なモジュールであるということを意識して手順を進めてください。

続いてchkconfigでApache自動起動設定もしておきましょう。

chkconfig httpd on
chkconfig --list | grep httpd

httpd.confの細かい設定は省きますので、必要に応じて適宜行ってください。
今回は必要最小限の設定になりますので、httpd.confは特に何も設定をしなくても大丈夫です。

WSGIの設定

以下の手順を行う前に、まずはGitやFTPを使用してDjangoのプロジェクトファイルを「/var/www/cgi-bin/」直下に配置してください。

続いて、前回までの手順でmod_wsgiをインストールしているため、「/etc/httpd/conf.d/wsgi.conf」というWSGIの設定ファイルが作成されています。
このファイルを修正しましょう。

vim /etc/httpd/conf.d/wsgi.conf
LoadModule wsgi_module modules/mod_wsgi.so

# プロジェクトのwsgi.pyのパスに合わせて設定
WSGIScriptAlias / /var/www/cgi-bin/testdir1/testdir2/wsgi.py

# Directoryはプロジェクトのパスに合わせてください
<Directory /var/www/cgi-bin/testdir1/testdir2>
Order deny,allow
Allow from all
</Directory>

Pythonのバージョンアップ

元々CentOSのサーバにはPythonの2.6.6が入っていたので、2.7.10を読み込むように設定します。

一応元のバージョンを確認してください。

python --version
Python 2.6.6

新バージョンをインストールします。

cd /usr/src
curl -O https://www.python.org/ftp/python/2.7.10/Python-2.7.10.tgz
tar zxf Python-2.7.10.tgz

展開してインストールします。

cd Python-2.7.10
./configure
make & make altinstall

そして元のバージョンをバックアップして置き換えましょう。

mv /usr/bin/python /usr/bin/python2.6.6
cp /usr/local/src/Python-2.7.10/python /usr/bin/python

そしてyumのファイルも変える必要があります。

vim /usr/bin/yum

先頭の行を以下のようにしてください。

#!/usr/bin/python2.6.6

そしてバージョンを確認します。

python --version
Python 2.7.10

これでバージョンアップは完了です。
結構手間がかかりましたね。

pipとvirtualenv

次にpipとvirtualenvのインストールです。

easy_install pip
pip install virtualenv
virtualenv ENV1
cd ENV1
. bin/activate

これでENV1環境に入れるはずなので、次にDjangoのインストールです。

pip install django==1.9.6

virtualenvのPythonを参照させる

次に「wsgi.py」を書き換えて、virtualenvのPythonを参照するようにします。

vim /var/www/cgi-bin/testdir1/testdir2(プロジェクトのパスに合わせてください)/wsgi.py
import os
 
try:
    from local_wsgi import *
except ImportError:
    import site
    import sys
 
    site.addsitedir("/root/ENV1/lib/python2.7/site-packages")
 
    sys.path.append('/var/www/cgi-bin/testdir1(ご自身のdjangoのパスに合わせてください)')
    sys.path.append('/var/www/cgi-bin/testdir1/testdir2(ご自身のdjangoのパスに合わせてください)')
 
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "プロジェクト名.settings")
 
    activate_env = os.path.expanduser("/root/ENV1/bin/activate_this.py")
    execfile(activate_env, dict(__file__=activate_env))
 
 
from django.core.wsgi import get_wsgi_application
 
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "プロジェクト名.settings")
 
application = get_wsgi_application()

※上記は開発環境と本番環境でPythonの読み込み先を変えるようにしています。
開発環境だけlocal_wsgiという空ファイルを作り、ファイルが存在していれば何もせず、存在しない場合はPythonの読み込み先を変えるようにしています。

ブラウザにアクセス、そして迷走

さあ、Apacheを再起動してブラウザにアクセスしてみましょう。

service httpd restart

...これでブラウザにアクセスすると、残念ながらApacheのエラーが出ると思います。

エラー内容を見てみましょう。
「/var/log/httpd/error_log」に記載があります。

mod_wsgi (pid=28251): Target WSGI script '/var/www/cgi-bin/test1/test2/wsgi.py' cannot be loaded as Python module.
mod_wsgi (pid=28251): Exception occurred processing WSGI script '/var/www/cgi-bin/test1/test2/wsgi.py'.
Traceback (most recent call last):
  File "/var/www/cgi-bin/test1/test2/wsgi.py", line 22, in <module>
    execfile(activate_env, dict(__file__=activate_env))
IOError: [Errno 13] Permission denied: '/root/ENV1/bin/activate_this.py'

どうやら「/root/ENV1/bin/activate_this.py」に権限がないらしい。

色々試して「activate_this.py」にだけ755権限の権限を与えてもダメでした。
ディレクトリごとに権限を与える必要があるようです。
やりたくないですがrootに755の権限を与えてみました。
root直下に作らなきゃよかったな...

chmod 755 /root

再度アクセスするとまたエラーが...
今度のエラー内容は下記のものでした。

mod_wsgi (pid=28294): Target WSGI script '/var/www/cgi-bin/test1/test2/wsgi.py' cannot be loaded as Python module.
mod_wsgi (pid=28294): Exception occurred processing WSGI script '/var/www/cgi-bin/test1/test2/wsgi.py'.
Traceback (most recent call last):
  File "/var/www/cgi-bin/test1/test2/wsgi.py", line 25, in <module>
    from django.core.wsgi import get_wsgi_application
  File "/root/ENV1/lib/python2.7/site-packages/django/__init__.py", line 1, in <module>
    from django.utils.version import get_version
  File "/root/ENV1/lib/python2.7/site-packages/django/utils/version.py", line 7, in <module>
    from django.utils.lru_cache import lru_cache
  File "/root/ENV1/lib/python2.7/site-packages/django/utils/lru_cache.py", line 28
     fasttypes = {int, str, frozenset, type(None)},
                     ^
 SyntaxError: invalid syntax

シンタックスエラーが出ているのですが、これはPythonのバージョンが2.7でない時に発生するようです。

あれ?ちゃんと2.7を読み込んでるはずなのになんでろう...
本当に2.6の方を読み込んでるの?と疑問に思い、Djangoソースコードに以下の一文を入れました。

print(sys.version_info)

wsgi.py」に入れると良いと思います。

これで実行し、再度エラーログを見ると以下の一文が...

[error] (2, 6, 6, 'final', 0)

確かに旧バージョンを読み込んでいました。
「mod_wsgi」が旧バージョンの方を見ているらしく、再度コンパイルをしても直らず...
こちらの対応が一番時間がかかりました。
結果的には一度mod_wsgiをアンインストールし、再度入れ直してコンパイルすることで直りました。

ではmod_wsgiをアンインストールします。

yum remove mod_wsgi

この時点で「/etc/httpd/conf.d/wsgi.conf」は「/etc/httpd/conf.d/wsgi.conf.rpmsave」に変更されます。

mod_wsgiをインストールして展開してください。

cd /usr/src
wget https://github.com/GrahamDumpleton/mod_wsgi/archive/4.2.8.tar.gz -O mod_wsgi-4.2.8.tar.gz
tar xzf mod_wsgi-4.2.8.tar.gz
cd mod_wsgi-4.2.8
./configure --with-python=/usr/local/bin/python2.7
make & make install

コンパイルが終わったら、
wsgi.confを元に戻しましょう。

cd /etc/httpd/conf.d/
cp wsgi.conf.rpmsave wsgi.conf

これでブラウザにアクセスすると、また別なエラーが!
「Bad Request (400)」と表示されます。
あと一息。

settings.pyのALLOWED_HOSTSでアクセス制限をかけていないでしょうか。
もしかけている場合は、

ALLOWED_HOSTS = ['ドメイン名']

としてみてください。
私はそれで上手く表示されました。

まとめ

いやー、サーバで表示させるだけで大変でした。
まだDjangoは静的ファイルの扱いとかデータベースの設定もあるのに最初にこんなに詰まるとは。

本番環境へのデプロイで詰まった場合、以下の点を確認すると大抵うまくいくと思います。

  • 仮想環境(virtualenv)を用意した場合、プロジェクトのWSGIがvirtualenvを向いているか
  • サーバのPythonのバージョンを変えた場合、プロジェクトが新バージョンを向いているか
  • プロジェクトが設置されているディレクトリに読み込み可能な権限が付加されているか

でもまぁ、Djangoの実行の流れはわかったから今後は大丈夫かな。

基礎から学ぶ Django

基礎から学ぶ Django

  • 作者: 関根裕紀,新井正貴
  • 出版社/メーカー: シーアンドアール研究所
  • 発売日: 2018/09/19
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る