Nwht0xn1

Railsでデプロイ時にS3にassetsを配置してCloudFront経由で配信するCreated on 2016-05-18 by r7kamura

CSSやJavaScriptの配信が少し高速化されました - WikiHub Help で利用した技術情報についての記事です。WikiHubのJavaScriptやCSSなどを、S3からCDNを経由して配信するように手を加えたので、その過程をまとめておきます。

Amazon S3にbucketをつくる

まずassetsを配置するため、S3にbucketをつくります。東京リージョン (ap-northeast-1) を利用することにします。bucketは作成時に一意な名前を与える必要があるので、今回は wikihub という名前にします。

ここで、bucketの作成を自動化するために、Serverkitを利用することにします。Serverkitは、YAMLやJSONでレシピを書いて適用すると、対象のホストやクラウドサービス上の設定をその状態にしてくれるというツールで、プラグインとしてGemを入れるとAWSを扱うことができます。

# Gemfile
gem "serverkit"
gem "serverkit-aws"

Serverkit用のレシピは以下のようになります。

# recipe.yml
resources:
  - type: s3_bucket
    aws_region: ap-northeast-1
    name: wikihub

以下のコマンドを実行すると、s3にbucketがつくられます。wikihubという名前のバケットは既につくられているので、他の人が同じようにやると失敗します。

bundle install
bundle exec serverkit apply recipe.yml

ところで言及していませんでしたが、AWSのAPIを利用するために、serverkit実行時にはAWS Access Key IDなどの認証情報を与える必要があります。https://github.com/serverkit/serverkit-aws に詳細が書かれていますが、環境変数 AWS_ACCESS_KEY_ID や、~/.aws/credentials などを経由して適切な認証情報を与えてください。

Amazon CloudFrontにdistributionをつくる

続いて、CloudFrontの設定をします。CloudFrontでは、distributionという単位のリソースをつくると、あるS3のbucketを配信するためのドメインを割り当ててくれます。

CloudFrontのdistributionの作成もServerkitで行うことにします。前述したレシピを以下のように編集して適用すると、wikihubというbucketのコンテンツを配信するためのdistributionの設定が作成されます。

# recipe.yml
resources:
  - type: s3_bucket
    aws_region: ap-northeast-1
    name: wikihub
  - type: cloud_front_web_distribution
    check_script: true
    aws_region: ap-northeast-1
    distribution_config:
      caller_reference: test3
      default_cache_behavior:
        target_origin_id: S3-wikihub
      origins:
        items:
          - id: S3-wikihub
            domain_name: wikihub.s3.amazonaws.com
            s3_origin_config:
              origin_access_identity: ""
        quantity: 1

デプロイ時にS3にassetsをアップロードする

コードをproduction環境にデプロイするときに、precompileして生成したassetsをS3にアップロードする必要があります。これには、asset_sync というGemを利用します。このGemを利用すると、rake assets:precompile の挙動を拡張し、指定したS3のbucketにprecompileされたassetsをアップロードしてくれるようになります。rake assets:precompile にフックされるようになっていますが、多くの場合ではCapistranoを利用していて、このrakeタスクが呼ばれるようになっていると思います。

asset_syncの使い方は、https://github.com/AssetSync/asset_sync を見るとわかると思います。参考までに、WikiHubでは以下のような設定で動作させています。config.fog_directoryには作成したS3のbucketの名前を指定します。

# config/initializers/asset_sync.rb
AssetSync.configure do |config|
  config.aws_access_key_id = ENV["AWS_ACCESS_KEY_ID"]
  config.aws_secret_access_key = ENV["AWS_SECRET_ACCESS_KEY"]
  config.fog_directory = "wikihub"
  config.fog_provider = "AWS"
  config.fog_region = "ap-northeast-1"
  config.gzip_compression = true
end

Viewで生成するassetsのURLをCloudFrontのものにする

最後に、RailsのViewが生成するassetsのURLが、CloudFrontのURLになるように設定します。Wikihubで利用するCloudFrontのdistributionには d2fvkf4etwwds8.cloudfront.net というドメインが割り当てられているので、これを指定します。ドメイン名は、AWS Consoleから確認できます。

# config/environments/production.rb
Rails.application.configure do
  # Enable serving of images, stylesheets, and JavaScripts from an asset server.
  config.action_controller.asset_host = "//d2fvkf4etwwds8.cloudfront.net"
end

おしまい

以上で、デプロイ時にS3にassetsを配置して、CloudFront経由で配信できるようになりました。WikiHubではまだ設定したばかりで、gzipを利用していなかったり、一部のフォントなどを別のCDNから利用したりしているので、まだまだ最適化の余地がありそうです。