yamachan.log

紫陽花

AmazonCloudFrontでRailsのAssets周りにある静的ファイルをCDN配信する

AmazonCloudFrontでRailsのAssets周りにある静的ファイルをCDN配信する

RailsでアプリのassetsをCloudFront経由で配信した時の話

問題と解決

Railsのアクションキャッシュ導入時、Webサーバ内からassetsの配信を行っていた。 その場合、Deploy時にassets precompileを実行しmanifestの更新を行うと、 キャッシュしていたviewのCSSがmanifest更新に伴って参照できなくなり、表示が崩れてしまうという問題が発生した。 この問題を解決するために、Deploy時にassets以下のファイルをS3に置いてCloudFront経由で配信する形式に変更することにした。

CDN

CDN (コンテンツデリバリーネットワーク) Akamaiが1990年代に提唱したコンテンツを配信するネットワーク

参考: 第1回 CDN の 仕組み (CDNはどんな技術で何が出来るのか)

Amazon CloudFront

AWSが提供するCDNサービス 今回はCloudFrontを使いました

CloundFront

Amazon S3

SimpleStrageService Sが3つでS3 「超便利ファイル置き場」

今回は静的ファイルをS3に置いてCloudFrontが参照する

S3

CDNを導入すると何が良いの?

パフォーマンスが良くなる。(高速化) 世界中のどこからアクセスされてもある程度一定のレスポンス速度を担保できる。

やること

  • S3バケットを用意
  • CloudFront側の設定
  • Rails側の設定
  • sprocketsのmanifestファイル
  • S3でクロスオリジンの設定

S3バケットを用意

assetsファイルはS3バケットに置くので、バケットを用意します

ドメイン

assets.service-domain.com

CloudFrontの設定

CIでprecompileを行いS3にファイルを置く

DeployフローでCIを通す前提の話です。普段はCircleCIを利用しています

  • 1.テスト実行
  • 2.テスト成功
  • 3.assets precompile を実行
  • 4.compileファイルをs3にupload
  • 5.デプロイ
machine:
  environments:
  timezone:
    Japan
  ruby:
    version: 2.2.3
  services:
    - redis

deployment:
  production:
    branch: master
    commands:
     - ./deploy/circleci/upload_assets.sh
     - ./deploy/circleci/deployment.sh
#!/bin/sh
EXPIRE=`ruby -e "puts (Time.now + (60*60*24*30)).strftime('%Y-%m-%d')"`

bundle exec rake assets:precompile RAILS_ENV=production
mv ./public/assets/.sprockets-manifest-* ./public/assets/.sprockets-manifest-8jednoecyllbeucnvekdwhbqlkjwhhdq.json
aws s3 sync ./public/assets s3://assets.service-domain.com/assets --region ap-northeast-1 --expires $EXPIRE

shellファイルの先頭に #!/bin/sh (シバン))を記述することはマナー (一応記述がなくても動く)

EXPIREでS3内のファイル有効期限を指定 (今回は30日間にセット)

mv コマンドで生成したmanifestの32文字の乱数部分を同一のものに変更 (今回は決めの値を記述しましたが、32文字であれば何でも大丈夫)

Rails側の設定

Rails側でassetsの配信設定を行います

config/environments/production.rb

config.action_controller.asset_host = ""

デフォルトではコメントアウトになっています、asset_hostに配信のURLを指定します。

config.acrion_controller.asset_host = "https://assets.service-domain.com"

precompile後のファイルはS3に置きますが、manifestファイルはWebサーバーのpublic/assets以下に置かなければうまく参照できず正しく表示されません。 Deployのタスク内でmanifestファイルのみをs3から取ってくる処理を書きます。

execute "aws s3 cp assets manifest" do
  cwd release_path
  command "aws s3 cp s3://assets.service-domain.com/assets/.sprockets-manifest-8jednoecyllbeucnvekdwhbqlkjwhhdq.json ./public/assets/"
  environment "RAILS_ENV" => rails_env
end

今回はaws s3 cpコマンドで設置方法

sprocketsのmanifestファイル

  1. そもそもmanifestファイルってなんのために存在するの?
  2. manifestファイルではコンパイルされたassetsファイルのルートを指示する
.sprockets-manifest-8jednoecyllbeucnvekdwhbqlkjwhhdq.json

S3でクロスオリジンの設定

RailsでFontawsomeなどを利用している場合、上記の手順でDeployし表示できるが、Fontawsomeのアイコンが豆腐になってしまう問題が発生する。 この問題はクロスオリジンの設定をすることで解決できる。

うまく設定できるまで幾つか地雷を踏みましたがうまく設定できました。