Herokuでpython+mecab+ffmpegを使う


はじめに

最近、ちまちまとdiscord上で動くchatbotを作っているのですが、やっぱり公開サーバーで動かさないと日常的に使えないのでHerokuにデプロイすることにしました。
ただ、無料枠のHerokuで動かそうとするといろいろと解決しないといけない課題が多くてひたすら逃げていたのですが、ようやく重い腰を上げてデプロイしたので、手順をメモがてら残してみたいと思います。

必要な要件

  • python (3.5以上)
  • mecab+mecab-ipadic
  • FFmpeg
  • open-jtalk

を使っているのでこれらが動かせる環境が必要。

Herokuでpython+mecabの環境づくりは下記の記事を参考にしました。
herokuでpython+django+scikit-learn+mecab(1)
ffmpegの環境づくりはこちらを参考にしました。
DiscordBotでyoutubeの音声をボイスチャットに流す

いざ、構築

condaとherokuの複数のビルドパックを使うのでheroku-buildpack-multiでアプリを作成する必要があります。気になるのはこのリポジトリがメンテナンスを終了していることでしょうか。

This buildpack is no longer actively maintained. The associated functionality exists natively on the Heroku platform. Please refer to https://devcenter.heroku.com/articles/buildpacks and https://devcenter.heroku.com/articles/using-multiple-buildpacks-for-an-app for documentation.

まず、ローカルでリポジトリを作ります。

$ git init
$ heroku create --buildpack https://github.com/heroku/heroku-buildpack-multi

使用するビルドパックは以下の通りです。

.buildpacks
https://github.com/Sashimimochi/conda-buildpack.git
https://github.com/sunny4381/heroku-buildpack-linuxbrew.git
https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest.git
https://github.com/Crazycatz00/heroku-buildpack-libopus.git

scikit-learnなどのCコンパイラを必要とするライブラリも使いたいのでcondaのビルドパックがいるのですが、pythonのバージョンを固定したいので以下のリポジトリをforkして自前で用意することにしました。
https://elements.heroku.com/buildpacks/teamupstart/conda-buildpack
minicondaのバージョン一覧はこちらから見れます。
https://repo.continuum.io/miniconda/

ちなみに、ものによっては、以下のような最近のpipでは廃止されたオプションが付いていてビルドエラーを起こすので注意。

pip install -r requirements.txt  --exists-action=w --allow-all-external | indent

上記の.buildpacksheroku-buildpack-linuxbrewを入れたのでbrewが使えるようになっています。brewで入れたいパッケージを.cellarで指定します。

.cellar
mecab
mecab-ipadic
open-jtalk

condaおよびpipでインストールするライブラリはconda-requirements.txtrequirements.txtに書いておきます。

Herokuにmecab-pythonをインストールしようとすると案の定、エラーが出ました。
herokuでpython+django+scikit-learn+mecab(1)では手動でインストールしていましたが、今回は、python3系を使うわけですし、mecab-python3ならはいったので、代わりにこちらを入れます。
Heroku mecabインストール時にエラー

あとはパスを指定してデプロイします。

$ heroku config:add LD_LIBRARY_PATH=/app/.linuxbrew/lib
$ heroku config:set MECAB_PATH=/app/.linuxbrew/lib/libmecab.so
$ git add .
$ git commit -m 'initial'
$ git push heroku master

滞りなく、一連のデプロイが進んで無事うまくいったように思えたのですが、最後のメッセージであえなく撃沈。

-----> Compressing...
 !     Compiled slug size: 3009.8M is too large (max is 500M).
 !     See: http://devcenter.heroku.com/articles/slug-size
 !     Push failed

https://devcenter.heroku.com/articles/slug-compiler#slug-size
上記のメッセージにもある通り、Herokuの無料枠のストレージサイズが500MBなのでデプロイ時にこの範囲内に収める必要があります。

容量を食っているのが、機械学習モデルだったので、Herokuでこれを動かすにはモデルのサイズを圧縮しておく必要がありました。
中でも一番のファイルサイズが大きいのがWord2Vecだったので、こちらのライブラリを使ってモデルサイズを圧縮しました。
50,000語程度にまで絞れば約60MBまで圧縮できます。
https://github.com/yagays/minify_w2v
重要語は以下から選択しました。
日本語を読むための語彙データベース Ver. 1.1
その他にもcacheを削除するなどいろいろ工夫の余地はありそうです。

これでリポジトリの容量をかなり圧縮できました。

大量のライブラリを使ってしまったせいで、これでもデプロイ時にpip installまでしてしまうと上限の500MBを超えてしまったので、起動時にpip installが走るようにしておきました。

Procfile
bot: bash run.sh
run.sh
pip install -r requirements.txt
python app.py

以上で、なんとか無事に動きました。

トラブルシューティング

Herokuリポジトリにログイン

Herokuにログインしてマニュアル操作するときは以下のようにすればログインしてbashコマンドが使えます。

heroku run bash

ログの確認

デプロイ後にアプリケーションのログが見たければ以下のコマンドで確認できます。

$ heroku logs

Herokuアプリケーションのログについて