序章

このガイドでは、uWSGIが提供する簡単なWSGIアプリケーションをセットアップします。 Nginx Webサーバーをアプリケーションサーバーへのリバースプロキシとして使用して、より堅牢な接続処理を提供します。 これらのコンポーネントをUbuntu14.04サーバーにインストールして構成します。

定義と概念

いくつかの用語を明確にする

始める前に、扱う相互に関連する概念に関連するいくつかの紛らわしい用語に対処する必要があります。 これらの3つの別個の用語は互換性があるように見えますが、実際には異なる意味を持っています。

  • WSGI :アプリケーションまたはフレームワークとアプリケーション/Webサーバー間の通信用の標準インターフェースを定義するPython仕様。 これは、一貫性と互換性のためにこれらのコンポーネント間の通信を簡素化および標準化するために作成されました。 これは基本的に、他のプロトコルで使用できるAPIインターフェースを定義します。
  • uWSGI :Webアプリケーションとサービスを開発および展開するためのフルスタックを提供することを目的としたアプリケーションサーバーコンテナー。 主要なコンポーネントは、さまざまな言語のアプリを処理できるアプリケーションサーバーです。 WSGI仕様で定義された方法を使用してアプリケーションと通信し、他のさまざまなプロトコルを介して他のWebサーバーと通信します。 これは、従来のWebサーバーからの要求をアプリケーションが処理できる形式に変換する部分です。
  • uwsgi :よりフル機能のWebサーバーと通信するためにuWSGIサーバーによって実装される高速のバイナリプロトコル。 これはワイヤプロトコルであり、トランスポートプロトコルではありません。 これは、uWSGIへの要求をプロキシしているWebサーバーと通信するための推奨される方法です。

WSGIアプリケーションの要件

WSGI仕様は、Webサーバーとスタックのアプリケーション部分の間のインターフェイスを定義します。 このコンテキストでは、「Webサーバー」とは、WSGI仕様を使用してクライアント要求をアプリケーションに変換するuWSGIサーバーを指します。 これにより、通信が簡素化され、緩く結合されたコンポーネントが作成されるため、どちらの側も問題なく簡単に交換できます。

Webサーバー(uWSGI)は、定義された「呼び出し可能」をトリガーすることにより、アプリケーションに要求を送信する機能を備えている必要があります。 呼び出し可能オブジェクトは、Webサーバーがいくつかのパラメーターを使用して関数を呼び出すことができるアプリケーションへの単なるエントリーポイントです。 必要なパラメーターは、環境変数のディクショナリと、Webサーバー(uWSGI)コンポーネントによって提供される呼び出し可能パラメーターです。

応答として、アプリケーションは、クライアント応答の本文を生成するために使用される反復可能オブジェクトを返します。 また、パラメーターとして受け取った呼び出し可能なWebサーバーコンポーネントを呼び出します。 呼び出し可能なWebサーバーをトリガーするときの最初のパラメーターはHTTPステータス・コードであり、2番目はタプルのリストであり、それぞれがクライアントに送り返す応答ヘッダーと値を定義します。

この場合、uWSGIによって提供されるこのインタラクションの「Webサーバー」コンポーネントを使用すると、アプリケーションが上記の品質を備えていることを確認するだけで済みます。 また、実際のクライアントリクエストを処理し、それらをuWSGIサーバーにプロキシするようにNginxを設定します。

コンポーネントをインストールします

開始するには、Ubuntu14.04サーバーに必要なコンポーネントをインストールする必要があります。 これは主にaptpipを使用して実行できます。

まず、aptパッケージインデックスを更新してから、Python開発ライブラリとヘッダー、pip Pythonパッケージマネージャー、およびNginxWebサーバーとリバースプロキシをインストールします。

sudo apt-get update
sudo apt-get install python-dev python-pip nginx

パッケージのインストールが完了すると、pipPythonパッケージマネージャーにアクセスできるようになります。 これを使用して、virtualenvパッケージをインストールできます。これを使用して、アプリケーションのPython環境をシステム上に存在する可能性のある他の環境から分離します。

