CloudFront + S3でSPAを配信する際の、実用的なデプロイスクリプトをまとめる。
前提
- クラウドベンダーはAWSを利用
- S3にフロントエンドのビルド成果物を配置し、CloudFront経由で配信
インフラ構成
S3
- バケットのバージョニング: 無効
- 暗号化: SSE-S3
- ブロックパブリックアクセス: ON
- 静的ウェブサイトホスティング: 無効
CloudFront
- 料金クラス: すべてのエッジロケーションを使用
- サポートするHTTPバージョン: HTTP/3, 2, 1.1, 1.0
オリジン
- オリジン名: S3-frontend-app
- オリジンドメイン:
<bucket_name>.s3.ap-northeast-1.amazonaws.com - オリジンパス:
/current - オリジンアクセス: Origin access control settings
ビヘイビア
デフォルト(*)
- オリジン: S3-frontend-app
- ビューワープロトコルポリシー: HTTP to HTTPS
- キャッシュポリシー: Managed-CacheOptimized
- ビューワーリクエスト: CloudFront functions使用
デプロイスクリプト
AWSのクレデンシャル周りは実行コンテキストによって違うので割愛。
# global varsreadonly S3_BUCKET=""readonly DIST_DIR=""
function main() { # BUILD_IDはGitコミットハッシュでもOK local -r build_id=$(date -Iseconds)
local -r base_uri="s3://$S3_BUCKET" local -r deploy_uri="$base_uri/builds/$build_id" local -r previous_uri="$base_uri/previous" local -r current_uri="$base_uri/current"
# builds配下にデプロイする
# js,css aws s3 sync "$DIST_DIR" "$deploy_uri" \ --exclude "*" \ --include "*.js" \ --include "*.css" \ --metadata-directive "REPLACE" --cache-control "public,max-age=31536000,immutable"
# js,css,html以外 aws s3 sync "$DIST_DIR" "$deploy_uri" \ --exclude "*.js" \ --exclude "*.css" \ --exclude "*.html" \ --metadata-directive "REPLACE" \ --cache-control "public,max-age=1,stale-while-revalidate=604800"
# html aws s3 sync "$DIST_DIR" "$deploy_uri" \ --exclude "*" \ --include "*.html" \ --metadata-directive "REPLACE" \ --cache-control "no-cache"
# currentパスで稼働中のフロントエンドアセットをpreviousにバックアップ aws s3 sync "$current_uri" "$previous_uri" --delete --exact-timestamp
# 今回のビルド成果物をcurrentにコピーして、ユーザに公開する aws s3 sync "$deploy_uri" "$current_uri" --delete --exact-timestamp}キャッシュコントロールの設定順序について
本当は一番最後のステップ(aws s3 sync "$deploy_uri" "$current_uri")でキャッシュコントロールの設定をしたいが、S3バケットからS3バケットへのsync時に--metadata-directive "REPLACE"を使うと、AWS側の仕様でContent-Typeの推論が効かなくなり、全てbinary/octet-stream扱いされてしまう。
ローカルからS3バケットへのsync時はContent-Typeの推論が行われた状態が維持されるので、このような形にしている。
切り戻しスクリプト
問題が発生した場合は、previousからcurrentに戻す。
# global varsreadonly S3_BUCKET=""
function revert() { local -r base_uri="s3://$S3_BUCKET" local -r previous_uri="$base_uri/previous" local -r current_uri="$base_uri/current"
# copy previous to current aws s3 sync "$previous_uri" "$current_uri" --delete --exact-timestamp}まとめ
CloudFront + S3でSPAを配信する際、適切なキャッシュコントロール設定とブルーグリーンデプロイ構成を組み合わせることで、安全かつ効率的なデプロイが実現できる。
buildsディレクトリに履歴を残しつつ、currentとpreviousで現行版と直前版を管理する構成により、迅速な切り戻しが可能だ。
hsb.horse