序章

このガイドでは、CentOS7でFlaskマイクロフレームワークを使用して簡単なPythonアプリケーションをセットアップします。 この記事の大部分は、アプリケーションを起動するようにGunicornアプリケーションサーバーを設定し、フロントエンドのリバースプロキシとして機能するようにNginxを設定する方法について説明します。

前提条件

このガイドを開始する前に、サーバーでroot以外のユーザーを構成しておく必要があります。 このユーザーは、管理機能を実行できるように、sudo特権を持っている必要があります。 これを設定する方法については、初期サーバー設定ガイドに従ってください。

アプリケーションサーバーがFlaskアプリとの通信に使用するWSGI仕様の詳細については、このガイドのリンクされたセクションをご覧ください。 これらの概念を理解すると、このガイドを理解しやすくなります。

続行する準備ができたら、読み進めてください。

CentOSおよびEPELリポジトリからコンポーネントをインストールします

最初のステップは、リポジトリから必要なすべてのピースをインストールすることです。 必要なコンポーネントのいくつかをインストールするには、いくつかの追加パッケージを含むEPELリポジトリを追加する必要があります。

次のように入力して、EPELリポジトリを有効にできます。

sudo yum install epel-release

システムでEPELリポジトリへのアクセスが構成されたら、必要なパッケージのインストールを開始できます。 Pythonコンポーネントをインストールして管理するために、Pythonパッケージマネージャーであるpipをインストールします。 また、Gunicornに必要なコンパイラと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とGunicornをインストールして、アプリケーションの設計を開始できます。

FlaskとGunicornをインストールします

pipのローカルインスタンスを使用して、FlaskとGunicornをインストールできます。 次のコマンドを入力して、これら2つのコンポーネントを取得します。

pip install gunicorn 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)を表示します。 次のように表示されます。

Flask sample app

終了したら、ターミナルウィンドウでCTRL-Cを数回押して、Flask開発サーバーを停止します。

WSGIエントリポイントを作成する

次に、アプリケーションのエントリポイントとして機能するファイルを作成します。 これにより、Gunicornサーバーがアプリケーションと対話する方法がわかります。

ファイルをwsgi.pyと呼びます。

nano ~/myproject/wsgi.py

ファイルは非常にシンプルです。アプリケーションからFlaskインスタンスをインポートして、実行するだけです。

from myproject import application

if __name__ == "__main__":
    application.run()

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

プロジェクトにサービスを提供するGunicornの能力をテストする

先に進む前に、Gunicornが正しく機能することを確認する必要があります。

これを行うには、エントリポイントの名前を渡すだけです。 また、公開されているインターフェイスで開始されるように、バインドするインターフェイスとポートを指定します。

cd ~/myproject
gunicorn --bind 0.0.0.0:8000 wsgi

Webブラウザの末尾に:8000が追加されたサーバーのドメイン名またはIPアドレスにアクセスすると、次のようなページが表示されます。

Flask sample app

正常に機能していることを確認したら、ターミナルウィンドウでCTRL-Cを押します。

これで仮想環境が完成したので、非アクティブ化できます。

deactivate

これで、すべての操作がシステムのPython環境に対して実行されます。

Systemdユニットファイルを作成する

次に注意する必要があるのは、Systemdサービスユニットファイルです。 Systemdユニットファイルを作成すると、CentOSのinitシステムが自動的にGunicornを起動し、サーバーが起動するたびにFlaskアプリケーションを提供できるようになります。

/etc/systemd/systemディレクトリ内に.serviceで終わるファイルを作成して開始します。

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

内部では、メタデータと依存関係を指定するために使用される[Unit]セクションから始めます。 ここにサービスの説明を入力し、ネットワークターゲットに到達した後にのみこれを開始するようにinitシステムに指示します。

[Unit]
Description=Gunicorn instance to serve myproject
After=network.target

次に、[Service]セクションを開きます。 プロセスを実行するユーザーとグループを指定します。 プロセスは関連するすべてのファイルを所有しているため、通常のユーザーアカウントにプロセスの所有権を付与します。 Nginxユーザーグループに所有権を付与して、Gunicornプロセスと簡単に通信できるようにします。

次に、作業ディレクトリをマップし、PATH環境変数を設定して、プロセスの実行可能ファイルが(仮想環境内で)どこにあるかをinitシステムが認識できるようにします。 次に、サービスを開始するコマンドを指定します。 Systemdでは、仮想環境内にインストールされているGunicorn実行可能ファイルへのフルパスを指定する必要があります。

3つのワーカープロセスを開始するように指示します(必要に応じてこれを調整します)。 また、myproject.sockというプロジェクトディレクトリ内にUnixソケットファイルを作成してバインドするように指示します。 007のumask値を設定して、他のアクセスを制限しながら、所有者とグループへのアクセスを許可するソケットファイルが作成されるようにします。 最後に、WSGIエントリポイントのファイル名を渡す必要があります。

[Unit]
Description=Gunicorn 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/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi

ファイルに追加する必要がある最後の部分は、[Install]セクションです。 これにより、起動時にサービスを開始できるようにした場合に、このサービスを何にリンクするかがSystemdに通知されます。 このサービスは、通常のマルチユーザーシステムが稼働しているときに開始する必要があります。

[Unit]
Description=Gunicorn 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/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi

[Install]
WantedBy=multi-user.target

これで、Systemdサービスファイルが完成しました。 今すぐ保存して閉じます。

これで、作成したGunicornサービスを開始し、起動時に開始するように有効にすることができます。

sudo systemctl start myproject
sudo systemctl enable myproject

リクエストをプロキシするためのNginxの構成

これで、Gunicornアプリケーションサーバーが稼働し、プロジェクトディレクトリのソケットファイルに対するリクエストを待機しているはずです。 構成ファイルにいくつかの小さな追加を行うことにより、そのソケットに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;
}

追加する必要がある他の唯一のものは、すべてのリクエストに一致するロケーションブロックです。 このブロック内で、Gunicornがリモートクライアント接続に関する情報を取得できるように、いくつかの標準プロキシHTTPヘッダーを設定します。 次に、Systemdユニットファイルで指定したソケットにトラフィックを渡します。

server {
    listen 80;
    server_name server_domain_or_IP;

    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://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アドレスにアクセスして、アプリケーションを確認できるようになります。

Flask sample app

結論

このガイドでは、Python仮想環境内に単純なFlaskアプリケーションを作成しました。 WSGI対応のアプリケーションサーバーがWSGIエントリポイントとインターフェイスできるようにWSGIエントリポイントを作成し、この機能を提供するようにGunicornアプリサーバーを構成します。 その後、起動時にアプリケーションサーバーを自動的に起動するSystemdユニットファイルを作成しました。 Webクライアントトラフィックをアプリケーションサーバーに渡し、外部リクエストを中継するNginxサーバーブロックを作成しました。

Flaskは非常にシンプルですが、非常に柔軟なフレームワークであり、構造や設計をあまり制限することなく、アプリケーションに機能を提供することを目的としています。 このガイドで説明されている一般的なスタックを使用して、設計したフラスコアプリケーションにサービスを提供できます。