sudo pip install virtualenv

これが完了すると、アプリケーションの一般的な構造の作成を開始できます。 上記で説明した仮想環境を作成し、この環境内にuWSGIアプリケーションサーバーをインストールします。

AppDirectoryとVirtualenvを設定します

まず、アプリ用のフォルダーを作成します。 これにより、より完全なアプリケーションの実際のアプリケーションコードを含むネストされたフォルダーを保持できます。 私たちの目的のために、このディレクトリは単に仮想環境とWSGIエントリポイントを保持します。

mkdir ~/myapp/

次に、ディレクトリに移動して、アプリケーションの環境を設定できるようにします。

cd ~/myapp

virtualenvコマンドで仮想環境を作成します。 簡単にするために、これをmyappenvと呼びます。

virtualenv myappenv

myappenvというディレクトリの下に新しいPython環境がセットアップされます。 次のように入力して、この環境をアクティブ化できます。

source myappenv/bin/activate

プロンプトが変化して、仮想環境内で操作していることを示します。 次のようになります。

(myappenv)username@host:~/my_app$

この環境をいつでも終了したい場合は、次のように入力するだけです。

deactivate

環境を非アクティブ化した場合は、再度アクティブ化してガイドを続行してください。

この環境がアクティブな場合、インストールされているPythonパッケージはすべてこのディレクトリ階層に含まれます。 システムのPython環境に干渉することはありません。 これを念頭に置いて、pipを使用してuWSGIサーバーを環境にインストールできるようになりました。 このためのパッケージはuwsgiと呼ばれます(これはまだuWSGIサーバーであり、uwsgiプロトコルではありません):

pip install uwsgi

次のように入力して、使用可能になったことを確認できます。

uwsgi --version

バージョン番号が返される場合は、uWSGIサーバーを使用できます。

WSGIアプリケーションを作成する

次に、前に説明したWSGI仕様要件を使用して、非常に単純なWSGIアプリケーションを作成します。 繰り返しになりますが、提供する必要のあるアプリケーションコンポーネントには、次のプロパティが必要です。

  • 呼び出し可能オブジェクト(呼び出すことができる関数または他の言語構造)を介してインターフェースを提供する必要があります
  • 呼び出し可能オブジェクトは、環境変数のようなキーと値のペアを含むディクショナリと、サーバー(uWSGI)でアクセス可能な呼び出し可能オブジェクトをパラメーターとして受け取る必要があります。
  • アプリケーションの呼び出し可能オブジェクトは、クライアントに送信する本文を生成する反復可能オブジェクトを返す必要があります。
  • アプリケーションは、HTTPステータスとリクエストヘッダーを使用してWebサーバーの呼び出し可能オブジェクトを呼び出す必要があります。

アプリケーションディレクトリのwsgi.pyというファイルにアプリケーションを書き込みます。

nano ~/myapp/wsgi.py

このファイル内に、可能な限り最も単純なWSGI準拠のアプリケーションを作成します。 すべてのPythonコードと同様に、インデントに注意を払うようにしてください。

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return ["<h1 style='color:blue'>Hello There!</h1>"]

上記のコードは、完全なWSGIアプリケーションを構成します。 デフォルトでは、uWSGIはapplicationという呼び出し可能オブジェクトを検索します。そのため、関数applicationを呼び出しました。 ご覧のとおり、2つのパラメーターが必要です。

最初にenvironと呼んだのは、キー値辞書のような環境変数になるからです。 2つ目はstart_responseと呼ばれ、で送信されるWebサーバー(uWSGI)呼び出し可能オブジェクトを参照するためにアプリが内部的に使用する名前です。 これらのパラメーター名は両方とも、WSGIの相互作用を定義する PEP 333 仕様の例で使用されているため、単純に選択されています。

