インフラブログ

とあるWEBサイトのインフラを構築運用するメモ

AWS CloudFront経由で静的コンテンツを配信する

画像、音声、css、jsなど静的コンテンツをAWS CloudFront経由で配信してwebサーバの負荷を軽減するようにします。 CloudFrontはリバースプロキシ型のキャッシュサーバのように動作します。

CloudFrontを試していたところ一つ問題を確認しています。クライアント端末がgoogleのパブリックDNSを使っている場合だと、CloudFrontからのリソース読み込みが遅くなる可能性があります。(参考になる記事) 今のところサーバサイドで解決する方法はわかっていません。2014-4-14:AWSのほうで対応したようです

構成

動的コンテンツと静的コンテンツのURLのドメインをあらかじめ分けておいて、静的コンテンツのリクエストはCloudFrontのほうに届くようにしておきます。静的コンテンツ配信のドメインをimage.staging.example.comとします。

端末
|  リクエスト http://image.staging.example.com/assets/xxxx 
|
CloudFront [image.staging.example.com]
|  キャッシュがCloudFrontになければ、下のoriginからリソースを取得してきて端末に配信する
| (キャッシュできるものであればキャッシュする)
|
web server(origin) [origin.staging.example.com]
|  CloudFrontからのリクエストに応じてリソースを配信する
|
app server

アプリがRails製なのでasset_hostで指定します。

  • config/environments/staging.rb
config.action_controller.asset_host = "image.staging.example.com"

CloudFrontディストリビューションの作成

スクリプトで作成できるようにしておきます。

stage = ARGV.shift
stage ||= "staging"

asset_host = "image.#{stage}.example.com"
origin_host = "origin.#{stage}.example.com"

cf = AWS::CloudFront.new

cf.client.create_distribution({
  :distribution_config => {
    :caller_reference => Time.now.to_i.to_s,
    :aliases => {:items => [asset_host], :quantity => 1},
    :default_root_object => "index",
    :origins => {
      :items => [{
        :id=>"Custom-#{origin_host}",
        :domain_name => origin_host,
        :custom_origin_config => {
          :http_port => 80,
          :https_port => 443,
          :origin_protocol_policy => "http-only"
        }
      }],
      :quantity => 1
    },
    :default_cache_behavior => {
      :target_origin_id => "Custom-#{origin_host}",
      :forwarded_values => {
        :query_string => false,
        :cookies=>{:forward => "none"}
      },
      :trusted_signers => {
        :items => [], :enabled => false, :quantity => 0
      },
      :viewer_protocol_policy => "allow-all",
      :min_ttl => 0,
      :allowed_methods => {:items => ["GET", "HEAD"], :quantity => 2}
    },
    :cache_behaviors => {:items => [], :quantity => 0},
    :comment => "#{stage}",
    :logging => {
      :enabled => false,
      :include_cookies => false,
      :bucket => "",
      :prefix => "",
    },
    :price_class => "PriceClass_All",
    :enabled => true,
    :viewer_certificate => {:cloud_front_default_certificate => true},
    :restrictions => {
      :geo_restriction => {:items => [], :restriction_type => "none", :quantity => 0}
    },
  }
})

resp = cf.client.list_distributions
resp[:items].each do |distribution|
  pp distribution
end

DNSの設定

CloudFrontでディストリビューションを作成した後、image.staging.example.comDNS AレコードをCloudFrontで作成したディストリビューションエイリアスに設定します。