最近、ユビレジでやったことを書いておこう。
ユビレジではRailsを使っていて、Herokuを使っていて、CloudFrontを使っている。CDNとうまくやるためにAssetSyncを使っていて、assets:precompile
されたCSSやJSや画像は自動でS3に転送され、なんかの設定をしておいた結果としてS3からCloudFront経由でダウンロードされるようになっている。
PDFとか動画とかどうしたらいいかなーという話と、slugsizeがでかくてつらい問題を、それぞれ解決を見たので、その話。
PDFをCDNからダウンロードさせる
PDFとか動画のファイルとか、サイズが大きいやつは/public
に入れない方が良い。/public
以下にあるファイルはRailsを通してHerokuからダウンロードされるが、これはあまり良い方法ではない。
- ファイルをただ転送している間、Railsのワーカプロセスが一個独占される
- ファイルサイズが大きいと、ダウンロードに30秒以上かかってしまい、Herokuにタイムアウトさせられる → ダウンロードが終わらない
- HerokuはUS EastのEC2で動いているので、ネットワーク的に遠くてダウンロードが遅い
-
/public
以下はgitで管理しているので、gitリポジトリがなんか予想に反して大きい
こういった感じの問題に対応するためにCDNというものが発明されて、弊社ではCloudFrontを使っているのだった。
さて、問題はS3にファイルを転送するタイミングで、「どうせ頻繁には更新しないんだから、手で転送すれば良いじゃん」というソリューションがある。がまあどう考えてもいまいちなので、Webアプリケーションのデプロイのタイミングで自動でS3にアップロードする方法が欲しいのだった。
- S3に転送する方法は?s3cmd?
- S3の認証とかどうするのか……
解決方法
普通にPDFもassets pipelineに突っ込めば良かった。方法。
- app/assets/pdfとかディレクトリを作って、PDFをそこにコピーする
-
config/application.rb
に次のように書く
config.assets.paths << "#{Rails.root}/app/assets/pdfs"
config.assets.precompile += (Rails.root + "app/assets/pdfs").children.map(&:to_s)
config.assets.paths
に足して、config.assets.precompile
に足せば良い。
これで、画像と同様にデプロイ時にCDNにアップロードしてくれる。Viewから参照するときは、ちゃんとasset_url
とか使うこと。
あっそういえば、gitリポジトリのサイズが肥大化する問題は解決していないのだった。まあ、こっちはリポジトリに全部入ってる嬉しさとのトレードオフなので……
slug sizeを抑える
さて、ここでよく考えてみると、Herokuにapp/assets
やpublic/assets
以下のファイルを保存しておく必要がないことに気づく。これらのファイルはCDNに転送されていてもう使われることはない。一方で、
- アプリケーションのスタートアップに時間がかかるなどの悪影響がある
- 画像ファイルを追加など繰り返すと最終的には
Compiled slug size is too large
とか言われてでプロイできなくなる
などの問題がある。これを消そう。
.slugignoreは使っては行けない
.slugignoreを使うと、assets:precompile
とかがうまくいかなくなる。Herokuにでプロイするときのメッセージを良く読むと、一番最初に
-----> Deleting 2 files matching .slugignore patterns.
とある。ので、.slugignoreにapp/assets
とか書く方法は失敗する。
Rakefileのタスクを書いて消す
などに書いてあることをやる。
Rakefileを使って、assets:precompile
後にapp/assets
とpublic/assets
のファイルを消す。注意事項としては、
- manifest.jsonは消さないようにする
- 上で書いた
application.rb
を書き換えて、app/assets/pdfs
が存在しない場合にアクセスしないようにする
などがある。
ユビレジでは、この結果としてslugsizeが280MBから137MBまで激減しました。