Denkinovelという、ノベルゲーム風の小説を書ける投稿サイトをRails + Herokuで開発しています。
サービスの特性上assetsに多くの画像、音楽ファイルを置いているので、HerokuのSlug size 200MB縛りがきつくなってきました。こんな状況のためにasset_syncというgemがあるので、使ってみることにしました。Heroku公式で推奨しているgemです。
herokuでのasset_syncの使い方は、英語公式がこちら。https://devcenter.heroku.com/articles/cdn-asset-host-rails31
ボランティアによる日本語訳もあります。ありがたい。こちらです。https://github.com/herokaijp/devcenter/wiki/cdn-asset-host-rails31
インストール
heroku公式の解説に従って
gem "asset_sync"
をGemfileに書いて
$ bundle
します。
このあとも解説のとおりにherokuの環境変数を設定します。
$ heroku config:add FOG_PROVIDER=AWS
$ heroku config:add AWS_ACCESS_KEY_ID=xxx
$ heroku config:add AWS_SECRET_ACCESS_KEY=yyy
$ heroku config:add FOG_DIRECTORY=yourappname-assets
でherokuの環境変数を追加。
このあと、
config/environments/production.rb内の設定もコメントアウトを外して設定を追加。
config.action_controller.asset_host = "https://#{ENV['FOG_DIRECTORY']}.s3.amazonaws.com"
とします。
asset_syncの設定変更
S3を日本のリージョンで使っている場合は、asset_syncの設定を変える必要があります。
を参考に、
$ rails g asset_sync:install --provider=AWS
します。これで/config/initializer/asset_sync.rb が誕生するので、設定を書き加えましょう。
東京リージョンなので、デフォルトのus-east-1ではなく
config.fog_region = 'ap-northeast-1'
に修正します。
で推奨されているように、
/config/initializer/asset_sync.rb
では、
if defined?(AssetSync)
AssetSync.configure do |config|
config.fog_provider = 'AWS'
config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID']
config.aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
config.fog_directory = ENV['FOG_DIRECTORY']
# Increase upload performance by configuring your region
config.fog_region = 'ap-northeast-1'
#
# Don't delete files from the store
# config.existing_remote_files = "keep"
#
# Automatically replace files with their equivalent gzip compressed version
# config.gzip_compression = true
#
# Use the Rails generated 'manifest.yml' file to produce the list of files to
# upload instead of searching the assets directory.
# config.manifest = true
#
# Fail silently. Useful for environments such as Heroku
# config.fail_silently = true
end
end
というように、
if defined?(AssetSync)
...
end
で囲みます。囲まないでデプロイしたあと、ウェブサイトにアクセスすると**uninitialized constant AssetSync (NameError)**なるエラーが発生しました。注意。
プリコンパイル
asset_syncの設定が完了したら、ローカル環境でプリコンパイルします。assetsのサイズが小さければ、ローカルでのプリコンパイルは必要ないのですが、僕が開発しているDenkinovelの場合、サービスの特性上assetsの容量が大きくならざるをえません。
slug sizeが100MBを越えていたので、プリコンパイルしないでgit push heroku masterするとheroku側でのコンパイルに異様に時間がかかり、time outしてしまいました。なのであらかじめローカルでプリコンパイルしました。
僕はzshを使っているので、.zshenvに
export AWS_ACCESS_KEY_ID=xxx
export AWS_SECRET_ACCESS_KEY=yyy
export FOG_DIRECTORY=yourapp-dev-assets
と設定を書き加え、zshを再起動する。
そして
$ rake assets:precompile
すると、ローカルの/public/assets内にassetsが入ると同時にS3にもプリコンパイルされたassetsファイルがアップロードされます。
.slugignoreを作る
assetsはS3にアップロードできました。しかし、まだこのままではslug sizeは減りません。
Heroku公式ドキュメントを参考に、.slugignoreを作りましょう。.slugignoreは名前のとおり、Heroku上でslugを作る際、指定したファイルを無視してslugを構築してくれます。
/spec
/app/assets
*.jpg
*.png
*.mp3
*.ogg
僕は.slugignoreをこう書いて、プロジェクトディレクトリの一番上(.gitignoreがあるのと同じ場所)に置きました。
/spec
/app/assets
だけでいいと思ったんですが、そう書いても.jpgや.mp3を無視してくれませんでした。
デプロイ
.slugignoreができたらとうとうデプロイです。
$ git add . -A
$ git commit -m プリコンパイルした
で変更をcommmitしたら、herokuにpushします。
$ git push heroku master
で、デプロイ完了です。
slug sizeが大幅に小さくなっていることを確認してください。Denkinovelの場合、140MB以上あったのが18MBになりました。
slug size縛りがこうしてなくると、VPSに移行する動機が弱くなってきますね……そのうち移行しようとは思っているのですが、ユーザーが少ないうちはこれで問題なさそうです。