AWS で SPA などの静的コンテンツを公開する際、S3
+ CloudFront
という構成がよくある形。
その構成でデプロイする場合、 S3
にファイルを配置して CloudFront
のキャッシュを削除する必要があるが、
CodeDeploy
は S3
へのデプロイに対応しておらず、
CodePipeline
は S3
へのファイル配置は可能であるものの CloudFront
のキャッシュ削除が出来ない。
CodeBuild
で実施するのがベターと考えた。
というわけで、そのための buildspec
が以下。
buildspec
buildspec.yml
version: 0.2
phases:
pre_build:
commands:
- echo "# Deoloyment Info"
- echo "S3_BUCKET_NAME = ${S3_BUCKET_NAME}"
- echo "CLOUDFRONT_ID = ${CLOUDFRONT_ID}"
- echo "CLOUDFONT_INVALIDATION_PATHS = ${CLOUDFONT_INVALIDATION_PATHS}"
# build:
# commands:
# # - command
post_build:
commands:
- echo "# Build completed on `date`"
- ls -la
- echo "# Update S3-Objects ..."
- aws s3 sync ./ s3://${S3_BUCKET_NAME} --exact-timestamps
- sleep 10
- echo "# Invalidate CloudFront-Cache"
- RESPONSE=`aws cloudfront create-invalidation --distribution-id "${CLOUDFRONT_ID}" --paths ${CLOUDFONT_INVALIDATION_PATHS}`
- INVALIDATION_ID=`echo ${RESPONSE} | jq -r '.Invalidation.Id'`
- echo "Invalidation.Id = ${INVALIDATION_ID}"
- STATUS="";
while [ "${STATUS,,}" != "completed" ]; do
sleep 5;
RESPONSE=`aws cloudfront get-invalidation --distribution-id "${CLOUDFRONT_ID}" --id "${INVALIDATION_ID}"`;
STATUS=`echo ${RESPONSE} | jq -r '.Invalidation.Status'`;
echo "status = ${STATUS}";
done
- echo "# Remove Old S3-Objects"
- aws s3 sync ./ s3://${S3_BUCKET_NAME} --delete
処理概要
- ファイルを
aws s3 sync
で S3 バケットにコピー。追加/更新のみ。 - CloudFront の キャッシュを削除。
- 不要になったファイルを
aws s3 sync --delete
で S3 バケットから削除。
前提
- S3 に配置するファイル群は CodeBuild 内のデフォルトディレクトリに存在する前提。
そうでない場合はaws s3 sync
のコピー元を変更する。
CodeBuild 環境変数
-
S3_BUCKET_NAME
... ファイルのデプロイ先となる S3 バケット名。 -
CLOUDFRONT_ID
... AWSが自動生成する CloudFront ID。13文字くらいのランダム文字列。 -
CLOUDFONT_INVALIDATION_PATHS
... キャッシュ削除の対象とするパス。スペース区切りで複数指定可。
CodeBuild の IAM-Role Policy
CodeBuild の IAM-Role に付与するポリシー。
IAM-Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "s3",
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::<BUCKET_NAME>",
"arn:aws:s3:::<BUCKET_NAME>/*"
],
"Action": [
"s3:Get*",
"s3:List*",
"s3:PutObject",
"s3:CopyObject",
"s3:DeleteObject"
]
},
{
"Sid": "cloudfront",
"Effect": "Allow",
"Resource": [
"arn:aws:cloudfront::<ACCOUNT_ID>:distribution/<CLOUDFRONT_ID>"
],
"Action": [
"cloudfront:*Invalidation"
]
}
]
}
S3に対するアクションはもう少し減らせる。
AWSナレッジセンターのこちらの記事 では s3 sync
のためには、ListObjectsV2
CopyObject
GetObject
PutObject
が必要と書いているが、 --delete
を使用する場合は DeleteObject
も必要。