Django

Ubuntu 環境へ Django で作った WEB アプリケーションをデプロイする ③【APサーバ】

上記の記事の続きです。

前回は VPS の中に Nginx を使用して Web サーバを構築し、リクエストを送るとレスポンスが返ってくるところまで行いました。

WEB 3層構成

目的は題名の通り、Django で作った WEB アプリケーションを VPS で公開することです。

そのためには下記のような WEB 3層構成(WEB 3層構造)を構築していきます。

下の段にある Webサーバ・APサーバ・DBサーバそれぞれが別の種類のサーバです。

サーバとはリクエストに対してレスポンスを返すものでした。

これら3つはそれぞれ別の種類のリクエストを受け取り、
別の種類のレスポンスを返します。

Web サーバNginx, Apache静的ページを扱う
AP サーバDjango, Laravel, Ruby on Rails動的ページを扱う
DB サーバMySQL, SQLite, MariaDB, PostgreSQLデータベースの管理

動的ページとは、同じ URL なのに見る人で違う内容が表示されるものです。
例えば Twitter のタイムライン。
タイムラインのページは全員同じ https://twitter.com/home です。
URL は同じですが、アカウント毎に表示が違います。

静的ページは誰が見ても同じ内容のページです。
Twitter の サービス利用規約 は誰が見ても同じです。
これは静的ページに当たります。

静的ページしか扱えない Nginx だけでは Twitter のサービス利用規約の表示はできますが、タイムラインを表示できません。
タイムラインは AP サーバを利用してレスポンスを返しています。


runserver による接続

先ほどの WEB 3層構成をそのまま構築します。

いつものようにmange.py runserverを行い、IPアドレスにアクセスがあった際に Nginx からそのページに飛ばす、という接続方法です。

DBサーバに関しては既に①で設定済みです。
今回は Nginx の Web サーバと Django で立ち上げる AP サーバの接続を行います。

Nginx / 設定ファイルの編集

 location / {
            proxy_set_header Host $http_host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X_Forwarded-Proto $scheme;

            proxy_pass http://127.0.0.1:8000;
        }

Django / settings.py の編集

settings.py の編集が必要なのはドメインを取得して利用している場合です。

ALLOWED_HOSTS は Django (アプリケーションサーバ)に誰が接続できるかを設定します。

ALLOWED_HOSTS = ['借りているIPアドレス', 'localhost']

このページの通りに来ている場合は上記の内容になっていると思います。

取得したドメインが example.com の場合、
APサーバに接続するのは example.com になります。
example.com は上記の内容に含まれていないためアクセスができず、
Webサーバ → APサーバ間でエラーが起きます。

ALLOWED_HOSTS = ['借りているIPアドレス', 'localhost', 'example.com']

'example.com'を追加することでエラーを回避できます。

runserver

  • python の仮想環境に入る
  • manage.py のディレクトリに移動

上記を行ったうえで、いつもどおり runserver を行います。

python3 manage.py runserver

これで Chrome などのウェブブラウザから IP アドレスにアクセスすると Django で設定しているページに飛べるはずです。

エラーが出る場合

前回の静的ファイルのレスポンスが問題なくできていたのであれば、リクエストは Nginx まで無事に届いています。

今回新しく追加した部分でエラーが起こっていることになります。

エラーが発生するケースは大きく分けると 3つです。

  1.  runserver が起動しないエラー
  2.  Nginx -> Django でのリクエストが届かないエラー
  3.  Django ↔ MariaDB 間でのエラー

エラーを検証していく前に確認しておきたいのが
ローカルでエラーが起きていないかという部分です。

サーバでエラーが発生し、ローカルでも同様のエラーが発生する場合、まずは必ずローカル環境を見直してください。
疑いのあるエラー箇所が多すぎるため、消去法で消していくほかありません。

① runserver が起動しないエラー

python3 manage.py runserverを行った際に
コンソールに何らかのエラー文がでるはずです。

下記の疑いがあります。比較的わかりやすく、対応もすぐできます。

  • manage.py とは違う階層で runserver を行っている
  • 仮想環境に入っていない
  • Django がインストールできてない / バージョンが違う

② Nginx → Django のエラー

Nginx から Django への接続ができていない場合です。

この場合、Django のページやエラーのページなどが一切表示されず、
下記のような Nginx のページが表示される場合です。

502 Bad Gateway】サイト死亡?原因と解決方法を考える。WEB担当者ができること - いいものタウン|兵庫県まんなかエリアのトレンドニュース

