デプロイ時にS3にassetsを配置してCloudFront使ってCDN化したメモ
Tweet昨日Reversalをデプロイした際にCDN経由でコンテンツ配信されるように色々追記したのでそれについての記事です。
主にTerraformで構築しているサーバについて変更を加えました。Rails側の変更は asset_sync
Gemを使うようにして量は少ないです。
assetsを配置するためのバケットとそれをバケットにCloudFrontからアクセスを許可するポリシーを設定します。
s3.tf
に追加
resource "aws_s3_bucket" "cdn" {
bucket = "reversal-cdn"
acl = "public-read"
policy = "${data.template_file.cdn_policy.rendered}"
}
data "template_file" "cdn_policy" {
template = "${file("cdn_policy.json.tpl")}"
vars {
bucket_name = "reversal-cdn"
origin_access_identity = "${aws_cloudfront_origin_access_identity.origin_access_identity.id}"
}
}
バケットを作りそれに対してバケットポリシーをテンプレートから適用しています。テンプレートは以下です。 cdn_policy.json.tpl
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadForGetBucketObjets",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${origin_access_identity}"
},
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::${bucket_name}/*"]
}
]
}
ClordFrontからのGetObjectを許可するポリシーになっています。次にCloudFrontにDistributionを作成します。 cdn.tf
resource "aws_cloudfront_origin_access_identity" "origin_access_identity" {
comment = "reversal_cloudfront_origin_access_identity"
}
resource "aws_cloudfront_distribution" "cdn" {
enabled = true
comment = "reversal_cdn"
price_class = "PriceClass_200"
aliases = ["ftg-reversal.net", "cdn.ftg-reversal.net"]
origin {
origin_id = "reversal-cdn"
domain_name = "reversal-cdn.s3.amazonaws.com"
s3_origin_config {
origin_access_identity = "${aws_cloudfront_origin_access_identity.origin_access_identity.cloudfront_access_identity_path}"
}
}
default_cache_behavior {
target_origin_id = "${aws_s3_bucket.cdn.id}"
allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
cached_methods = ["GET", "HEAD"]
viewer_protocol_policy = "allow-all"
min_ttl = 0
default_ttl = 3600
max_ttl = 86400
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
}
restrictions {
geo_restriction {
restriction_type = "whitelist"
locations = ["US", "CA", "GB", "DE", "JP"]
}
}
viewer_certificate {
cloudfront_default_certificate = true
}
}
ポイントは origin_id
と domain_name
に作成したS3バケットの値を入れるのとCNAMEを設定するために aliases
を設定しておくことです。
他は基本的にテンプレを埋める感じです。
最後に配信されるドメインにRoute53からCNAMEレコードを設定します。 route53.tf
resource "aws_route53_record" "cdn-ftg-reversal-net" {
zone_id = "${aws_route53_zone.ftg-reversal-net-public.id}"
name = "cdn.ftg-reversal.net"
type = "CNAME"
records = ["${aws_cloudfront_distribution.cdn.domain_name}"]
ttl = "300"
}
これで設定したバケットのファイルににRoute53からアクセスできることを確認したらRails側の設定です。
assets_sync
の設定をしたら config/environments/production.rb
から config.action_controller.asset_host = '//cdn.ftg-reversal.net'
で asset_precompile
でS3に配置したファイルにCloudFront経由でアクセスしてくれます。
本当は assets_sync
についてもCapistranoのタスクをいじって asset_precompile
をデプロイサーバ上で行ってS3上にアップロードするように書いた方が良いのですがWebサーバがまだ1台なのでとりあえずこれでよしとします。
もう少しハマると思ってたら案外すんなりいきました。