最終更新日:2023/01/01 原本2019-11-07

NGINX + NGINX Unit + Flask で PythonのWeb アプリを動かす

NGINX + NGINX Unit + Flask でPythonのWebアプリ開発

Python で Web 開発をしようと思い、Python の Web アプリの環境構築を行いました。
これまでは、NGINX <-> uwsgi <-> Flaskという構成が主流でしたが、2018 年 4 月に NGINX 社が軽量な AP サーバーNGINX Unitをリリースしました。
今回は NGINX Unit を使用し、NGINX <-> NGINX Unit <-> Flaskという構成で Web アプリケーションの環境を構築していきます。

環境

Web サーバーとしてNGINXを、AP サーバーとしてNGINX Unitを、Python の Web フレームワークにFlaskを使用します。

  • OS : CentOS7
  • Python : 3.7.4
  • NGINX : 1.16.1
  • NGINX Unit : 1.10.0
  • Flask : 1.1.1

備考

サーバーは Vagrant と VirtualBox の仮想環境を使用します。
プライベートネットワークを有効にしてください。

$ vagrant init centos/7
$ vi Vagrantfile
- # config.vm.network "private_network", ip: "192.168.33.10"
+ config.vm.network "private_network", ip: "192.168.33.10"
$ vagrant up
$ vagrant ssh

vagrant sshで仮想環境に接続し、selinux を無効にしてください。

$ sudo vi /etc/selinux/config
- SELINUX=enforcing
+ SELINUX=disabled
$ sudo reboot

Python の開発環境構築

仮想環境に Python の開発環境を構築します。
CentOS にはデフォルトでPython 2.7.5がインストールされています。

$ python --version
Python 2.7.5

今回はPython 3.7.4を利用します。

CentOS に Python3 をインストール

Python の公式ページの手順を参考にして CentOS に Python をインストールします。
まずは必要なツールをインストールします。

$ sudo yum -y groupinstall "development tools"
$ sudo yum install -y bzip2-devel gdbm-devel libffi-devel libuuid-devel ncurses-devel openssl-devel readline-devel sqlite-devel tk-devel wget xz-devel zlib-devel

インストーラーを Python の公式ページからwgetでダウンロードします。
ダウンロード後に解凍します。

$ wget https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tgz
$ tar xzf Python-3.7.4.tgz

ソースコードを解凍後にビルドします。

$ cd Python-3.7.4
$ ./configure --enable-shared
$ make
$ sudo make install
$ sudo sh -c "echo '/usr/local/lib' > /etc/ld.so.conf.d/custom_python3.conf"
$ sudo ldconfig

ビルドしたコマンドは/usr/local/bin配下ににインストールされます。

$ which python
/usr/bin/python
$ which python3
/usr/local/bin/python3
$ python3 --version
Python 3.7.4
$ which pip3
/usr/local/bin/pip3

最後にpipをアップグレードします。

$ pip3 install --upgrade pip --user

ローカルのbinに最新版のpipコマンドがインストールされます。

$ which pip
~/.local/bin/pip
$ pip --version
pip 19.2.3 from /home/vagrant/.local/lib/python3.7/site-packages/pip (python 3.7)

Python の環境構築は以上になります。

Python の仮想環境の作成

プロジェクトごとにパッケージを切り替えて管理するために、Python の仮想環境を構築します。
Python には仮想環境の作成をサポートしている標準モジュールとしてvenvが用意されています。
venvを使用して仮想環境を作成します。

# flask_sampleという仮想環境を作成
$ python3 -m venv flask_sample

venv で作成した仮想環境を有効化します。

$ source flask_sample/bin/activate
(flask_sample)$

venvモジュールで作成されたディレクトリ内のactivateスクリプトを実行することで、仮想環境を有効化することができます。
仮想環境を有効化するとプロンプトの先頭に(仮想環境名)が表示されます。
作成した仮想環境のディレクトリに移動して構成を確認します。

(flask_sample)$ cd flask_sample
(flask_sample)$ ls
bin  include  lib  lib64  pyvenv.cfg

binディレクトリには仮想環境を有効化するactivateスクリプトや、Python のパッケージ管理ツールpipコマンドが格納されています。
仮想環境内で pip コマンドを実行する際は、このディレクトリ内のコマンドが実行されます。
インストールされたパッケージはlib/python3.7/site-packageslib64/python3.7/site-packages内にインストールされます。
仮想環境内では、Python 本体のsite-packagesディレクトリを無視してこちらのディレクトリ内のパッケージを使用します。
Python 本体のパッケージを汚すことなくアプリ開発を行うことができます。

Flask でサンプルプロジェクトの作成

Flaskは Python の小規模なマイクロフレームワークです。標準で掲載されている機能は最小限になっており、小規模なアプリケーションを開発する際に用いられます。
プラグインが提供されているため、機能を拡張することができます。
初めから大規模なアプリケーションを開発する場合はDjangoを使用します。