これはリクエストが Django に届いていない状況です。
Nginx 側の設定ファイルやディレクトリ構造を見直してください。

  • 設定ファイルの記述が間違っている
  • ディレクティブの末尾の「 ; 」が抜けている
  • sites-abairable に設定ファイルが置かれていない
  • sites-enabled にシンボリックリンクが置かれていない
  • nginx.conf や設定ファイルに構文エラーがある
  • IPアドレスやドメイン名が間違っている
  • プロキシの文が間違っている

などです。

私の場合はデバッグ用のシンプルな html を表示させるビューを用意しています。
そのビューが表示されればリクエストが AP サーバまで届いているし、表示されなれば AP サーバまで渡っていません。

下記のコードで nginx.conf に不備がないか確認できます。

sudo nginx -t

下記の文が出力されていれば問題ありません。

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

③ Django → Nginx のエラー

Django からのレスポンスが返ってこない場合です。

ページは表示されるけれど、何かしらのアクションを行った際にエラーでとまるケースです。
ポイントはデータベースにアクセスしないページを表示することです。

例えば管理画面を表示しようとした場合、

  • データベースにアクセスできないエラー
  • データベースからデータを持ってこれない場合のエラー

など、DBサーバ側のエラーの疑いが含まれます。

ここでエラーが起きている場合は Django の内部でのエラーです。

  • settings.py の DEBUG を True にしてみる
  • pip でインストールが必要なライブラリが揃っていない
  • PyTorch をローカルと同じ方法でインストールしている
  • migrate をしていない
  • Git へのプッシュ / プルが正確にできてない
  • 100 MB を超えるファイルに対してLFS のプルを行っていない

など、他の可能性も含めて疑いのある原因は多いです。

この場合は settings.py の DEBUG を True にすることでエラー内容を確認できます。
まだ公開していない場合やテストサーバの場合は True にしてエラー文を見てみることをお勧めします。

④ Django ↔ MariaDB のエラー

データベースを読みに行ってエラーが発生する場合はデータベースサーバでエラーが発生しています。

ローカルで動いているのであれば、Django とデータベースの接続はできているはずです。

サーバの環境でデータベースサーバとうまく連携されていない可能性が高いため、下記を確認してみてください。

  • サーバ側の settings.py の DATABASE の設定が間違っている
  • データベースのインストールがされていない
  • データベースのアカウントを作っていない

Gunicorn

runserver で起動した場合は一時的な起動しかできません。
VPS のコンソールからログアウトした段階で接続が切れます。

そのため、runserver は起動確認などでのみ利用します。

実際の運用時には Gunicorn をNginx と Django の間に入れ、
Gunicorn をアプリケーションサーバとして利用します。

Gunicorn とは

Gunicorn は WSGI規格に準拠した AP サーバのひとつです。

WSGI

インストール

Gunicorn は pip で仮想環境にインストールします。
仮想環境に入っていない場合は仮想環境に入ってからインストールします。

workon 環境名
pip install gunicorn

Gunicorn の使い方

起動 gunicorn --bind 127.0.0.1:8000 プロジェクト名.wsgi
バックグラウンド
(デーモンモード)で起動
gunicorn --bind 127.0.0.1:8000 プロジェクト名.wsgi -D
プロセスの確認ps ax | grep gunicorn
停止pkill gunicorn

-D はデーモンモードで Gunicorn を実行するコマンドです。バックグラウンドで Gunicorn が起動します。

デーモン

デーモンは Linux の常駐プログラムを指します。

先ほどもお伝えしましたが、Django は runserver を起動したときしか AP サーバとして稼働しないため、常駐させられません。
Gunicorn もデフォルトの起動方法ではデーモン化しません。
(この表現合ってるんでしょうか)

Gunicorn は -D を付けることでデーモンモ常駐してくれるようになります。

Supervisor を使用して Gunicorn を常駐化させるチュートリアルもありましたが、こちらは私は試していません。

http と ソケット接続

Nginx と Gunicorn を接続するには http 接続とソケット接続の2種類があります。

http接続構成変更がしやすい・簡単
ソケット接続早い

http 接続

Nginx の設定ファイル

http 接続は受け取ったリクエストを自身の 8000番ポートへ接続します。
runserver の時と同じ内容です。

location / {
            proxy_set_header Host $http_host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X_Forwarded-Proto $scheme;

            proxy_pass http://127.0.0.1:8000;
        }

接続

ここまでのすべてのエラーを解消していれば、下記のコードで常駐する AP サーバが稼働します。

gunicorn --bind 127.0.0.1:8000 プロジェクト名.wsgi -D

Gunicorn の http 接続はかなり簡単です。インストールして起動するだけです。

ソケット接続

ソケット接続に関しては書きかけです。そのうち更新します。(たぶん)

ソケット

-Django