アプリケーションはこの情報を取得し、2つのことを実行する必要があります。 まず、HTTPステータスコードと送り返したいヘッダーを使用して、受信した呼び出し可能オブジェクトを呼び出す必要があります。 この場合、「200 OK」応答を送信し、Content-Typeヘッダーをtext/htmlに設定しています。

第二に、それは応答本体として使用するために反復可能で戻る必要があります。 ここでは、HTMLの単一の文字列を含むリストを使用しました。 文字列も反復可能ですが、リスト内では、uWSGIは1回の反復で文字列全体を処理できます。

実際のシナリオでは、このファイルは残りのアプリケーションコードへのリンクとして使用される可能性があります。 たとえば、Djangoプロジェクトには、デフォルトでwsgi.pyファイルが含まれており、Webサーバー(uWSGI)からアプリケーション(Django)にリクエストを変換します。 簡略化されたWSGIインターフェイスは、実際のアプリケーションコードがどれほど複雑であっても同じです。 これは、インターフェイスの長所の1つです。

終了したら、ファイルを保存して閉じます。

コードをテストするために、uWSGIを起動できます。 とりあえずHTTPを使用し、ポート8080でリッスンするように指示します。 スクリプトの名前を渡します(サフィックスは削除されています)。

uwsgi --socket 0.0.0.0:8080 --protocol=http -w wsgi

ここで、WebブラウザでサーバーのIPアドレスまたはドメイン名にアクセスし、続いて:8080にアクセスすると、wsgi.pyファイルに本文として渡された第1レベルのヘッダーテキストが表示されます。

wsgi application example

これが機能することを確認したら、CTRL-Cでサーバーを停止します。

この時点で、実際のアプリケーションの設計は完了です。 必要に応じて、仮想環境を非アクティブ化できます。

deactivate

uWSGI構成ファイルを構成する

上記の例では、uWSGIサーバーを手動で起動し、コマンドラインでいくつかのパラメーターを渡しました。 これを回避するには、構成ファイルを作成します。 uWSGIサーバーはさまざまな形式の構成を読み取ることができますが、簡単にするために.ini形式を使用します。

これまで使用してきた命名を続けるために、ファイルmyapp.iniを呼び出して、アプリケーションフォルダーに配置します。

nano ~/myapp/myapp.ini

内部に、[uwsgi]というセクションを作成する必要があります。 このセクションには、すべての構成アイテムがあります。 まず、アプリケーションを特定します。 uWSGIサーバーは、アプリケーションの呼び出し可能ファイルがどこにあるかを知る必要があります。 次の範囲内でファイルと関数を指定できます。

[uwsgi]
module = wsgi:application

最初のuwsgiプロセスをマスターとしてマークしてから、いくつかのワーカープロセスを生成します。 5人の労働者から始めます:

[uwsgi]
module = wsgi:application

master = true
processes = 5

実際には、uWSGIが外界と話すために使用するプロトコルを変更します。 アプリケーションをテストするときに、--protocol=httpを指定して、Webブラウザーから表示できるようにしました。 nginxをuWSGIの前でリバースプロキシとして構成するため、これを変更できます。 Nginxは、uwsgiプロキシメカニズムを実装しています。これは、uWSGIが他のサーバーと通信するために使用できる高速バイナリプロトコルです。 uwsgiプロトコルは実際にはuWSGIのデフォルトプロトコルであるため、プロトコル仕様を省略するだけで、uwsgiにフォールバックします。

