はじめに
モダンなWebアプリケーションの開発において、Reactは最も人気のあるフロントエンドフレームワークの一つです。しかし、開発したアプリケーションを効率的に本番環境に展開するためには、適切なデプロイ戦略が必要です。この記事では、Docker、AWS S3、CloudFrontを組み合わせてReactアプリケーションを効率的に配信する方法について解説します。
この構成の主なメリットは以下の通りです:
- 開発環境の一貫性: Dockerを使用することで、開発環境と本番環境の差異を最小限に抑えられます
- 高可用性: AWS S3の高い耐久性とCloudFrontのグローバルCDNによる高速配信
- コスト効率: 静的ファイルのホスティングは非常に低コスト
- スケーラビリティ: トラフィックが増加しても自動的にスケール
前提条件
- AWS アカウント
- Docker がインストールされた環境
- Node.js と npm
- AWS CLI(設定済み)
- 基本的な React アプリケーション
構成の概要
この記事で構築するシステムの全体像は以下のようになります:
- Docker: Reactアプリをビルドする環境を提供
- AWS S3: ビルドされた静的ファイルを保存
- CloudFront: コンテンツをCDN経由で高速配信
- Route 53(オプション): カスタムドメインの設定
実装手順
1. Docker環境の準備
まず、ReactアプリケーションをビルドするためのDockerfile を作成します。
# ビルド用のステージ
FROM node:16-alpine as build
WORKDIR /app
# 依存関係のインストール
COPY package.json package-lock.json ./
RUN npm ci
# ソースコードのコピーとビルド
COPY . ./
RUN npm run build
# 配信用の軽量ステージ
FROM nginx:alpine
# ビルドされたファイルをnginxのコンテンツディレクトリにコピー
COPY --from=build /app/build /usr/share/nginx/html
# nginxの設定(SPAのためのルーティング設定)
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
SPAのルーティングをサポートするための nginx.conf
も作成します:
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
}
2. Dockerイメージのビルドとテスト
以下のコマンドでDockerイメージをビルドします:
docker build -t react-app .
ローカルでテストするには:
docker run -p 8080:80 react-app
これで http://localhost:8080
にアクセスして動作確認ができます。
3. AWS S3バケットの作成
AWS S3バケットを作成し、静的ウェブサイトホスティングを有効にします。
# S3バケットの作成
aws s3 mb s3://my-react-app-bucket
# 静的ウェブサイトホスティングの設定
aws s3 website s3://my-react-app-bucket --index-document index.html --error-document index.html
# パブリックアクセスの設定
aws s3api put-bucket-policy --bucket my-react-app-bucket --policy '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-react-app-bucket/*"
}
]
}'
4. ビルドされたファイルのアップロード
Dockerコンテナからビルドファイルを抽出してS3にアップロードします:
# 一時的にコンテナを実行して、ビルドファイルを抽出
CONTAINER_ID=$(docker create react-app)
mkdir -p ./build
docker cp $CONTAINER_ID:/usr/share/nginx/html ./build
docker rm $CONTAINER_ID
# S3にアップロード
aws s3 sync ./build/html s3://my-react-app-bucket --delete
または、CI/CDパイプラインを使用する場合は、このプロセスを自動化するスクリプトを作成できます。
5. CloudFrontディストリビューションの設定
AWSコンソールまたはAWS CLIを使用してCloudFrontディストリビューションを作成します:
aws cloudfront create-distribution \
--origin-domain-name my-react-app-bucket.s3.amazonaws.com \
--default-root-object index.html \
--error-responses Quantity=1,Items=[{ErrorCode=404,ResponsePagePath=/index.html,ResponseCode=200,ErrorCachingMinTTL=10}]
注意: 実際のCloudFront設定はより複雑になるため、上記のコマンドは簡略化されています。AWS管理コンソールを使用して、より詳細な設定を行うことをお勧めします。
S3バケットから直接ファイルを配信するのではなく、CloudFrontを経由することで以下のメリットがあります:
- グローバルなエッジロケーションによる高速配信
- HTTPSの対応
- カスタムドメインの利用
- WAF(Web Application Firewall)による保護
6. カスタムドメインの設定(オプション)
既にRoute 53でドメインを管理している場合は、CloudFrontディストリビューションにカスタムドメインを設定できます:
- AWS Certificate Manager(ACM)でSSL証明書を取得
- CloudFrontディストリビューションに証明書を関連付け
- Route 53でDNSレコードを作成(CloudFrontディストリビューションを指すように)
7. CI/CDパイプラインの構築(オプション)
GitHub ActionsやAWS CodePipelineなどを使用して、コードの変更が自動的にデプロイされる仕組みを構築すると便利です。
GitHubリポジトリのワークフローの例(.github/workflows/deploy.yml
):
name: Deploy React App
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Docker
uses: docker/setup-buildx-action@v1
- name: Build Docker image
run: docker build -t react-app .
- name: Extract build files
run: |
CONTAINER_ID=$(docker create react-app)
mkdir -p ./build
docker cp $CONTAINER_ID:/usr/share/nginx/html ./build
docker rm $CONTAINER_ID
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Deploy to S3
run: aws s3 sync ./build/html s3://my-react-app-bucket --delete
- name: Invalidate CloudFront cache
run: |
aws cloudfront create-invalidation \
--distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \
--paths "/*"
キャッシュ戦略とデプロイの最適化
キャッシュコントロール
効率的なキャッシュ戦略の実装は非常に重要です:
# index.htmlは短いキャッシュ期間に設定
aws s3 cp ./build/html/index.html s3://my-react-app-bucket/index.html \
--cache-control "max-age=60"
# 静的アセット(ハッシュ値を含むファイル名)は長期キャッシュに設定
aws s3 sync ./build/html/static s3://my-react-app-bucket/static \
--cache-control "max-age=31536000" \
--exclude "*" \
--include "*.js" \
--include "*.css"
CloudFrontのキャッシュ無効化
新しいバージョンをデプロイした後、CloudFrontのキャッシュを無効化する必要があります:
aws cloudfront create-invalidation \
--distribution-id DISTRIBUTION_ID \
--paths "/*"
トラブルシューティング
CORS設定
API呼び出しで問題が発生した場合は、S3バケットのCORS設定を確認してください:
aws s3api put-bucket-cors --bucket my-react-app-bucket --cors-configuration '{
"CORSRules": [
{
"AllowedOrigins": ["*"],
"AllowedMethods": ["GET"],
"AllowedHeaders": ["*"]
}
]
}'
SPAルーティングの問題
CloudFrontでSPAのルーティングを適切に処理するために、404エラーをindex.html
にリダイレクトする設定が必要です。CloudFrontディストリビューションのエラーページ設定で、404エラーを/index.html
にリダイレクトするように設定します。
本番環境の考慮事項
セキュリティ
- バケットポリシーを最小権限の原則に基づいて設定
- CloudFrontとS3の間のOAI(Origin Access Identity)を使用
- WAF(Web Application Firewall)の導入を検討
コスト最適化
- S3ライフサイクルポリシーの設定
- CloudFrontのPrice Classの適切な選択
- リザーブドキャパシティの検討(大規模なトラフィックの場合)
パフォーマンス最適化
- Reactアプリのコード分割
- 画像の最適化
- Gzipなどの圧縮設定
まとめ
この記事では、Docker、AWS S3、CloudFrontを組み合わせたReactアプリケーションの効率的なデプロイ方法について解説しました。この方法を使用することで、高可用性と低コストを両立させた堅牢なデプロイメントパイプラインを構築できます。
また、CI/CDパイプラインを導入することで、開発からデプロイまでのプロセスを自動化し、より高速な開発サイクルを実現できます。
最後に、本番環境でのセキュリティやパフォーマンスの最適化についても忘れずに検討しましょう。これらはエンドユーザーのエクスペリエンスに直接影響する重要な要素です。
コメント