CentOS7でuWSGIとNginxを使用してFlaskアプリケーションを提供する方法
序章
このガイドでは、CentOS7でFlaskマイクロフレームワークを使用して簡単なPythonアプリケーションをセットアップします。 この記事の大部分は、アプリケーションを起動するようにuWSGIアプリケーションサーバーを設定し、フロントエンドのリバースプロキシとして機能するようにNginxを設定する方法について説明します。
前提条件
このガイドを開始する前に、サーバーでroot以外のユーザーを構成しておく必要があります。 このユーザーは、管理機能を実行できるように、sudo
特権を持っている必要があります。 これを設定する方法については、初期サーバー設定ガイドに従ってください。
uWSGI、アプリケーションサーバー、およびWSGI仕様の詳細については、このガイドのリンクされたセクションを参照してください。 これらの概念を理解すると、このガイドを理解しやすくなります。
続行する準備ができたら、読み進めてください。
CentOSおよびEPELリポジトリからコンポーネントをインストールします
最初のステップは、リポジトリから必要なすべてのピースをインストールすることです。 必要なコンポーネントのいくつかをインストールするには、いくつかの追加パッケージを含むEPELリポジトリを追加する必要があります。
次のように入力して、EPELリポジトリを有効にできます。
sudo yum install epel-release
システムでEPELリポジトリへのアクセスが構成されたら、必要なパッケージのインストールを開始できます。 Pythonコンポーネントをインストールして管理するために、Pythonパッケージマネージャーであるpip
をインストールします。 また、uWSGIのビルドに必要なコンパイラとPython開発ファイルも入手できます。 Nginxもインストールします。
次のように入力すると、これらのコンポーネントをすべてインストールできます。
sudo yum install python-pip python-devel gcc nginx
Python仮想環境を作成する
次に、Flaskアプリケーションをシステム上の他のPythonファイルから分離するために、仮想環境をセットアップします。
pip
を使用してvirtualenv
パッケージをインストールすることから始めます。
sudo pip install virtualenv
これで、Flaskプロジェクトの親ディレクトリを作成できます。 作成後、ディレクトリに移動します。
mkdir ~/myproject
cd ~/myproject
次のように入力することで、FlaskプロジェクトのPython要件を保存する仮想環境を作成できます。
virtualenv myprojectenv
これにより、Pythonとpip
のローカルコピーが、プロジェクトディレクトリ内のmyprojectenv
というディレクトリにインストールされます。
仮想環境内にアプリケーションをインストールする前に、それをアクティブ化する必要があります。 次のように入力してください。
source myprojectenv/bin/activate
プロンプトが変わり、仮想環境内で操作していることを示します。 このようになります(myprojectenv)user@host:~/myproject$
。
Flaskアプリケーションをセットアップする
仮想環境にいるので、FlaskとuWSGIをインストールして、アプリケーションの設計を開始できます。
FlaskとuWSGIをインストールします
pip
のローカルインスタンスを使用して、FlaskとuWSGIをインストールできます。 次のコマンドを入力して、これら2つのコンポーネントを取得します。
pip install uwsgi flask
サンプルアプリを作成する
Flaskが利用可能になったので、簡単なアプリケーションを作成できます。 Flaskはマイクロフレームワークです。 よりフル機能のフレームワークが持つ可能性のあるツールの多くは含まれていません。主に、Webアプリケーションの初期化を支援するためにプロジェクトにインポートできるモジュールとして存在します。
アプリケーションはもっと複雑かもしれませんが、Flaskアプリを単一のファイルで作成します。これをmyproject.py
と呼びます。
nano ~/myproject/myproject.py
このファイル内に、アプリケーションコードを配置します。 基本的に、フラスコをインポートして、Flaskオブジェクトをインスタンス化する必要があります。 これを使用して、特定のルートが要求されたときに実行する必要がある関数を定義できます。 コードapplication
でFlaskアプリケーションを呼び出して、WSGI仕様にある例を複製します。
from flask import Flask
application = Flask(__name__)
@application.route("/")
def hello():
return "<h1 style='color:blue'>Hello There!</h1>"
if __name__ == "__main__":
application.run(host='0.0.0.0')
これは基本的に、ルートドメインにアクセスしたときに表示するコンテンツを定義します。 終了したら、ファイルを保存して閉じます。
次のように入力して、Flaskアプリをテストできます。
python myproject.py
サーバーのドメイン名またはIPアドレスにアクセスし、その後にWebブラウザーの端末出力で指定されたポート番号(ほとんどの場合:5000
)を表示します。 次のように表示されます。
終了したら、ターミナルウィンドウでCTRL-Cを数回押して、Flask開発サーバーを停止します。
WSGIエントリポイントを作成する
次に、アプリケーションのエントリポイントとして機能するファイルを作成します。 これにより、uWSGIサーバーがアプリケーションと対話する方法がわかります。
ファイルをwsgi.py
と呼びます。
nano ~/myproject/wsgi.py
ファイルは非常にシンプルです。アプリケーションからFlaskインスタンスをインポートして、実行するだけです。
from myproject import application
if __name__ == "__main__":
application.run()
終了したら、ファイルを保存して閉じます。
uWSGIを構成する
これでアプリケーションが作成され、エントリポイントが確立されました。 これで、uWSGIに進むことができます。
uWSGIサービングのテスト
最初に行うことは、uWSGIがアプリケーションを提供できることを確認するためのテストです。
これを行うには、エントリポイントの名前を渡すだけです。 また、公開されているインターフェイスで開始されるようにソケットを指定し、uwsgi
バイナリプロトコルの代わりにHTTPを使用するようにプロトコルを指定します。
uwsgi --socket 0.0.0.0:8000 --protocol=http -w wsgi
Webブラウザの末尾に:8000
が追加されたサーバーのドメイン名またはIPアドレスにアクセスすると、次のようなページが表示されます。
正常に機能していることを確認したら、ターミナルウィンドウでCTRL-Cを押します。
これで仮想環境が完成したので、非アクティブ化できます。
deactivate
これで、すべての操作がシステムのPython環境に対して実行されます。
uWSGI構成ファイルの作成
uWSGIがアプリケーションに対応できることをテストしましたが、長期的な使用に対してより堅牢なものが必要です。 必要なオプションを使用してuWSGI構成ファイルを作成できます。
これをプロジェクトディレクトリに配置して、myproject.ini
と呼びましょう。
nano ~/myproject/myproject.ini
内部では、[uwsgi]
ヘッダーから始めて、uWSGIが設定を適用できるようにします。 wsgi.py
ファイルから拡張子を引いたものを参照して、モジュールを指定します。
[uwsgi]
module = wsgi
次に、uWSGIにマスターモードで起動し、実際のリクエストを処理するために5つのワーカープロセスを生成するように指示します。
[uwsgi]
module = wsgi
master = true
processes = 5
テスト中に、ネットワークポートでuWSGIを公開しました。 ただし、実際のクライアント接続を処理するためにNginxを使用します。これにより、リクエストがuWSGIに渡されます。 これらのコンポーネントは同じコンピューター上で動作するため、より安全で高速なUnixソケットが推奨されます。 ソケットをmyproject.sock
と呼び、このディレクトリに配置します。
また、ソケットのアクセス許可を変更する必要があります。 後でuWSGIプロセスの所有権をNginxグループに与えるので、ソケットのグループ所有者がソケットから情報を読み取ったり書き込んだりできることを確認する必要があります。 また、「バキューム」オプションを追加して、プロセスが停止したときにソケットをクリーンアップします。
[uwsgi]
module = wsgi
master = true
processes = 5
socket = myproject.sock
chmod-socket = 660
vacuum = true
最後に行う必要があるのは、die-on-term
オプションを設定することです。 これが必要なのは、Upstart initシステムとuWSGIが、異なるプロセス信号が何を意味するかについて異なる考えを持っているためです。 これを設定すると、2つのシステムコンポーネントが調整され、期待される動作が実装されます。
[uwsgi]
module = wsgi
master = true
processes = 5
socket = myproject.sock
chmod-socket = 660
vacuum = true
die-on-term = true
コマンドラインから行ったようにプロトコルを指定しなかったことにお気づきかもしれません。 これは、デフォルトでは、uWSGIがuwsgi
プロトコルを使用して通信するためです。これは、他のサーバーと通信するように設計された高速バイナリプロトコルです。 Nginxはこのプロトコルをネイティブに話すことができるため、HTTPによる通信を強制するよりもこれを使用する方が適切です。
終了したら、ファイルを保存して閉じます。
Systemdユニットファイルを作成する
次に注意する必要があるのは、Systemdサービスユニットファイルです。 Systemdユニットファイルを作成すると、CentOSのinitシステムが自動的にuWSGIを起動し、サーバーが起動するたびにFlaskアプリケーションを提供できるようになります。
/etc/systemd/system
ディレクトリ内に.service
で終わるユニットファイルを作成して開始します。
sudo nano /etc/systemd/system/myproject.service
内部では、メタデータと依存関係を指定するために使用される[Unit]
セクションから始めます。 ここにサービスの説明を入力し、ネットワークターゲットに到達した後にのみこれを開始するようにinitシステムに指示します。
[Unit]
Description=uWSGI instance to serve myproject
After=network.target
次に、[Service]
セクションを開きます。 プロセスを実行するユーザーとグループを指定します。 プロセスは関連するすべてのファイルを所有しているため、通常のユーザーアカウントにプロセスの所有権を付与します。 Nginxユーザーグループに所有権を付与して、uWSGIプロセスと簡単に通信できるようにします。
次に、作業ディレクトリをマップし、PATH
環境変数を設定して、プロセスの実行可能ファイルが(仮想環境内で)どこにあるかをinitシステムが認識できるようにします。 次に、サービスを開始するコマンドを指定します。 Systemdでは、仮想環境内にインストールされているuWSGI実行可能ファイルへのフルパスを指定する必要があります。 プロジェクトディレクトリに作成した.ini
構成ファイルの名前を渡します。
[Unit]
Description=uWSGI instance to serve myproject
After=network.target
[Service]
User=user
Group=nginx
WorkingDirectory=/home/user/myproject
Environment="PATH=/home/user/myproject/myprojectenv/bin"
ExecStart=/home/user/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
最後に、[Install]
セクションを追加します。 これにより、起動時にサービスを開始できるようにした場合に、このサービスを何にリンクするかがSystemdに通知されます。 このサービスは、通常のマルチユーザーシステムが稼働しているときに開始する必要があります。
[Unit]
Description=uWSGI instance to serve myproject
After=network.target
[Service]
User=user
Group=nginx
WorkingDirectory=/home/user/myproject
Environment="PATH=/home/user/myproject/myprojectenv/bin"
ExecStart=/home/user/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
[Install]
WantedBy=multi-user.target
これで、Systemdサービスファイルが完成しました。 今すぐ保存して閉じます。
これで、作成したuWSGIサービスを開始し、起動時に開始するように有効にすることができます。
sudo systemctl start myproject
sudo systemctl enable myproject
リクエストをプロキシするためのNginxの構成
これで、uWSGIアプリケーションサーバーが稼働し、プロジェクトディレクトリのソケットファイルに対する要求を待機しているはずです。 uwsgi
プロトコルを使用してそのソケットにWebリクエストを渡すようにNginxを構成する必要があります。
Nginxのデフォルトの構成ファイルを開くことから始めます。
sudo nano /etc/nginx/nginx.conf
すでにファイルにある他のserver {}
ブロックのすぐ上にあるサーバーブロックを開きます。
http {
. . .
include /etc/nginx/conf.d/*.conf;
server {
}
server {
listen 80 default_server;
. . .
Flaskアプリケーションのすべての構成をこの新しいブロック内に配置します。 まず、このブロックがデフォルトのポート80でリッスンし、サーバーのドメイン名またはIPアドレスに応答するように指定します。
server {
listen 80;
server_name server_domain_or_IP;
}
追加する必要がある他の唯一のものは、すべてのリクエストに一致するロケーションブロックです。 このブロック内に、設定が必要ないくつかの一般的なuWSGIパラメーターを指定するuwsgi_params
ファイルを含めます。 次に、uwsgi_pass
ディレクティブを使用して定義したソケットにリクエストを渡します。
server {
listen 80;
server_name server_domain_or_IP;
location / {
include uwsgi_params;
uwsgi_pass unix:/home/user/myproject/myproject.sock;
}
}
実際、アプリケーションを提供するために必要なのはこれだけです。 終了したら、ファイルを保存して閉じます。
nginx
ユーザーは、アプリケーションディレクトリのソケットファイルにアクセスするために、アプリケーションディレクトリにアクセスできる必要があります。 デフォルトでは、CentOSは各ユーザーのホームディレクトリを非常に制限的にロックダウンするため、nginx
ユーザーをユーザーのグループに追加して、アクセスを許可するために必要な最小限のアクセス許可を開くことができるようにします。
次のコマンドを使用して、nginx
ユーザーをユーザーグループに追加できます。 コマンドのuser
を自分のユーザー名に置き換えます。
sudo usermod -a -G user nginx
これで、ユーザーグループにホームディレクトリに対する実行権限を与えることができます。 これにより、Nginxプロセスは以下のコンテンツを入力してアクセスできるようになります。
chmod 710 /home/user
権限を設定すると、Nginx構成ファイルの構文エラーをテストできます。
sudo nginx -t
これが問題を示さずに戻った場合は、Nginxプロセスを開始して有効にし、起動時に自動的に開始するようにします。
sudo systemctl start nginx
sudo systemctl enable nginx
これで、Webブラウザでサーバーのドメイン名またはIPアドレスにアクセスして、アプリケーションを確認できるようになります。
結論
このガイドでは、Python仮想環境内に単純なFlaskアプリケーションを作成しました。 WSGI対応のアプリケーションサーバーがWSGIエントリポイントとインターフェイスできるようにWSGIエントリポイントを作成し、この機能を提供するようにuWSGIアプリサーバーを構成します。 その後、起動時にアプリケーションサーバーを自動的に起動するSystemdサービスユニットファイルを作成しました。 Webクライアントトラフィックをアプリケーションサーバーに渡し、外部リクエストを中継するNginxサーバーブロックを作成しました。
Flaskは非常にシンプルですが、非常に柔軟なフレームワークであり、構造や設計をあまり制限することなく、アプリケーションに機能を提供することを目的としています。 このガイドで説明されている一般的なスタックを使用して、設計したフラスコアプリケーションにサービスを提供できます。