この構成はNginxで使用するように設計しているため、ネットワークポートの使用から変更し、代わりにUnixソケットを使用します。 これはより安全で高速です。 相対パスを使用すると、現在のディレクトリにソケットが作成されます。 これをmyapp.sockと呼びます。 Nginxが書き込みできるように、権限を「664」に変更します(Nginxが使用するwww-dataグループでuWSGIを起動します。 vacuumオプションも追加します。これにより、プロセスが停止したときにソケットが削除されます。

[uwsgi]
module = wsgi:application

master = true
processes = 5

socket = myapp.sock
chmod-socket = 664
vacuum = true

起動時にアプリケーションを開始するためのUpstartファイルを作成するため、最後のオプションが1つ必要です。 UpstartとuWSGIは、SIGTERMシグナルがアプリケーションに対して何をすべきかについて異なる考えを持っています。 この不一致を整理して、Upstartでプロセスを期待どおりに処理できるようにするには、die-on-termというオプションを追加するだけで、uWSGIがプロセスをリロードする代わりに強制終了します。

[uwsgi]
module = wsgi:application

master = true
processes = 5

socket = myapp.sock
chmod-socket = 664
vacuum = true

die-on-term = true

終了したら、ファイルを保存して閉じます。 この構成ファイルは、Upstartスクリプトで使用するように設定されています。

アプリを管理するためのアップスタートファイルを作成する

アプリケーションを常に利用できるように、起動時にuWSGIインスタンスを起動できます。 これを、Upstartがチェックする/etc/initディレクトリに配置します。 これをmyapp.confと呼びます。

sudo nano /etc/init/myapp.conf

まず、サービスの説明から始めて、自動的に実行する必要のあるシステムランレベルを選択します。 標準のユーザーランレベルは2から5です。 このグループ外のランレベルにある場合(システムの再起動時やシングルユーザーモード時など)にサービスを停止するようにUpstartに指示します。

description "uWSGI instance to serve myapp"

start on runlevel [2345]
stop on runlevel [!2345]

次に、プロセスを実行するユーザーとグループについてUpstartに通知します。 自分のアカウントでアプリケーションを実行したい(このガイドではdemoを使用していますが、自分のユーザーに置き換える必要があります)。 ただし、グループをNginxが使用するwww-dataユーザーに設定します。 これが必要なのは、Webサーバーが.iniファイルが作成するソケットの読み取りと書き込みができる必要があるためです。

description "uWSGI instance to serve myapp"

start on runlevel [2345]
stop on runlevel [!2345]

setuid demo
setgid www-data

次に、実際のコマンドを実行してuWSGIを起動します。 uWSGIを仮想環境にインストールしたため、追加の作業が必要になります。 uWSGI実行可能ファイルへのパス全体を提供することもできますが、代わりに、仮想環境をアクティブ化します。 これにより、環境にインストールされている追加のソフトウェアに依存している場合に簡単になります。

これを行うには、scriptブロックを使用します。 内部では、アプリケーションディレクトリに移動し、仮想環境をアクティブ化して(sourceではなく.をスクリプトで使用する必要があります)、.iniを指すuWSGIインスタンスを開始します。 ] ファイル:

description "uWSGI instance to serve myapp"

start on runlevel [2345]
stop on runlevel [!2345]

setuid demo
setgid www-data

script
    cd /home/demo/myapp
    . myappenv/bin/activate
    uwsgi --ini myapp.ini
end script

これで、Upstartスクリプトが完成しました。 終了したら、ファイルを保存して閉じます。

これで、次のように入力してサービスを開始できます。

sudo start myapp

次のように入力することで、開始されたことを確認できます。

ps aux | grep myapp
demo   14618  0.0  0.5  35868  5996 ?        S    15:02   0:00 uwsgi --ini myapp.ini
demo   14619  0.0  0.5  42680  5532 ?        S    15:02   0:00 uwsgi --ini myapp.ini
demo   14620  0.0  0.5  42680  5532 ?        S    15:02   0:00 uwsgi --ini myapp.ini
demo   14621  0.0  0.5  42680  5532 ?        S    15:02   0:00 uwsgi --ini myapp.ini
demo   14622  0.0  0.5  42680  5532 ?        S    15:02   0:00 uwsgi --ini myapp.ini
demo   14623  0.0  0.5  42680  5532 ?        S    15:02   0:00 uwsgi --ini myapp.ini
demo   15520  0.0  0.0  11740   936 pts/0    S+   15:53   0:00 grep --color=auto myapp

これは起動時に自動的に開始されます。 次のように入力すると、いつでもサービスを停止できます。

sudo stop myapp

