【Rails】asset_syncを利用してCloudFront + S3からアセットファイルを配信する

Ruby

こんにちは。Enjoy IT Life管理人の仁科(@nishina555)です。

Railsアプリケーションで利用されるアセットファイルは、デフォルトの設定ではアプリケーションサーバに配置されています。

今回はアセットファイルを外部リソースへ配置し、配信できるようにするasset_syncgemの使い方について紹介します。

asset_syncを導入するメリットは以下の2点です。

asset_sync導入のメリット
  • アセットファイルを参照する際にアプリケーションサーバーへアクセスする必要がなくなるため、サーバー負荷を軽減できる
  • CDNを利用することでキャッシュを活用した高速な配信が可能になる

今回利用する検証環境の詳細は以下の通りです。

  • ストレージ: S3
  • CDN: CloudFront
  • asset_syncのバーション: 2.12.1
  • railsのバージョン: 6.0.3.2
  • Railsの実行環境: 本番(production)

下準備: サンプル画像を表するRailsアプリケーションの作成

アセットファイルの配信元が変更されているか検証するためにサンプルアプリケーションを作成します。

app/assets/images配下に適当なイメージ画像を配置します。今回はgroup_young_world.pngというサンプル画像を用意しました。

ルーティングの編集をします。

config/routes

Rails.application.routes.draw do
+ root to: 'home#index'
end

トップページを表示するコントーラー・ビューを作成します。

$ bundle exec rails g controller home index

app/views/home/index.html.erb

<%= image_tag 'group_young_world.png', width: '500' %>

assets:precompileを実行とアプリケーションの起動をします。

$ bundle exec rails assets:precompile RAILS_ENV=production
$ bundle exec rails s -e production

トップページを表示するとサンプル画像が表示されます。ソースコードを確認するとassets配下のファイルを直接参照していることがわかります。

S3バケットを作成する

S3のダッシュボードの『バケットを作成する』を選択します。

必要項目を入力してバケットを作成します。
Webサイトを公開状態にするため、アクセス許可の設定で『パブリックアクセスをブロック』のチェックを外します。

一覧にS3バケットが表示されればOKです。

Railsアプリケーションの修正

Gemのインストールをします。fog-awsはAWS連携に必要なクラウドサービスライブラリです。

Gemfile

gem 'asset_sync'
gem 'fog-aws'

asset_syncのinitializerのインストールと設定を行います。

$ bundle exec rails g asset_sync:install --provider=AWS

config/initializers/asset_sync.rb

if defined?(AssetSync)
  AssetSync.configure do |config|
    config.fog_provider = 'AWS'
    config.fog_directory = 'rails-app-production-assets' # S3バケット名
    config.aws_access_key_id = 'xxx' # IAMユーザのアクセスキー
    config.aws_secret_access_key = 'xxx' # IAMユーザのシークレットキー
    config.aws_session_token = ENV['AWS_SESSION_TOKEN'] if ENV.key?('AWS_SESSION_TOKEN')
    config.fog_region = 'ap-northeast-1' # S3バケットのリージョン
  end
end

IAMユーザーにはS3のアクセス権限が必要です。必要に応じてAWSのIAMコンソールで新規ユーザーの作成、もしくは既存ユーザーへの権限付与を行ってください。

なお、今回は説明の都合上、設定ファイルに直接アクセスキー・シークレットキーを記載しています。
実際の運用では、秘匿情報はシェルの設定ファイルやdotenv-railsを活用して環境変数でセットすることをオススメします。

Railsの設定ファイルを修正します。今回は本番環境で実行するためenvironments/production.rbを編集します。

config/environments/production.rb

Rails.application.configure do
+ config.action_controller.asset_host = "http://rails-app-production-assets.s3.amazonaws.com" # S3バケットのエンドポイント
end

設定が完了したらRailsアプリケーションを起動します。

$ bundle exec rails assets:precompile RAILS_ENV=production
$ bundle exec rails s -e production

ソースコードを確認するとS3バケットにアクセスしてファイルを表示していることがわかります。

S3バケットにはassetsディレクトリが同期されています。

CloudFrontを導入し、アセットファイルをキャッシュできるようにする

CloudFrontとはコンテンツ配信ネットワークサービスを提供するAWSの機能です。
コンテンツ配信ネットワークサービスは総称してCDNと呼ばれています。つまり、CloudFrontはCDNの一種といえます。

CDNにはコンテンツのキャッシュ機能が搭載されています。
CloudFrontを利用することでアセットファイルをキャッシュできるため、ファイルアクセスの高速化の効果が期待できます。

CloudFront経由でS3バケットへアクセスできるように設定をします。

CloudFrontのダッシュボードを開き、『Create Distribution』を選択します。

Webの『Get Started』を選択します。

『Origin Domain Name』は、『Amazon S3 Buckets』に表示されているS3バケットのエンドポイント(xxx.s3.amazonaws.com)を指定します。

そのほかの設定はデフォルトで指定されているものを選択します。

設定に問題がなければ、設定完了後しばらくするとステータスが『Deployed』になります。

アセットファイルのアクセスポイントが変わったのでRailsの設定ファイルを変更します。

config/environments/production.rb

Rails.application.configure do
-  config.action_controller.asset_host = "http://rails-app-production-assets.s3.amazonaws.com" # S3バケットのエンドポイント
+  config.action_controller.asset_host = "https://d8yldxafmxvy8.cloudfront.net" # CloudFrontのドメイン名
end

CloudFrontのドメイン名は一覧画面から確認できます。

Railsアプリケーションの再起動後、ソースコードを確認するとCloudFront経由でファイルを表示していることがわかります。

今回はCloudFrontのドメイン名をアセットファイルのホストにしましたが、CloudFrontのドメイン名に独自ドメインを割り当てることも可能です。
CloudFrontに独自ドメインを割り当てる手順についてはhttps対応した独自ドメインのWebサイトをS3 + CloudFrontで運用する手順を参考にしてください。

https対応した独自ドメインのWebサイトをS3 + CloudFrontで運用する手順

まとめ

以上で、S3 + CloudFrontを活用したRailsアプリケーションのアセットファイル配信方法の紹介を終わります。

今回のまとめ
  • asset_syncを利用することで外部リソースからアセットファイルを配信できる
  • CloudFrontを活用することでファイルアクセスの高速化が期待できる

今回の検証結果を見てわかるように、S3に配置されるアセットファイルはassetsディレクトリのみで、Webpackerでビルドされたファイルの出力先であるpacksは含まれていません。

asset_syncをWebpackerにも対応するためには追加で修正する必要があります。

asset_syncのWebpacker対応は【Rails】asset_syncでWebpackerのビルドファイルをS3に同期する手順で紹介しているので参照してください。

【Rails】asset_syncでWebpackerのビルドファイルをS3に同期する手順

この記事がいいなと思いましたらTwitter(@nishina555)のフォローもよろしくお願いします!

Rubyのオススメ参考書