CentOS 7でPythonアプリを提供するためにuWSGIとNginxをセットアップする方法

前書き

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

定義と概念

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

飛び込む前に、相互に関連する概念に関連するいくつかの混乱する用語に対処する必要があります。 これらの3つの別個の用語は交換可能に見えますが、実際には明確な意味があります。

  • * WSGI *:アプリケーションまたはフレームワークとアプリケーション/ Webサーバー間の通信用の標準インターフェイスを定義するhttps://www.python.org/dev/peps/pep-0333/[Python仕様]。 これは、一貫性と互換性のためにこれらのコンポーネント間の通信を簡素化および標準化するために作成されました。 これは基本的に、他のプロトコルで使用できるAPIインターフェースを定義します。

  • * uWSGI *:WebアプリケーションおよびWebサービスを開発および展開するための完全なスタックを提供することを目的とするアプリケーションサーバーコンテナ。 主なコンポーネントは、異なる言語のアプリを処理できるアプリケーションサーバーです。 WSGI仕様で定義されているメソッドを使用してアプリケーションと通信し、他のさまざまなプロトコルを介して他のWebサーバーと通信します。 これは、従来のWebサーバーからの要求を、アプリケーションが処理できる形式に変換する部分です。

  • * uwsgi *:フル機能のWebサーバーと通信するためにuWSGIサーバーによって実装される高速なバイナリプロトコル。 これはhttp://en.wikipedia.org/wiki/Wire_protocol[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をセットアップします。

コンポーネントをインストールする

開始するには、CentOS 7サーバーに必要なコンポーネントをインストールする必要があります。 主に `+ yum `と ` pip +`を使用してこれを行うことができます。

まず、EPELリポジトリをインストールして、より広範なパッケージにアクセスできるようにする必要があります。 次のように入力することで、単一の `+ yum +`コマンドで簡単に実行できます。

sudo yum install epel-release

これで、コンポーネントをインストールできます。 Python開発ライブラリとヘッダー、 + pip + Pythonパッケージマネージャー、およびNginx Webサーバーとリバースプロキシを取得する必要があります。 また、uWSGIバイナリを一時的にビルドするためのコンパイラも必要です。

sudo yum install python-pip python-devel nginx gcc

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

sudo pip install virtualenv

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

App DirectoryとVirtualenvをセットアップする

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

mkdir ~/myapp/

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

cd ~/myapp

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

virtualenv

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

source /bin/activate

プロンプトが変わり、現在仮想環境内で操作していることを示す必要があります。 これは次のようになります。

()@:~/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 ~//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相互作用を定義するhttps://www.python.org/dev/peps/pep-0333/[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 +」ファイルで本文として渡した最初のレベルのヘッダーテキストが表示されます。

image:https://assets.digitalocean.com/articles/nginx_uwsgi_wsgi_1404/test_app.png [wsgiアプリケーション例]

これが機能することを確認したら、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ソケットを使用します。 これはより安全で高速です。

自分のユーザー名を指定して、 `+ uwsgi `サーバーを実行し、ソケットファイルを所有します。 ` / run `の下にディレクトリを作成してソケットファイルを配置し、uWSGIとNginxの両方がアクセスできるようにします。 ソケット自体を「 myapp.sock 」と呼びます。 Nginxが書き込みできるようにアクセス許可を「664」に変更します(Nginxが使用する ` www-data `グループでuWSGIを起動します)。 また、プロセスが停止したときにソケットを削除する「 vacuum +」オプションを追加します。

[uwsgi]
module = wsgi:application

master = true
processes = 5

uid =
socket = /run/uwsgi/myapp.sock
chown-socket = :nginx
chmod-socket = 660
vacuum = true

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

[uwsgi]
module = wsgi:application

master = true
processes = 5

uid =
socket = /run/uwsgi/myapp.sock
chown-socket = :nginx
chmod-socket = 660
vacuum = true

die-on-term = true

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

Systemd Unitファイルを作成してアプリを管理する

ブート時にuWSGIインスタンスを起動して、アプリケーションが常に利用できるようにすることができます。 これを行うために、systemdユニットファイルを作成できます。 これをユーザーが作成したユニットファイルに最適な `+ / etc / systemd / system`ディレクトリに配置します。 ユニットファイル `+ uwsgi.service`を呼び出します:

sudo nano /etc/systemd/system/uwsgi.service

まず、メタデータのペースを調整できる「+ [Unit] +」セクションから始めます。 ここに置く唯一のものは、サービスの説明です。

[Unit]
Description=uWSGI instance to serve myapp

次に、 `+ [Service] `セクションを開きます。 仮想環境を使用しているため、サービス開始コマンドは従来よりも複雑になります。 ` ExecStartPre `コマンドを使用して、ソケットディレクトリが作成され、正しい関係者によって所有されていることを確認します。 既に設定されている場合は、(等号の後に「-」を付けることで)これは失敗します。 これは、 ` bash +`の1回の呼び出しに渡されます。

uWSGIを起動する実際の `+ ExecStart `コマンドについても、実際のコマンドを ` bash `に渡します。 このディレクティブでは1つのコマンド(この場合は「 bash」)しか実行できないため、これにより、いくつかの異なるコマンドを実行できます。 これを使用してアプリケーションディレクトリに変更し、仮想環境をアクティブにし、作成した `+ .ini +`ファイルでuWSGIを起動します。

[Unit]
Description=uWSGI instance to serve myapp

[Service]
ExecStartPre=-/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown :nginx /run/uwsgi'
ExecStart=/usr/bin/bash -c 'cd /home//myapp; source myappenv/bin/activate; uwsgi --ini myapp.ini'

これで、あとは `+ [Install] `セクションを作成するだけです。 これにより、ユニットを「+有効化」したときに何が起こるかが決まります。 基本的には、ユニットが自動起動する状態を指定します。 有効にすると、サーバーがマルチユーザーモードになっているときにこのユニットが起動するように指定します。

[Unit]
Description=uWSGI instance to serve myapp

[Service]
ExecStartPre=-/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown :nginx /run/uwsgi'
ExecStart=/usr/bin/bash -c 'cd /home//myapp; source myappenv/bin/activate; uwsgi --ini myapp.ini'

[Install]
WantedBy=multi-user.target

上記の構成を書き出したら、ファイルを保存して閉じます。

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

sudo systemctl start uwsgi

次のように入力して、問題なく起動したことを確認します。

systemctl status uwsgi

エラーがなかった場合は、次のように入力して、起動時にサービスが開始されるようにサービスを有効にします。

sudo systemctl enable uwsgi

次のように入力して、いつでもサービスを停止できます。

sudo systemctl stop uwsgi

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

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

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

設定するNginxの構成は非常に簡単です。 既存の `+ nginx.conf `ファイルを修正し、新しいサーバーブロックを追加します。 編集のために ` sudo +`でファイルを開きます:

sudo nano /etc/nginx/nginx.conf

デフォルトのサーバーブロックの前に、独自のサーバーブロックを追加します。

http {

   . . .

   include /etc/nginx/conf.d/*.conf;




   server {
       listen 80 default_server;
       server_name localhost;

       . . .

作成したブロックは、uWSGIプロキシの構成を保持します。 以下の残りの構成アイテムは、このブロック内に配置されます。 サーバーブロックはポート80でリッスンし、サーバーのドメイン名またはIPアドレスに応答する必要があります。

server {
   listen 80;
   server_name ;
}

その後、すべてのリクエストを処理する単一のロケーションブロックを開くことができます。 このブロック内に、 `+ / etc / nginx / uwsgi_params `ファイルにある ` uwsgi +`パラメーターを含め、uWSGIがリッスンしているソケットにトラフィックを渡します。

server {
   listen 80;
   server_name ;

   location / {
       include uwsgi_params;
       uwsgi_pass unix:/run/uwsgi/myapp.sock;
   }
}

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

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

次のように入力して、Nginxの構成が有効であることをテストして確認できます。

sudo nginx -t

これがエラーなしで戻る場合は、次のように入力してサービスを開始します。

sudo systemctl start nginx

サービスを有効にして、起動時にNginxを起動します。

sudo systemctl enable nginx

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

image:https://assets.digitalocean.com/articles/nginx_uwsgi_wsgi_1404/full_app.png [完全なWSGIアプリ]

結論

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

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

Related