logo hsb.horse
← ブログ一覧に戻る

ブログ

CloudFront + S3でSPAを配信するデプロイスクリプト

CloudFront経由でS3にホストしたSPAを配信する際のデプロイスクリプト。キャッシュコントロール設定、ブルーグリーンデプロイ、切り戻し手順を整理。

公開日:

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のクレデンシャル周りは実行コンテキストによって違うので割愛。

Terminal window
# global vars
readonly 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に戻す。

Terminal window
# global vars
readonly 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ディレクトリに履歴を残しつつ、currentpreviousで現行版と直前版を管理する構成により、迅速な切り戻しが可能だ。