前書き
このガイドでは、uWSGIによって提供される単純なWSGIアプリケーションをセットアップします。 Nginx Webサーバーをアプリケーションサーバーへのリバースプロキシとして使用して、より堅牢な接続処理を提供します。 これらのコンポーネントをUbuntu 14.04サーバーにインストールして構成します。
定義と概念
いくつかの用語を明確にする
飛び込む前に、相互に関連する概念に関連するいくつかの混乱する用語に対処する必要があります。 これらの3つの別個の用語は交換可能に見えますが、実際には明確な意味があります。
-
WSGI:アプリケーションまたはフレームワークとアプリケーション/ Webサーバー間の通信用の標準インターフェースを定義するPython spec。 これは、一貫性と互換性のためにこれらのコンポーネント間の通信を簡素化および標準化するために作成されました。 これは基本的に、他のプロトコルで使用できるAPIインターフェイスを定義します。
-
uWSGI:Webアプリケーションおよびサービスを開発およびデプロイするためのフルスタックを提供することを目的としたアプリケーションサーバーコンテナー。 主なコンポーネントは、異なる言語のアプリを処理できるアプリケーションサーバーです。 WSGI仕様で定義されているメソッドを使用してアプリケーションと通信し、他のさまざまなプロトコルを介して他のWebサーバーと通信します。 これは、従来のWebサーバーからの要求を、アプリケーションが処理できる形式に変換する部分です。
-
uwsgi:よりフル機能のWebサーバーと通信するためにuWSGIサーバーによって実装される高速のバイナリプロトコル。 これはwire protocolであり、トランスポートプロトコルではありません。 uWSGIへのリクエストをプロキシしているWebサーバーと通信するための好ましい方法です。
WSGIアプリケーションの要件
WSGI仕様は、Webサーバーとスタックのアプリケーション部分との間のインターフェースを定義しています。 このコンテキストでは、「Webサーバー」とは、WSGI仕様を使用してクライアント要求をアプリケーションに変換する役割を担うuWSGIサーバーを指します。 これにより、通信が簡素化され、疎結合のコンポーネントが作成されるため、多くのトラブルなしにどちらの側も簡単に交換できます。
Webサーバー(uWSGI)には、定義済みの「呼び出し可能」をトリガーすることにより、アプリケーションに要求を送信する機能が必要です。 callableは、Webサーバーがいくつかのパラメーターを指定して関数を呼び出すことができるアプリケーションへの単なるエントリーポイントです。 予想されるパラメーターは、環境変数のディクショナリーと、Webサーバー(uWSGI)コンポーネントによって提供される呼び出し可能オブジェクトです。
応答として、アプリケーションはクライアント応答の本文を生成するために使用される反復可能オブジェクトを返します。 また、パラメーターとして受け取ったWebサーバーコンポーネントcallableを呼び出します。 Webサーバーcallableをトリガーするときの最初のパラメーターはHTTPステータスコードになり、2番目のパラメーターはタプルのリストになります。各タプルは、クライアントに送り返す応答ヘッダーと値を定義します。
このインスタンスでuWSGIによって提供されるこの対話の「Webサーバー」コンポーネントでは、アプリケーションが上記の品質を持っていることを確認するだけです。 また、実際のクライアントリクエストを処理してuWSGIサーバーにプロキシするようにNginxをセットアップします。
コンポーネントをインストールする
まず、必要なコンポーネントをUbuntu 14.04サーバーにインストールする必要があります。 これは主にapt
とpip
を使用して実行できます。
まず、apt
パッケージインデックスを更新してから、Python開発ライブラリとヘッダー、pip
Pythonパッケージマネージャー、NginxWebサーバーとリバースプロキシをインストールします。
sudo apt-get update
sudo apt-get install python-dev python-pip nginx
パッケージのインストールが完了すると、pip
Pythonパッケージマネージャーにアクセスできるようになります。 これを使用してvirtualenv
パッケージをインストールできます。これを使用して、アプリケーションのPython環境をシステム上に存在する可能性のある他の環境から分離します。
sudo pip install virtualenv
これが完了すると、アプリケーションの一般的な構造の作成を開始できます。 上記の仮想環境を作成し、この環境内にuWSGIアプリケーションサーバーをインストールします。
App DirectoryとVirtualenvをセットアップする
アプリのフォルダーを作成することから始めます。 これにより、より完全なアプリケーションの実際のアプリケーションコードを含むネストされたフォルダーを保持できます。 目的のために、このディレクトリには仮想環境とWSGIエントリポイントが保持されます。
mkdir ~/myapp/
次に、ディレクトリに移動して、アプリケーションの環境を設定できるようにします。
cd ~/myapp
virtualenv
コマンドを使用して仮想環境を作成します。 簡単にするために、これをmyappenv
と呼びます。
virtualenv myappenv
新しいPython環境は、myappenv
というディレクトリの下にセットアップされます。 次のように入力して、この環境をアクティブ化できます。
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アプリケーションを作成します。 繰り返しますが、提供する必要があるアプリケーションコンポーネントには、次のプロパティが必要です。
-
callable(呼び出し可能な関数または他の言語構成要素)を介してインターフェイスを提供する必要があります
-
呼び出し可能オブジェクトは、環境変数のようなキーと値のペアを含む辞書と、サーバー(uWSGI)でアクセス可能な呼び出し可能オブジェクトをパラメーターとして受け取る必要があります。
-
アプリケーションのcallableは、クライアントを送信するためのボディを生成するiterableを返す必要があります。
-
アプリケーションは、HTTPステータスとリクエストヘッダーを使用してウェブサーバーのcallableを呼び出す必要があります。
アプリケーションをアプリケーションディレクトリのwsgi.py
というファイルに書き込みます。
nano ~/myapp/wsgi.py
このファイル内で、できる限り単純なWSGI準拠のアプリケーションを作成します。 すべてのPythonコードと同様に、インデントに注意してください。
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return ["Hello There!
"]
上記のコードは、完全な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プロジェクトには、デフォルトで、Webサーバー(uWSGI)からアプリケーション(Django)にリクエストを変換するwsgi.py
ファイルが含まれています。 単純化されたWSGIインターフェイスは、実際のアプリケーションコードがどれほど複雑であっても同じままです。 これは、インターフェイスの強みの1つです。
完了したら、ファイルを保存して閉じます。
コードをテストするために、uWSGIを起動できます。 とりあえずHTTPを使用し、ポート8080
でリッスンするように指示します。 スクリプトの名前を渡します(サフィックスは削除されます)。
uwsgi --socket 0.0.0.0:8080 --protocol=http -w wsgi
これで、WebブラウザでサーバーのIPアドレスまたはドメイン名にアクセスしてから:8080
にアクセスすると、wsgi.py
ファイルの本文として渡した第1レベルのヘッダーテキストが表示されます。
これが機能することを確認したら、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が外部の世界と話すために使用するプロトコルを変更します。 アプリケーションをテストするときに、Webブラウザーから表示できるように--protocol=http
を指定しました。 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スクリプトで使用するように設定されました。
アプリを管理するための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アドレス(ポート番号なし)に移動して、設定したアプリケーションを確認できるはずです。
結論
これまでに作成した場合は、単純なWSGIアプリケーションを作成し、より複雑なアプリケーションをどのように設計する必要があるかについての洞察を得ています。 uWSGIアプリケーションコンテナー/サーバーを専用の仮想環境にインストールして、アプリケーションを提供しています。 このプロセスを自動化するために、構成ファイルとUpstartスクリプトを作成しました。 uWSGIサーバーの前に、uwsgi
ワイヤープロトコルを使用してuWSGIプロセスと通信できるNginxリバースプロキシを設定しました。
実際の実稼働環境をセットアップするときに、これをどのように拡張できるかを簡単に確認できます。 たとえば、uWSGIには、「皇帝モード」と呼ばれるものを使用して複数のアプリケーションを管理する機能があります。 Nginx構成を展開して、uWSGIインスタンス間で負荷を分散したり、アプリケーションの静的ファイルを処理したりできます。 複数のアプリケーションを提供する場合、ニーズに応じて、仮想環境ではなくグローバルにuWSGIをインストールするのが最善の場合があります。 コンポーネントはすべてかなり柔軟であるため、多くの異なるシナリオに対応できるように構成を調整できる必要があります。