はじめに
Reactアプリのデプロイ、CloudFormationでサクッと構築したい!という方に向けて、最小限の手順でデプロイする方法を紹介します。S3でホスティングして、CloudFrontで配信するシンプルな構成です。
必要なもの
- AWS CLI
- make コマンド
- 以下のファイル:
- CloudFormationテンプレート(cloudfront.yaml)
- Makefile
デプロイ手順
1. デプロイ用ファイルを用意
cloudfront.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'CloudFormation template for React App deployment with S3 and CloudFront'
Parameters:
Environment:
Type: String
Default: dev
AllowedValues:
- dev
- stg
- prod
Description: Environment name
Resources:
S3Bucket:
Type: AWS::S3::Bucket
DeletionPolicy: Retain
Properties:
BucketName: !Sub react-app-${Environment}-${AWS::AccountId}-${AWS::Region}
PublicAccessBlockConfiguration:
BlockPublicAcls: false
BlockPublicPolicy: true
IgnorePublicAcls: false
RestrictPublicBuckets: true
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
VersioningConfiguration:
Status: Enabled
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: index.html
OwnershipControls:
Rules:
- ObjectOwnership: BucketOwnerPreferred
CorsConfiguration:
CorsRules:
- AllowedHeaders: ['*']
AllowedMethods: [GET, HEAD]
AllowedOrigins: ['*']
MaxAge: 3600
S3BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref S3Bucket
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Action: s3:GetObject
Resource: !Sub ${S3Bucket.Arn}/*
Condition:
StringEquals:
AWS:SourceArn: !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}
CloudFrontOriginAccessControl:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Name: !Sub ${AWS::StackName}-OAC
Description: Origin Access Control for S3
SigningBehavior: always
SigningProtocol: sigv4
OriginAccessControlOriginType: s3
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: !Sub ${S3Bucket.RegionalDomainName}
Id: S3Origin
S3OriginConfig:
OriginAccessIdentity: ''
OriginAccessControlId: !Ref CloudFrontOriginAccessControl
Enabled: true
DefaultRootObject: index.html
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
- OPTIONS
CachedMethods:
- GET
- HEAD
- OPTIONS
TargetOriginId: S3Origin
ForwardedValues:
QueryString: false
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
Compress: true
DefaultTTL: 86400 # 1 day
MinTTL: 0
MaxTTL: 31536000 # 1 year
CustomErrorResponses:
- ErrorCode: 403
ResponseCode: 200
ResponsePagePath: /index.html
- ErrorCode: 404
ResponseCode: 200
ResponsePagePath: /index.html
ViewerCertificate:
CloudFrontDefaultCertificate: true
PriceClass: PriceClass_100
HttpVersion: http2
IPV6Enabled: true
Outputs:
BucketName:
Description: Name of S3 bucket to hold website content
Value: !Ref S3Bucket
BucketDomainName:
Description: Domain name of S3 bucket
Value: !GetAtt S3Bucket.DomainName
CloudFrontDistributionId:
Description: ID of CloudFront distribution
Value: !Ref CloudFrontDistribution
CloudFrontDomainName:
Description: Domain name of CloudFront distribution
Value: !GetAtt CloudFrontDistribution.DomainName
WebsiteURL:
Description: URL for website hosted on S3
Value: !Sub https://${CloudFrontDistribution.DomainName}
まず、最小限必要なファイルを配置します。
your-project/
├── templates/
│ └── cloudfront.yaml # CloudFormationテンプレート
├── ui/
│ └── chat-app/
│ └── dist/ # Reactのビルドファイル
└── Makefile
2. デプロイコマンドを実行
コマンドを実行させるために下のmakefileを作成して下さい。
# 環境変数
REGION ?= us-east-1
ENV ?= dev
STACK_NAME ?= react-app-stack
TEMPLATE_PATH ?= templates/cloudfront.yaml
DIST_PATH ?= ui/chat-app/dist
# バケット名を取得するヘルパー関数
define get_bucket_name
$(shell aws cloudformation describe-stacks \
--stack-name $(STACK_NAME) \
--region $(REGION) \
--query 'Stacks[0].Outputs[?OutputKey==`BucketName`].OutputValue' \
--output text)
endef
# UIデプロイ
.PHONY: ui-deploy
ui-deploy:
aws cloudformation create-stack \
--stack-name $(STACK_NAME) \
--template-body file://$(TEMPLATE_PATH) \
--region $(REGION) \
--parameters ParameterKey=Environment,ParameterValue=$(ENV)
# UIスタック更新
.PHONY: ui-update
ui-update:
aws cloudformation update-stack \
--stack-name $(STACK_NAME) \
--template-body file://$(TEMPLATE_PATH) \
--region $(REGION) \
--parameters ParameterKey=Environment,ParameterValue=$(ENV)
# UIスタック削除
.PHONY: ui-delete
ui-delete:
aws cloudformation delete-stack \
--stack-name $(STACK_NAME) \
--region $(REGION)
# UIスタック状態確認
.PHONY: ui-status
ui-status:
aws cloudformation describe-stacks \
--stack-name $(STACK_NAME) \
--region $(REGION)
# UIバケット名を取得
.PHONY: ui-get-bucket
ui-get-bucket:
@echo "Retrieving bucket name..."
@echo "Bucket name: $(call get_bucket_name)"
# UIS3同期
.PHONY: ui-sync
ui-sync:
@echo "Syncing UI files to bucket..."
aws s3 sync $(DIST_PATH) s3://$(call get_bucket_name)
# UIキャッシュ無効化
.PHONY: ui-invalidate
ui-invalidate:
@echo "Invalidating CloudFront cache..."
aws cloudfront create-invalidation \
--distribution-id $$(aws cloudformation describe-stacks \
--stack-name $(STACK_NAME) \
--region $(REGION) \
--query 'Stacks[0].Outputs[?OutputKey==`CloudFrontDistributionId`].OutputValue' \
--output text) \
--paths "/*"
# ヘルプ
.PHONY: help
help:
@echo "UI関連コマンド:"
@echo " make ui-deploy - UIのCloudFormationスタックをデプロイ"
@echo " make ui-deploy ENV=prod - UI本番環境にデプロイ"
@echo " make ui-update - UIスタックを更新"
@echo " make ui-delete - UIスタックを削除"
@echo " make ui-status - UIスタックの状態を確認"
@echo " make ui-sync - UIビルドファイルをS3に同期"
@echo " make ui-invalidate - CloudFrontのキャッシュを無効化"
@echo ""
@echo "環境変数:"
@echo " REGION - AWSリージョン (デフォルト: us-east-1)"
@echo " ENV - 環境名 (デフォルト: dev)"
@echo " STACK_NAME - スタック名 (デフォルト: react-app-stack)"
@echo " TEMPLATE_PATH - テンプレートパス (デフォルト: templates/cloudfront.yaml)"
@echo " DIST_PATH - ビルドファイルパス (デフォルト: ui/chat-app/dist)"
たった3ステップでデプロイ完了します:
# 1. インフラをデプロイ
make ui-deploy
# 2. Reactのビルドファイルをアップロード
make ui-sync
# 3. CloudFrontのキャッシュを無効化
make ui-invalidate
以上です!CloudFormationのOutputsに表示されるURLにアクセスすれば、アプリが表示されます。
インフラの中身
CloudFormationテンプレートで作成されるリソースは以下の通りです:
-
S3バケット
- Reactアプリのホスティング用
- 暗号化有効
- バージョニング有効
-
CloudFront
- HTTPSリダイレクト
- キャッシュ設定(デフォルト1日)
- SPA対応(404/403を200にリダイレクト)
便利な運用コマンド
# スタックの状態確認
make ui-status
# バケット名の確認
make ui-get-bucket
# 環境の指定(dev/stg/prod)
make ui-deploy ENV=prod
# スタックの削除
make ui-delete
カスタマイズのポイント
-
環境変数で設定変更が可能
REGION # AWSリージョン ENV # 環境名(dev/stg/prod) STACK_NAME # スタック名
-
CloudFormationテンプレートの主な設定箇所
- バケット名のフォーマット
- CloudFrontのキャッシュ設定
- CORSの設定
まとめ
これで最小構成のデプロイ環境の構築は完了です。あとは必要に応じて:
- Route 53でドメイン設定
- WAFでセキュリティ設定
- CodePipelineで自動デプロイ
などを追加していけば、本番環境としても使える構成になります。
CloudFormationを使うことで、環境の再現性が担保され、複数環境の管理も容易になります。まずはこのベース構成から始めて、必要な機能を追加していくアプローチがおすすめです。