Flask のインストール

venv 仮想環境で、Flask をインストールします。

(flask_sample)$  pip install Flask

アプリケーションの作成

サンプルプロジェクトの構成は以下のようにします。

/sample
  |- app.py
  |- templates
        |- index.html
        |- post.html

それぞれのコードは以下のように実装します。

app.py
from flask import Flask ,render_template,request

application = Flask(__name__)

@application.route('/')
def index():
    return render_template('index.html')

@application.route('/sample',methods=['POST'])
def sample():
    message = request.form['message']
    return render_template('post.html',message=message)

if __name__=="__main__":
    application.run(host='0.0.0.0')
index.html
<html>
  <head>
    <meta charset="utf-8" />
    <title>Flask Sample</title>
  </head>
  <body>
    <h1>Flask Smaple</h1>
    <form action="sample" method="post">
      <input type="text" name="message" />
      <input type="submit" value="送信" />
    </form>
  </body>
</html>
post.html
<html>
  <head>
    <meta charset="utf-8" />
    <title>Flask Sample</title>
  </head>
  <body>
    <h1>Flask Smaple</h1>
    メッセージ:{{message}}
  </body>
</html>

実装後にapp.pyを実行し、Flask のアプリケーションを起動します。

(flask_sample)$ python /sample/app.py
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

起動後にブラウザでhttp://仮想環境のプライベートIP:5000/にアクセスすると、index.htmlが表示されます。
確認できればFlaskの動作確認は終了です。次は、NGINX Unit で AP サーバーを構築します。

NGINX Unit

NGINX Unit は NGINX 社が開発した、軽量なアプリケーションサーバーです。
複数の言語のアプリケーションを実行することができるため、同じサーバー上で異なる言語のアプリケーションを運用できます。
言語はPython,PHP,Go,Perl,Ruby,Node.js,Javaに対応しています。
さらに、言語内の異なるバージョンを共存させて実行することができます。(Python2.7 と Python3 など)
API や JSON 経由で、サーバーを停止することなくリアルタイムに設定を変更することができるため、サービスを停止させることなくシームレスに設定の変更を行うことができます。

インストール

公式ドキュメントに各 OS ごとのインストール方法が公開されています。

venv 仮想環境から出て、yum のリポジトリを追加します。

(flask_sample)$ deactivate
$ sudo vi /etc/yum.repos.d/unit.repo
[unit]
name=unit repo
baseurl=https://packages.nginx.org/unit/centos/$releasever/$basearch/
gpgcheck=0
enabled=1

インストールします。

$ sudo yum install -y unit
$ sudo yum install -y unit-devel unit-go unit-jsc8 unit-perl unit-php unit-python

NGINX Unit の自動起動を設定します。

$ sudo systemctl enable unit
Created symlink from /etc/systemd/system/multi-user.target.wants/unit.service to /usr/lib/systemd/system/unit.service.
$ sudo service unit start
Redirecting to /bin/systemctl start unit.service
$ sudo service unit status
Redirecting to /bin/systemctl status unit.service
● unit.service - NGINX Unit
   Loaded: loaded (/usr/lib/systemd/system/unit.service; enabled; vendor preset: disabled)
   Active: active (running) since 火 2019-11-05 15:42:47 UTC; 7h ago
 Main PID: 5714 (unitd)
   CGroup: /system.slice/unit.service
           ├─5714 unit: main v1.12.0 [/usr/sbin/unitd --log /var/log/unit/unit.log --pid /var/run/unit/unit.pid --no-daemon]
           ├─5716 unit: controller
           └─5717 unit: router

service unit statusで NGINX Unit が起動できていることが確認できます。

Flask 用の設定を行う

NGINX Unit で Flask のアプリケーションを実行する設定を行います。
設定ファイルを NGINX Unit のソケットから GET して、Flask のアプリケーションを NGINX Unit にロードする設定を行います。
NGINX Unit のコントロール用の Unix ソケットは、/var/run/unit/control.sockにあります。(OSによって場所は異なります)

$ cd /sample
$ sudo curl --unix-socket /var/run/unit/control.sock http://localhost/config/ > config.json
$ vi config.json
{
  "listeners": {
    "*:8080": {
      "pass": "applications/flask_app"
    }
  },

  "applications": {
    "flask_app": {
      "type": "python",
      "processes": 2,
      "path": "/sample/",
      "module": "app"
    }
  }
}
  • listeners : ポートの設定を行います。*:8080passの値が、applicationsの階層と紐ずいています。
  • applications :
    • type : モジュール名(言語)を指定
    • processes : worker 数
    • path : Python プログラムを配置しているパス
    • module : 起動するファイル。ファイル名から拡張子を除いた形で指定

