メインコンテンツへスキップ
見出し画像

Nginx・Gunicorn・Djangoの関係を整理する|サーバーの中の位置づけと設定の考え方

    NDシステムズは、日頃の制作で使う技術だけでなく、その周辺の仕組みにも
    目を向けて学ぶことを大切にしています。

    この記事では、Pythonのフレームワーク「Django」で作ったアプリケーションをVPS(仮想サーバー)で公開するときの構成を、学習用にまとめた資料をもとにご紹介します。代表者の坂本がDjangoを使って開発した経験を土台に、アプリケーションの外側で何が起きているのかを学び直しました。

    この分野には、よく目にするものの、意味を説明しようとすると言葉に詰まる用語が多くあります。この記事では、そうした用語も一つずつ、できるだけイラストを交えて整理します。

    サーバーは、6つの層でできている

    最初に整理したのは、サーバー全体を層に分けて見る考え方です。下から、ハードウェア、仮想化、OS、ミドルウェア、実行環境、アプリケーションの順に積み重なっています。

    画像
    サーバーの6つの層。VPSでは、仮想化より下を事業者が、OSより上を利用者が管理します

    VPSでは、OSの導入から上を管理者の権限で自由に設定できます。その分、OSの更新や守りも利用者の責任になります。不具合が起きたときも、まずどの層の話かを切り分けることが出発点になります。

    ハードウェアと仮想化の用語

    • SSD:データを保存する記憶装置です。以前のハードディスクと比べて読み書きが速く、OSやデータベースのファイルはここに保存されます

    • ハイパーバイザー:1台の物理サーバーのCPU・メモリ・SSDを仕切り、複数の仮想マシンに割り当てる仕組みです

    • 仮想マシン:ハイパーバイザーによって仕切られた、仮想のコンピューターです。利用者からは、独立した1台のサーバーに見えます。VPSは、この仮想マシンを1台分借りるサービスです

    画像
    1棟の建物を部屋に仕切って貸すように、1台の物理サーバーを仮想マシンに仕切って貸し出します

    OSと実行環境の用語

    • OS:CPU・メモリ・ファイル・通信を管理し、プログラムに割り当てる基本のソフトウェアです。サーバーでは、Linuxの一種であるUbuntuが多く使われています

    • systemd:Ubuntuで、プログラムの起動・停止・再起動を管理する仕組みです。サーバーの起動時にNginxなどを開始し、止まったときは自動で再起動します

    画像
    systemdは、サーバーの管理人のような存在です
    • ファイアウォール:外部からの通信を、決めた扉(後述のポート)以外で遮断する仕組みです

    • ライブラリ:よく使う機能をまとめた、プログラムの部品です。Django自体も、Pythonのライブラリの一つです

    • 仮想環境(venv):アプリケーションごとに、ライブラリの置き場所を分けるPythonの仕組みです。アプリAとアプリBで必要なDjangoの版が違っても、互いに影響しません

    画像
    venvは、アプリケーションごとに道具箱を分ける仕組みです

    「ミドルウェア」という言葉の2つの意味

    学ぶ中で混乱しやすかったのが、「ミドルウェア」という言葉です。サーバーの層としてのミドルウェアは、NginxやPostgreSQLのような、OSとアプリケーションの間で共通の仕事を担う独立したプログラムを指します。一方、Djangoの中のミドルウェアは、すべての依頼の前後に実行される処理(ログインの確認やCSRFの対策など)を指し、同じ言葉でも範囲が異なります。

    1回の依頼が、Djangoに届くまで

    ブラウザからの依頼は、Nginx、Gunicorn、Djangoの順に渡り、必要に応じてPostgreSQLから情報を取り出します。利用者と直接通信するのはNginxに限られ、GunicornとPostgreSQLはサーバーの内部からのみ接続できるように配置します。

    画像
    依頼の流れ。外部に開くのは入口のNginxで、GunicornとPostgreSQLは外部から接続できない場所に置きます
    1. Nginxが443番で接続を受け付け、HTTPSの暗号を解く

    2. 静的ファイルはNginxが自分で返し、それ以外はGunicornへ転送する

    3. Gunicornの空いているワーカーが、WSGIという規格でDjangoを呼び出す

    4. DjangoがPostgreSQLから情報を取り出し、HTMLを生成する

    5. 結果がGunicorn、Nginxの順に戻り、ブラウザが画面を表示する

    通信の用語

    • プロセス:実行中のプログラムのことです。Nginx・Gunicorn・PostgreSQLは、それぞれ別のプロセスとして動いています

    • ポート:1台のサーバーの中で、通信の行き先を区別する番号です。建物の扉の番号のようなもので、HTTPSは443番、HTTPは80番、サーバーを遠隔で操作するSSHは22番、PostgreSQLは5432番が標準です

    画像
    ポートは扉の番号です。外に開く扉を絞り、ほかはファイアウォールで閉じます
    • HTTPS:ブラウザとサーバーの間の通信を暗号化する仕組みです。証明書によって、接続先が本物であることも確認できます

    • UNIXソケット:同じサーバーの中のプロセスどうしが通信するための窓口です。ファイルとして存在し、外部からは接続できません

    • WSGI:ウェブサーバーとPythonのアプリケーションをつなぐための、共通の規格です。GunicornとDjangoは、この規格に沿ってやり取りします

    • SQL:データベースに、情報の取り出しや保存を指示するための言語です

    • ORM:Pythonのコードから、SQLを自動で組み立てる仕組みです。Djangoでは、SQLを直接書かなくてもデータベースを操作できます

    画像
    DjangoのORMが、PythonのコードをSQLに翻訳してPostgreSQLに伝えます

    NginxとGunicornの役割分担

    NginxとGunicornは、どちらも「サーバー」と呼ばれるため、違いが分かりにくい組み合わせです。資料では、飲食店にたとえて整理しました。

    • Nginx:客を迎えて注文を受ける受付。接続の受け付け、HTTPS、静的ファイルの返却を担う

    • Gunicorn:注文を料理人(ワーカー)に割り振る厨房の責任者。Pythonのプログラムを動かす

    • Django:料理の手順(レシピ)。画面と業務の処理を担う

    • PostgreSQL:食材の倉庫。受注や顧客などの情報を保存する

    画像
    飲食店にたとえた役割分担。料理人(ワーカー)は、Djangoの手順で調理します

    ワーカーとは

    ワーカーは、依頼を実際に処理するプロセスです。Gunicornを起動すると、まず「マスター」が立ち上がり、マスターが複数のワーカーを起動して見守ります。それぞれのワーカーは、Djangoを読み込んだ独立したPythonのプログラムです。

    画像
    同時に処理できる依頼の数は、ワーカーの数と同じです

    標準の同期のワーカーは、1つの依頼を最後まで処理してから次の依頼を受けます。ワーカー1つが数十から百数十MBのメモリを使うため、小さなVPSでは、増やせるワーカーの数はメモリの量で決まります。ワーカーが止まったときは、マスターが代わりのワーカーを起動します。

    Gunicornだけで公開しない理由

    GunicornもHTTPの依頼を直接受けられますが、公式の説明でも、Nginxのようなプロキシ(依頼を受け取って代わりに転送する中継役)の後ろに置くことが強く推奨されています。

    画像
    通信の遅い利用者がいるとき。Nginxを前に置くと、ワーカーは待たずに次の依頼を処理できます

    特に大きな理由は、通信の遅い利用者からワーカーを守ること(バッファリング)です。Gunicornだけで受けると、通信が終わるまでワーカーが待たされ、ほかの依頼を処理できなくなります。Nginxが受信と送信を肩代わりし、完了してから渡すことで、ワーカーを業務の処理に集中させられます。

    python manage.pyとrunserverの意味

    Djangoを学ぶと最初に出てくるのが、「python manage.py runserver」という命令です。毎回入力していても、それぞれの言葉の意味を説明するのは意外に難しいものです。

    • python:Pythonのプログラムを実行する命令です

    • manage.py:Djangoのプロジェクトを作ると最初から用意される、操作の入口になるファイルです。後ろに続ける言葉で、さまざまな操作を呼び出します

    • settings.py:Djangoの設定をまとめたファイルです。データベースの接続先や、静的ファイルの置き場所などを書きます

    画像
    manage.pyは、Djangoの操作盤のようなものです

    manage.pyで呼び出す主な命令は、次のとおりです。

    • runserver:開発用の簡易サーバーを起動します。自分のパソコンで画面を確認するためのもので、多くの依頼を同時に処理する性能や安全の機能はなく、Django自身も本番での利用を想定していません。本番では、runserverの代わりにGunicornがDjangoを動かします

    • migrate:models.py(データの項目の定義)に合わせて、データベースの表を作成・変更します

    • collectstatic:各アプリに散らばった静的ファイルを、1か所(STATIC_ROOT)に集めます

    • check --deploy:本番に必要な安全の設定の不足を、一覧で示します

    静的ファイルを、Nginxから配信する理由

    静的ファイルとは、CSS・JavaScript・ロゴの画像のように、どの利用者にも同じ内容を返すファイルです。Pythonの処理を通す必要がないため、Pythonを動かさないNginxに任せます。Gunicornで返すと、画像1枚のためにワーカーが1つ占有され、画面の処理に回るワーカーが不足します。

    画像
    静的ファイルはNginxが直接返し、画面の依頼だけをGunicornとDjangoへ渡します

    runserverで開発しているときは、Djangoが静的ファイルを探して返してくれます。一方、本番(DEBUG = False)では、collectstaticでファイルをSTATIC_ROOTに集め、Nginxにその場所を伝えます。本番でCSSが表示されない原因の多くは、collectstaticの未実行か、Nginxの設定の場所の誤りです。

    Djangoには、ファイル名に内容の指紋を付ける機能(ManifestStaticFilesStorage)もあります。style.cssがstyle.3f2a91c.cssのような名前で保存され、内容を変えると名前も変わります。そのため、キャッシュ(一度取得したファイルをブラウザが保存し、次回に再利用する仕組み)の期間を長くしても、更新が確実に反映されます。

    PostgreSQLと、メモリの配分

    PostgreSQLは、Djangoとは別のプロセスとして動くデータベースのサーバーで、接続ごとに専用のプロセスを起動します。メモリ2GBの小さなVPSでは、OSに約300MB、PostgreSQLに約500MB、Gunicornのワーカー3つに1つあたり約60〜150MBという配分が一つの目安です。数値はアプリケーションにより大きく異なるため、実際の使用量を確認してワーカーの数を決めます。

    設定で重視する順序

    資料の中で最も大切だと感じたのは、設定で重視する順序です。

    画像
    設定で重視する順序。下の段から順に整えます
    1. 安全:公開するポートを絞り、管理者の権限で動くものを減らし、更新を続ける

    2. 復旧できること:バックアップをサーバーの外に置き、復元の手順を訓練しておく

    3. 安定:異常が起きても自動で再開し、停止に早く気づく

    4. 性能:上の3つが整ったうえで、ワーカーの数やキャッシュを調整する

    性能の不足は後から補えますが、失ったデータは戻りません。なお、動作中のデータベースのファイルを複写しても正しいバックアップにはならないため、pg_dump(PostgreSQLのバックアップの命令)のような専用の方法で取得します。

    具体的には、SSHを鍵による認証に限る、GunicornとPostgreSQLを外部に公開しない、DjangoのDEBUG(誤りの詳細を画面に表示する開発用の設定)をFalseにする、といった設定を先に整えます。DEBUGがTrueのままでは、誤りの画面に設定やコードの内容が表示されてしまいます。

    症状から、どの層の問題かを判断する

    画面に出る誤りの番号から、どの層を確認すればよいかも整理しました。

    画像
    画面に出る症状と、確認する層
    • 502 Bad Gateway:Gunicornが停止しているか、Nginxとの接続先が一致していない

    • 504 Gateway Timeout:Djangoの処理が、Nginxの待ち時間を超えた

    • 400 Bad Request:ホスト名が、DjangoのALLOWED_HOSTS(受け付けるドメインの一覧)にない

    • CSSや画像が表示されない:静的ファイルの場所を、Nginxが把握していない

    • ログイン後にhttpへ戻される:HTTPSであることが、Djangoに伝わっていない

    502と504はNginxが返す画面ですが、原因の多くはGunicornとDjangoの側にあります。まずNginxのerror.log(誤りの記録)で、転送先との間で起きたことを確認します。

    学んで分かったこと

    1. 層で考える:障害も守りも、どの層の話かを最初に切り分ける

    2. 得意な仕事を分担する:Nginxは入口と静的ファイル、GunicornはPythonの実行、Djangoは業務の処理、PostgreSQLはデータの保存を担う

    3. 外に開くのは入口に限る:GunicornとPostgreSQLは、サーバーの内部に閉じる

    4. 安全と復旧を先に:更新・権限・バックアップ・監視を整えてから、性能を調整する

    使う言語やサービスが違っても、この考え方は共通しています。用語の意味を一つずつ確認していくと、それぞれの設定がなぜ必要なのかも見えてきました。NDシステムズは、これからも制作で直接使う技術に限らず、幅広く学んだことを発信していきます。

    免責事項

    この記事は、筆者が個人として調べたことや経験をもとに、執筆時点の内容をまとめたものです。法律・税務・会計・投資などの専門家による助言ではありません。分かりやすさを優先し、細かい条件や例外を省いている場合があります。

    制度、製品の仕様、料金、施設の営業時間などは変わることがあります。実際の判断や手続きにあたっては、出典や公式の情報で最新の内容を確認し、必要に応じて専門家や窓口にご相談ください。この記事の内容を利用して生じた損害については、責任を負いかねます。

    NDシステムズのサービスについて

    NDシステムズは、月額制のホームページ制作を中心に、事業のデジタル化を支援しています。ホームページ制作は公開後の更新と改善まで月額で続けてお引き受けし、独自システム開発は1つの業務に絞ったシステムを承ります。初回の無料相談(オンライン・30分)は、お問い合わせのフォームまたはメールで承ります。

     
     
    福岡県久留米市のNDシステムズです。IT・AI、語学、会計、数学、九州北部の風景などについて、調べて考えたことを書いています。記事は筆者が個人として調べた執筆時点の内容で、専門家の助言ではありません。最新の情報は出典でご確認ください。

    あなたへのおすすめ