http://jawsug-cli.doorkeeper.jp/events/14614 でのハンズオン資料です。
CloudFormationを利用して、S3上に静的ウェブホスティング(独自ドメイン)用のバケットを構築、運用します。
今回は、S3:#5 (http://qiita.com/tcsh/items/de8676d836ffe611cc58) で作成したピュアなS3バケットにWebホスティングの公開に必要な各種設定を追加します。
Web公開準備のときの設定更新作業として行なうことを想定しています。
前提条件
- S3へのフルアクセス権限
- 独自ドメインを運用している。
- 独自ドメイン取得手順: http://qiita.com/tcsh/items/597e7644949bfe4ab405
- 独自ドメインを持っていない場合は、example.comやexample.jpのサブドメインを利用してみてください。(Route53への登録は可能なようです。継続的に利用できるかは未確認)
- 事前作業
==============
0.1. バケットの決定
更新するバケットを決めます。
$ S3_BUCKET_NAME=www.example.com
Note
このハンズオンでは、ログバケット名が”{コンテンツバケット名}-log”であることを前提にしています。
0.2. 変数の定義
$ CF_STACK_NAME="s3-`echo ${S3_BUCKET_NAME}|sed 's/\./-/g'`"; echo ${CF_STACK_NAME}
$ FILE_CF_TEMPLATE="${CF_STACK_NAME}.template"
0.3. リージョンの決定
更新するバケットが存在するリージョンをAWS_DEFAULT_REGIONとして設定します。
$ export AWS_DEFAULT_REGION=`aws s3api get-bucket-location --bucket ${S3_BUCKET_NAME} --output text`; echo ${AWS_DEFAULT_REGION}
Note
このハンズオンでは、ログバケットがコンテンツバケットと同じリージョンにあることを前提にしています。
0.4. リポジトリへの移動
リポジトリが存在する場合、作業場所としてリポジトリディレクトリに移動します。
$ cd ~/_work/aws/project-01
- テンプレート更新
===================
CloudFormationテンプレートを編集します。
ここではS3バケット(設定なし)に、以下の設定を追加します。
-
ログバケット
- ACL (ログ書き込みを許可)
-
コンテンツバケット
- Webサイトホスティング
- バケットポリシー (Webアクセスを許可)
- アクセスログ保存
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "website bucket (www.example.com)",
"Resources": {
"LogBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": "www.example.com-log"
}
},
"WebBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": "www.example.com"
}
}
}
}
10c10,11
< "BucketName": "www.example.com-log"
---
> "BucketName": "www.example.com-log",
> "AccessControl": "LogDeliveryWrite"
16c17,39
< "BucketName": "www.example.com"
---
> "BucketName": "www.example.com",
> "WebsiteConfiguration": {
> "IndexDocument": "index.html",
> "ErrorDocument": "error.html"
> },
> "LoggingConfiguration": {
> "DestinationBucketName": {"Ref": "LogBucket"},
> "LogFilePrefix": "logs"
> }
> }
> },
> "WebBucketPolicy": {
> "Type": "AWS::S3::BucketPolicy",
> "Properties": {
> "Bucket": "www.example.com",
> "PolicyDocument": {
> "Statement": [{
> "Action": "s3:GetObject",
> "Effect": "Allow",
> "Principal": { "AWS": "*" },
> "Resource": "arn:aws:s3:::www.example.com/*"
> }]
> }
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "website bucket (www.example.com)",
"Resources": {
"LogBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": "www.example.com-log",
"AccessControl": "LogDeliveryWrite"
}
},
"WebBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": "www.example.com",
"WebsiteConfiguration": {
"IndexDocument": "index.html",
"ErrorDocument": "error.html"
},
"LoggingConfiguration": {
"DestinationBucketName": {"Ref": "LogBucket"},
"LogFilePrefix": "logs"
}
}
},
"WebBucketPolicy": {
"Type": "AWS::S3::BucketPolicy",
"Properties": {
"Bucket": "www.example.com",
"PolicyDocument": {
"Statement": [{
"Action": "s3:GetObject",
"Effect": "Allow",
"Principal": { "AWS": "*" },
"Resource": "arn:aws:s3:::www.example.com/*"
}]
}
}
}
}
}
JSONファイルを作成したら、フォーマットが壊れてないか必ず確認します。
$ cat ${FILE_CF_TEMPLATE} | json_verify
JSON is valid
invalidとエラーが表示された場合は、jsonlintでどこが壊れているか調べます。
$ cat ${FILE_CF_TEMPLATE} | jsonlint
validate-templateサブコマンドで、簡単な検証ができます。
$ aws cloudformation validate-template --template-body file://${FILE_CF_TEMPLATE}
- スタック(バケット)更新
==========================
スタックを更新して、S3バケットの設定を変更します。
2.1. スタック(S3バケット)更新
$ aws cloudformation update-stack --stack-name ${CF_STACK_NAME} --template-body file://${FILE_CF_TEMPLATE}
{
"StackId": "arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/route53-example-com-hostedzone/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
}
2.2. スタックの状況確認
スタックの更新状況を確認します。
$ aws cloudformation list-stacks \
| jq -r --arg stackname ${CF_STACK_NAME} '.StackSummaries[] | select(.StackName == $stackname) | .StackStatus'
UPDATE_COMPLETE
StackStatusが’UPDATE_COMPLETE’になっていれば作成は完了です。 (30秒から1分程度かかるようです。)
それ以外が表示されている場合は、下記コマンドでFailedの文字が出ている前後を見て原因を調べます。
$ aws cloudformation describe-stack-events --stack-name ${CF_STACK_NAME}
2.3. スタックの内容確認
更新されたスタックの内容を確認します。
$ aws cloudformation get-template --stack-name ${CF_STACK_NAME}
{
"TemplateBody": {
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "website bucket (www.opelab01.opelab.jp)",
"Resources": {
"WebBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"LoggingConfiguration": {
"DestinationBucketName": {
"Ref": "LogBucket"
},
"LogFilePrefix": "logs"
},
"BucketName": "www.opelab01.opelab.jp",
"WebsiteConfiguration": {
"IndexDocument": "index.html",
"ErrorDocument": "error.html"
}
}
},
"LogBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"AccessControl": "LogDeliveryWrite",
"BucketName": "www.opelab01.opelab.jp-log"
}
},
"WebBucketPolicy": {
"Type": "AWS::S3::BucketPolicy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::www.opelab01.opelab.jp/*",
"Effect": "Allow",
"Principal": {
"AWS": "*"
}
}
]
},
"Bucket": "www.opelab01.opelab.jp"
}
}
}
}
}
- ログバケット確認
=====================
ログバケットの設定を確認します。
3.1. バケットACLポリシー確認
LogDeliveryに対して、”WRITE”と”READ_ACP”が許可されていることを確認します。
$ aws s3api get-bucket-acl --bucket ${S3_BUCKET_NAME}-log
{
"Owner": {
"DisplayName": "XXXXX",
"ID": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
"Grants": [
{
"Grantee": {
"DisplayName": "XXXXX",
"ID": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
"Permission": "FULL_CONTROL"
},
{
"Grantee": {
"URI": "http://acs.amazonaws.com/groups/s3/LogDelivery"
},
"Permission": "WRITE"
},
{
"Grantee": {
"URI": "http://acs.amazonaws.com/groups/s3/LogDelivery"
},
"Permission": "READ_ACP"
}
]
}
- コンテンツバケット確認
==========================
4.1. Webサイトホスティング設定の確認
Webサイトホスティングの設定が反映されていることを確認します。
$ aws s3api get-bucket-website --bucket ${S3_BUCKET_NAME}
{
"IndexDocument": {
"Suffix": "index.html"
},
"ErrorDocument": {
"Key": "error.html"
}
}
4.2. バケットポリシーの確認
バケットポリシーの設定が反映されていることを確認します。
$ aws s3api get-bucket-policy --bucket ${S3_BUCKET_NAME}
{
"Policy": "{\"Version\":\"2008-10-17\",\"Statement\":[{\"Sid\":\"AddPerm\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"*\"},\"Action\":\"s3:GetObject\",\"Resource\":\"arn:aws:s3:::www.example.com/*\"}]}"
}
4.3. アクセスログ保存設定の確認
アクセスログの保存設定が反映されていることを確認します。
$ aws s3api get-bucket-logging --bucket ${S3_BUCKET_NAME}
{
"LoggingEnabled": {
"TargetPrefix": "logs",
"TargetBucket": "www.example.com-log"
}
}
- コミット
=============
問題無くスタックの更新が完了していれば、ここで一旦テンプレートをコミットしておきましょう。
$ hg commit -m "update website bucket configuration (${S3_BUCKET_NAME})."
ウェブサイトエンドポイントの保存
コンテンツ転送後に確認するためのエンドポイントをメモしておきます。
$ WEB_ENDPOINT="${S3_BUCKET_NAME}.s3-website-${AWS_DEFAULT_REGION}.amazonaws.com" && echo ${WEB_ENDPOINT}
www.example.com.s3-website-ap-northeast-1.amazonaws.com
完了
S3でのウェブサイトホスティングの構築が完了したので、Route53にコンテンツバケットへのエイリアスレコードを登録します。 http://qiita.com/tcsh/items/abe87b236e50d29f08e6
おまけ
サンプルコンテンツを転送しておくと、下記のURLでコンテンツ確認ができます。
ENDPOINT="${S3_BUCKET_NAME}.s3-website-${AWS_DEFAULT_REGION}.amazonaws.com" && echo ${ENDPOINT}