nginxをuWSGIにプロキシするように構成する

この時点で、WSGIアプリがあり、uWSGIがそれを読み取って提供できることを確認しました。 構成ファイルとUpstartスクリプトを作成しました。 uWSGIプロセスはソケットをリッスンし、uwsgiプロトコルを使用して通信します。

これで、Nginxをリバースプロキシとして構成できるようになりました。 Nginxには、uWSGIと通信するためのuwsgiプロトコルを使用してプロキシする機能があります。 これはHTTPよりも高速なプロトコルであり、パフォーマンスが向上します。

セットアップするNginxの構成は非常に簡単です。 Nginxの構成階層内のsites-availableディレクトリ内に新しいファイルを作成します。 使用しているアプリ名と一致するように、ファイルをmyappと呼びます。

sudo nano /etc/nginx/sites-available/myapp

このファイル内で、このサーバーブロックが応答するポート番号とドメイン名を指定できます。 この例では、デフォルトのポート80を使用します。

server {
    listen 80;
    server_name server_domain_or_IP;
}

このドメインまたはIPアドレスのすべてのリクエストをWSGIアプリケーションに送信するため、/で始まるリクエストに対して、すべてに一致する単一のロケーションブロックを作成します。 内部では、includeディレクティブを使用して、Nginx構成ディレクトリ内のファイルから適切なデフォルトのパラメーターをいくつか含めます。 これらを含むファイルはuwsgi_paramsと呼ばれます。 その後、uwsgiプロトコルを介してトラフィックをuWSGIインスタンスに渡します。 以前に構成したUNIXソケットを使用します。

server {
    listen 80;
    server_name server_domain_or_IP;

    location / {
        include         uwsgi_params;
        uwsgi_pass      unix:/home/demo/myapp/myapp.sock;
    }
}

実際、単純なアプリケーションに必要なのはこれだけです。 より完全なアプリケーションのために行うことができるいくつかの改善があります。 たとえば、このブロックの外側にいくつかのアップストリームuWSGIサーバーを定義し、それらをそこに渡すことができます。 さらにいくつかのuWSGIパラメータを含めることができます。 また、Nginxからの静的ファイルを直接処理し、動的リクエストのみをuWSGIインスタンスに渡す場合もあります。

ただし、3行のアプリではこれらの機能は必要ないため、ファイルを保存して閉じることができます。

sites-enabledディレクトリにリンクして、作成したサーバー構成を有効にします。

sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled

構成ファイルで構文エラーを確認してください。

sudo service nginx configtest

問題が検出されなかったことが報告された場合は、サーバーを再起動して変更を実装します。

sudo service nginx restart

Nginxが再起動すると、サーバーのドメイン名またはIPアドレス(ポート番号なし)に移動して、構成したアプリケーションを確認できるようになります。

full WSGI app

結論

ここまで進んだら、単純なWSGIアプリケーションを作成し、より複雑なアプリケーションをどのように設計する必要があるかについての洞察を得ることができます。 uWSGIアプリケーションコンテナ/サーバーを専用の仮想環境にインストールして、アプリケーションを提供します。 このプロセスを自動化するための構成ファイルとUpstartスクリプトを作成しました。 uWSGIサーバーの前に、uwsgiワイヤープロトコルを使用してuWSGIプロセスと通信できるNginxリバースプロキシをセットアップしました。

実際の実稼働環境をセットアップするときに、これをどのように拡張できるかを簡単に確認できます。 たとえば、uWSGIには、「エンペラーモード」と呼ばれるものを使用して複数のアプリケーションを管理する機能があります。 Nginx構成を拡張して、uWSGIインスタンス間の負荷分散を行ったり、アプリケーションの静的ファイルを処理したりできます。 複数のアプリケーションにサービスを提供する場合、ニーズによっては、仮想環境ではなくグローバルにuWSGIをインストールすることが最も重要な場合があります。 コンポーネントはすべてかなり柔軟なので、さまざまなシナリオに対応するように構成を微調整できるはずです。