Python
nginx
Flask
gunicorn
TensorFlow

centos7にtensorflowとdlibで作られたflaskアプリを動くように構築する

タイトルにあるようにceontos7.1上にtensorflowを用いたflaskアプリが動く環境を構築します。
はじめにこちらの記事のようにconohaでcentos7.1の環境を立ち上げているものとします。

アプリの構成

python, flask, anaconda, tensorflow, dlib, opencv を使っています。
アプリの構成は以下のようになっています。

.
├── evaluation.py # 画像の判定を行う。dlib、opencv、tensorflowを利用。
├── guniconf.py
├── lib # dlibとtensorflowの学習済みデータを配置する場所
├── model.py # 画像データを扱いやすくするためにModelという形式を利用
├── static
│   ├── css
│   │   └── style.css
│   ├── images/
│   ├── js
│   │   └── main.js
│   └── robots.txt
├── templates
│   ├── index.html
│   └── layout.html
└── web.py # リクエストとか受けて、結果を返す

anacondaを入れる

pyenvを用いてanacondaを入れることにします。
centosでのpyenvのインストールはこちらを参考にしました。
http://qiita.com/glostuan/items/6030e309542615470e0d

$ sudo yum install epel-release # epelリポジトリ追加
$ sudo yum install gcc zlib-devel bzip2 bzip2-devel readline readline-devel sqlite sqlite-devel openssl openssl-devel git
$ git clone https://github.com/yyuu/pyenv.git ~/.pyenv
$ vim .bash_profile
# 追加する
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"

$ source .bash_profile # 反映
$ pyenv install --list
# anaconda3-4.0.0 があるか確認
$ pyenv install anaconda3-4.0.0
$ pyenv global anaconda3-4.0.0
$ pyenv versions
  system
* anaconda3-4.0.0 (set by /home/develop/.pyenv/version)

これでanacondaが使えます。

opencv類のインストール

はじめはopencvを入れるのに色々調べて、依存ライブラリを一つ一つ入れていこうと思いましたがその量が多く、うまく入れることができませんでした。
最終的に下記サイトにあるようにyumで古いopencvを入れて依存ライブラリをインストールしてから、古いopencvをremoveする方法を行い上手く入れることができました。
https://daichan.club/linux/78330
ただ、今回opnecvを動かすにはインストールされていなかったライブラリがあったので、別にyumでインストールしました。

$ sudo yum install epel-release # epelリポジトリを追加
$ sudo yum update
$ sudo yum install opencv # 古いopencvを入れる
# 依存ライブラリインストール

$ sudo yum remove opencv # 古いopencvを削除
$ conda install -c menpo opencv3
$ conda install -c menpo dlib
$ conda install -c meznom boost-python
$ conda install -c conda-forge tensorflow=1.1.0

# アプリのディレクトリに移動

$ python web.py server
# 起動と実行を確認
# エラーを読んで必要なライブラリをインストール
$ sudo yum install libpng12

次にnginx + gunicorn でアプリを稼働させます。
こちらの記事を参考にセットアップしていきます。
http://qiita.com/Alice1017/items/fb28e1055c6e498d021e

gunicorn と nginxのセットアップ

gunicornのインストールを行います。
pipから入れていいですが、他のものと統一した方がいいと思ったので、condaから入れています。

$ conda install -c anaconda gunicorn
$ gunicorn web:app --config guniconf.py
# /tmp/gunicorn_my_app.sockが生成されているか確認

guniconf.pyは以下のように設定しています。

guniconf.py
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/www/app/log/error.log'
loglevel = 'error'
logconfig = None

# Process Name
proc_name = 'gunicorn_my_app'

次にnginxのインストールを行います。
epelにあるnginxは古いので自分で最新のnginxを入れれるように、nginxのリポジトリを登録してインストールしましょう。

$ sudo vim /etc/yum.repos.d/nginx.repo
# 以下の内容を追加
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/
gpgcheck=0
enabled=1

$ sudo yum -y --enablerepo=nginx install nginx

nginxのconfを編集する。
念のために元のファイルの残しておきましょう。

$ cd /etc/nginx/conf.d/
$ sudo mv default.conf default.conf.org
$ sudo vim default.conf

以下のように設定します。

default.conf
upstream my_app_server{
    server unix:/tmp/gunicorn_my_app.sock;
}

server {
  listen 80 default_server;

  error_page 404 /404.html;

  error_page 500 502 503 504 /50x.html;
  location = /50x.html {
          root /usr/share/nginx/html;
  }

  location / {
          try_files $uri @my_app;
          client_max_body_size 20M;
  }

  location @my_app {
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_redirect off;
          proxy_request_buffering off;

          proxy_pass http://my_app_server;
  }

}

client_max_body_sizeproxy_request_bufferingは私が作ったアプリの関係でこのように設定しています。
適宜設定を見直していただければと思います。

nginxを再起動して動いているか確認します。

$ sudo systemctl restart nginx
$ sudo systemctl enable nginx
# guniconf.pyのあるディレクトリまで移動
$ gunicorn web:app --config guniconf.py
# ブラウザで確認

ブラウザで確認できたらctrl+cで止めます。

supervisorの導入

次にgunicornのデーモンの操作を楽に行うためにsupervisorを使おうと思います。
yumでいれるのが一番楽です。

$ sudo yum install supervisor
$ sudo vim /etc/supervisord.d/my_app.ini
my_app.ini
[program:my_app]
command = /home/develop/.pyenv/shims/gunicorn web:app --config /var/www/app/guniconf.py
directory = /var/www/app/
user = root 

supervisorをsystemdに登録します。

$ sudo vim /etc/systemd/system/supervisord.service
supervisord.service
[Unit]
Description=Supervisor process control system for UNIX
Documentation=http://supervisord.org
After=network.target

[Service]
ExecStart=/usr/bin/supervisord -n -c /etc/supervisord.conf
ExecStop=/usr/bin/supervisorctl $OPTIONS shutdown
ExecReload=/usr/bin/supervisorctl $OPTIONS reload
KillMode=process
Restart=on-failure
RestartSec=50s

[Install]
WantedBy=multi-user.target
$ sudo systemctl list-unit-files --type=service
# supervisordが登録されているか確認

$ sudo systemctl start supervisord
$ sudo systemctl status supervisord
$ sudo systemctl stop supervisord
# 上記3つがきちんと動いているか確認

$ sudo systemctl enable supervisord.service
# 自動起動になるように設定

# 正しく設定できていればすでに動いているが念のため実行して確認
$ sudo supervisorctl reread
$ sudo supervisorctl update
$ sudo supervisorctl start my_app

これでブラウザからアクセスできるはずです。