作成した設定ファイルを NGINX Unit のソケットに対して PUT して、設定の反映をします。

$ sudo curl -X PUT --data-binary @config.json --unix-socket /var/run/unit/control.sock http://localhost/config
{
    "success": "Reconfiguration done."
}

successが帰ってくると設定が完了しています。設定内容の確認もできます。

$ sudo curl --unix-socket /var/run/unit/control.sock http://localhost/
{
    "certificates": {},
    "config": {
        "listeners": {
            "*:8080": {
                "pass": "applications/flask_app"
            }
        },

        "applications": {
            "flask_app": {
                "type": "python",
        "processes": 2,
                "path": "/sample/",
                "module": "app"
            }
        }
    }
}

仮想環境を起動し、http://localhost:8080/にアクセスします。

$ source venv/bin/activate
(flask_sample)$ curl http://localhost:8080/
<html>
  <head>
    <meta charset="utf-8" />
    <title>Flask Sample</title>
  </head>
  <body>
    <h1>Flask Smaple</h1>
    <form action="sample" method="post">
      <input type="text" name="message" />
      <input type="submit" value="送信" />
    </form>
  </body>
</html>

index.htmlが表示されれば構築完了です。ブラウザでアクセスしてもindex.htmlが表示されます。
NGINX Unit の構築は以上です。次は Web サーバーの NGINX を構築します。

NGINX

軽量・高速が特徴のオープンソースの Web サーバー で、Apache の代替になりうるサーバーとして注目されています。
Apache と比べるとスケーラビリティの面で優れており、処理性能・並列処理・メモリ使用量の小ささなどが特徴として挙げられます。今回はプロキシサーバーとして利用します。

NGINX を CentOS にインストールする

NGINX は公式に yum のリポジトリを公開しているため、そのリポジトリからインストールします。
公式ページの記述を参考にリポジトリを追加してインストールを行います。

リポジトリの追加

一度 Python 仮想環境から出ます。
yum リポジトリの追加を行います。/etc/yum.repos.d/NGINX.repoを追加します。

$ sudo vi /etc/yum.repos.d/NGINX.repo
[NGINX]
name=NGINX repo
baseurl=http://NGINX.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1

インストール

リポジトリの確認を行います。

$ sudo yum info nginx
Available Packages
Name        : NGINX
Arch        : x86_64
Epoch       : 1
Version     : 1.16.1
Release     : 1.el7_4.ngx
Size        : 754 k
Repo        : NGINX/x86_64
Summary     : High performance web server
URL         : http://NGINX.org/
License     : 2-clause BSD-like license
Description : NGINX [engine x] is an HTTP and reverse proxy server, as well as
            : a mail proxy server.

yum infoコマンドでリポジトリに NGINX があるとこが確認できたらインストールを行います。

$ sudo yum install nginx

自動起動を設定し、
NGINX を起動します。

$ sudo systemctl enable nginx
$ sudo service start nginx
$ ![nginx.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239179/0d818e0a-7aee-8a07-af95-72d34dfaa824.png)
service status nginx
● NGINX.service - NGINX - high performance web server
   Loaded: loaded (/usr/lib/systemd/system/NGINX.service; enabled; vendor preset: disabled)
   Active: active (running)

NGINX を起動後にブラウザでhttp://仮想環境のプライベートIPにアクセスします。
以下のうような画面が表示されれば起動が完了です。

nginx.png

NGINX と NGINX Unit の連携

NGINX の設定ファイル

NGINXNGINX Unit の前の WEB サーバーやプロキシサーバーとして運用します。
アプリケーションへのリクエストを Nginx Unit にプロキシします。
NGINX の設定ファイルは/etc/nginx/conf.dにあります。

$ sudo vi /etc/nginx/conf.d/app.conf
upstream unit-python {
        server 127.0.0.1:8080;
}
server {
    listen 80;
    server_name localhost;

    location ~ / {
      proxy_pass http://unit-python;
      proxy_set_header Host $host;
    }
}

NGINX を再起動し、http://localhost/ にアクセスします。

$ sudo service restart nginx
$ curl http://localhost/
<html>
  <head>
    <meta charset="utf-8" />
    <title>Flask Sample</title>
  </head>
  <body>
    <h1>Flask Smaple</h1>
    <form action="sample" method="post">
      <input type="text" name="message" />
      <input type="submit" value="送信" />
    </form>
  </body>
</html>

'index.html'が表示されればプロキシ設定が完了です。ブラウザでhttp://仮想環境のプライベートIPにアクセスしindex.htmlを確認することができます。
以上でPythonのWebアプリの環境構築は終了です。

まとめ

NGINX + NGINX Unit + Flask で WEB アプリケーションの環境構築を行いました。
NGINX Unit はマイクロサービスの運用に特化しているため、今後も注目されて行くと思います。
継続して触れていきたいと思います。