こんにちは。かねしろ@pinkrootです。
今まで、flaskで作ったアプリはapache2 + wsgiの構成で動かしていたのですが、
Railsの勉強をしているうちに、nginx/unicorn構成も良いなぁと思いましたので、
類似環境でflaskアプリを動かすようにしてみました。
構成としてはnginx/gunicornとなり、gunicornをデーモン化させるためにsupervisorを利用しました。
なお、OSはubuntuです。AWS上にEC2インスタンスとして構築しました。
簡単ですが備忘録を残します。
必要なもののインストール
とりあえずざっくりと書きコマンドで必要なものをインストールします。
1 2 3 4 5 6 7 |
sudo apt-get install -y nginx sudo apt-get install -y gunicorn sudo apt-get install -y python-pip sudo apt-get install -y python-dev sudo apt-get install -y supervisor sudo apt-get install -y git |
うまくinstallできない場合はapt-getのupdateなどをお試しください。
flaskアプリを配備
動かしたいflaskアプリを
/var/www/sample
にでも配備しましょう。
動作確認だけで良ければ下記で十分かと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/usr/bin/env python # -*- encoding:utf8 -*- from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World!" if __name__ == "__main__": app.run(host='0.0.0.0', debug=True) |
ファイル名はapp.pyなどわかりやすい感じで。
次に、必要なモジュール群をpipでインストールしましょう。
上記だけであれば
1 2 |
sudo pip install Flask |
で十分かと思います。
viewをちゃんと書くならJinja2を入れたり、ログを出すためにloggingを入れたり、というのがバラバラと発生するようであれば、
プロジェクトディレクトリのトップに
requirements.txt
でも作成し、その中に
1 2 3 4 |
Flask Jinja2 logging |
とインストールしたいものを一覧で記載し、
1 2 |
sudo pip install -r requirements.txt |
とすると楽ができます。
なお、最近のトレンドはvenvを使ってプロジェクトごとに環境を作り分けるそうですが今回はやっていません。
この時点での動作を確認したい場合、
1 2 |
app.run(host='0.0.0.0', debug=True) |
となっている箇所を
1 2 |
app.run(host='0.0.0.0', debug=True, port=8080) |
という風にポート番号指定の形に書き換えてあげて、
1 2 |
python app.py |
とすると、
http://サーバのIPアドレス:8080
へアクセスすることでHello Worldが垣間見れるかと思います。
AWSの場合はセキュリティグループ設定で8080ポートへのアクセスを許可するように設定してあげてください。
ついでに後述する設定のために80へのアクセスも許可しておくとハッピーです。
nginxの設定
nginxの設定ファイルについては
/etc/nginx/sites-available
に設定ファイルを作成し、
/etc/nginx/sites-enabled
にシンボリックリンクを作成するのがセオリーなようですが、今回はシンボリックリンクだとうまく動作しなかったので、直接sites-enabled直下に設定ファイルを作成しました。
内容は下記のようになっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# gunicornとソケット通信を行うという設定 upstream my_app_server{ server unix:/tmp/gunicorn_my_app.sock fail_timeout=0; } server { # 独自ドメインを設定する場合は # server_name ドメイン名; server_name localhost; charset utf-8; client_max_body_size 75M; error_log /var/log/nginx/error.log; access_log /var/log/nginx/access.log; # ドメイン直下へのアクセスについての設定は @my_appを参照するように、という指定 location / { try_files $uri @my_app; } location @my_app { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_redirect off; proxy_pass http://my_app_server; } } |
上記設定に問題がない場合は
1 2 |
sudo /etc/init.d/nginx restart |
でnginxが起動してくれるはず。
この時点で
http://サーバのIPアドレス
へアクセスすると502エラーが表示されるはずです。
gunicornが起動していないので現時点だとそれで問題ありません。
他のエラーの場合はflaskのポート指定が間違えている可能性があるので見なおしてください。
もしくはAWSのセキュリティグループの設定ミスです。ポート開けてないとかそういう感じの。
gunicornの設定
まずはgunicornの設定ファイルを作りましょう。
flaskのプロジェクトディレクトリにgunicorn_conf.pyなどといった名前でファイルを作成し、内容を下記のようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import multiprocessing # Server Socket bind = 'unix:/tmp/gunicorn_my_app.sock' backlog = 2048 # Worker Processes workers = multiprocessing.cpu_count() * 2 + 1 worker_class = 'sync' worker_connections = 1000 max_requests = 0 timeout = 30 keepalive = 2 debug = False spew = False # Logging logfile = '/var/log/gunicorn/my_app.log' loglevel = 'info' logconfig = None # Process Name proc_name = 'gunicorn_my_app' |
ここまで問題なければ、flaskのディレクトリで
sudo gunicorn app:app –config /var/www/sample/gunicorn_tofu.conf.py
でgunicornが起動します。
nginxとgunicornが無事に連携して仕事をしてくれていれば、
http://サーバのIPアドレス
へアクセスした際に、今度はエラーではなくHello Worldがコンニチハするはずです。
supervisor
さて、gunicornさんですが、デーモン化をきちんと管理させるためにsupervisor経由で動かすようにしたほうが安全とのことです。
名残惜しいですが一旦
sudo pkill gunicorn
で起動プロセスを殺し、supervisorの設定を行いましょう。
/etc/supervisor/conf.d
の下にmy_appといったファイルを作成し、下記のような内容を記載します。
1 2 3 4 5 |
[program:my_app] command = gunicorn app:app --config /var/www/sample/gunicorn_conf.py directory = /var/www/sample user = root |
先程手動で起動させる際に用いたコマンドを記載し、ディレクトリとユーザを指定しているだけです。
本来的にはrootではないユーザを作成し、そのユーザで起動するようにしてあげたほうがセキュアではあるのですが今回はざっくりとrootで。
supervisor経由での起動は下記コマンドを用います。
流れとしては設定ファイルの再読み込み・更新・起動となります。
設定ファイルに更新がない場合は起動コマンドだけで十分かと。
1 2 3 4 |
sudo supervisorctl reread sudo supervisorctl update sudo supervisorctl start my_app |
念のために
1 2 |
ps alx|grep gunicorn |
コマンドなどでプロセスを確認すると、問題なくgunicornさんが仕事をしてくれているはずです。
これで当初目的としていた組み合わせの実現ができました。やった。
細かいところは省略したりもしていますし、venvやらユーザの指定やらは実施せずにざっくりと設定しているので、更に改善はできる設定ではありますが、参考になれば幸いです。
いいゴールデンウィークのスタートを切れました。
おしまい。