はじめに
AWS CloudFormationを利用してS3静的ホスティング・SPA(React)構築のテンプレートのサンプルです。
テンプレートの概要が分からない場合は、はじめてのAWS CloudFormationテンプレートを理解するを参考にしてください。
コードはGitHubにもあります。
今回は、akane というシステムの dev 環境を想定しています。
同じ構成で違う環境を作成する場合は、{環境名}-parameters.jsonを別途作成します。
ディレクトリ構成
akane (システム)
├── app (Reactアプリ)
└── s3 (スタック)
├─ s3.yml (CFnテンプレート)
└─ dev-parameters.json (dev 環境のパラメータ)
AWS リソース構築内容
- s3スタック
- s3バケット (akane-dev-s3-reacts)
- バケットポリシー (s3:GetObject)
実行環境の準備
AWS CloudFormationを動かすためのAWS CLIの設定を参考にしてください。
Reactアプリ ビルド手順
-
予め node.js yarn をインストールする。
-
下記を実行してアプリをビルドする
cd akane/app yarn install yarn build
AWS リソース構築手順
-
下記を実行してスタックを作成
./create_stacks.sh
-
下記を実行してスタックを削除
./delete_stacks.sh
構築テンプレート
1. s3スタック
s3.yml
AWSTemplateFormatVersion: 2010-09-09
Description: S3 For Akane
# Metadata:
Parameters:
SystemName:
Type: String
AllowedPattern: '[a-zA-Z0-9-]*'
EnvType:
Description: Environment type.
Type: String
AllowedValues: [all, dev, stg, prod]
ConstraintDescription: must specify all, dev, stg, or prod.
AppS3Bucket:
Type: String
AppIndexDocument:
Type: String
# Mappings
# Conditions
# Transform
Resources:
# S3 Bucket作成
akaneS3Bucket:
Type: AWS::S3::Bucket
Properties:
AccessControl: Private
BucketName: !Ref AppS3Bucket
Tags:
- Key: Name
Value: !Ref AppS3Bucket
- Key: SystemName
Value: !Ref SystemName
- Key: EnvType
Value: !Ref EnvType
WebsiteConfiguration:
IndexDocument: !Ref AppIndexDocument
# S3 BucketPolicy作成
akaneS3BucketPolicy:
Type: AWS::S3::BucketPolicy
DependsOn: akaneS3Bucket
Properties:
Bucket: !Ref akaneS3Bucket
PolicyDocument:
Statement:
- Action:
- s3:GetObject
Effect: Allow
Resource: !Join
- ''
- - 'arn:aws:s3:::'
- !Ref akaneS3Bucket
- /*
Principal:
AWS: '*'
Outputs:
akaneS3Bucket:
Value: !Ref akaneS3Bucket
Export:
Name: !Ref AppS3Bucket
all-parameters.json
{
"Parameters": [
{
"ParameterKey": "SystemName",
"ParameterValue": "akane"
},
{
"ParameterKey": "EnvType",
"ParameterValue": "dev"
},
{
"ParameterKey": "AppS3Bucket",
"ParameterValue": "akane-dev-s3-react"
},
{
"ParameterKey": "AppIndexDocument",
"ParameterValue": "index.html"
}
]
}
3. 実行ファイル
create_stacks.sh
#!/bin/sh
cd `dirname $0`
SYSTEM_NAME=akane
create_stack () {
ENV_TYPE=$1
STACK_NAME=$2
aws cloudformation create-stack \
--stack-name ${SYSTEM_NAME}-${ENV_TYPE}-${STACK_NAME} \
--template-body file://./${SYSTEM_NAME}/${STACK_NAME}/${STACK_NAME}.yml \
--cli-input-json file://./${SYSTEM_NAME}/${STACK_NAME}/${ENV_TYPE}-parameters.json
aws cloudformation wait stack-create-complete \
--stack-name ${SYSTEM_NAME}-${ENV_TYPE}-${STACK_NAME}
}
create_stack dev s3
./akane/deploy_app.dev.sh
exit 0
delete_stacks.sh
#!/bin/sh
cd `dirname $0`
SYSTEM_NAME=akane
delete_stack () {
ENV_TYPE=$1
STACK_NAME=$2
aws cloudformation delete-stack \
--stack-name ${SYSTEM_NAME}-${ENV_TYPE}-${STACK_NAME}
aws cloudformation wait stack-delete-complete \
--stack-name ${SYSTEM_NAME}-${ENV_TYPE}-${STACK_NAME}
}
./akane/delete_app.dev.sh
delete_stack dev s3
exit 0
4. デプロイファイル
deploy_app.dev.sh
#!/bin/sh
cd `dirname $0`
BASENAME=$(basename $0)
FILENAME=${BASENAME%.*}
ENV_TYPE=${FILENAME##*.}
APP_DIR=app/build
S3_DIR=s3/
BUCKET_NAME=$(cat ${S3_DIR}${ENV_TYPE}-parameters.json | jq -r '.Parameters[] | select(.ParameterKey == "AppS3Bucket").ParameterValue')
aws s3 cp ${APP_DIR} s3://${BUCKET_NAME} --recursive
exit 0
delete_app.dev.sh
#!/bin/sh
cd `dirname $0`
BASENAME=$(basename $0)
FILENAME=${BASENAME%.*}
ENV_TYPE=${FILENAME##*.}
S3_DIR=s3/
BUCKET_NAME=$(cat ${S3_DIR}${ENV_TYPE}-parameters.json | jq -r '.Parameters[] | select(.ParameterKey == "AppS3Bucket").ParameterValue')
aws s3 rm s3://${BUCKET_NAME} --recursive
exit 0