AWS CDKでReactアプリをデプロイしてみた

2020.01.15

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

AWS CDK (Cloud Development Kit) でS3とCloudFrontを利用したReactアプリのデプロイ方法を説明します。S3バケットへのアップロードからCloudFrontのキャッシュ削除までAWS CDKだけで出来ます。

なお、Reactに限らずAngularやVue.jsなど他のSPAの場合も同じような手順になります。

開発環境

パッケージ名 バージョン
typescript 3.7.2
aws-cdk 1.20.0
@aws-cdk/aws-cloudfront 1.20.0
@aws-cdk/aws-s3 1.20.0
@aws-cdk/aws-s3-deployment 1.20.0
react 16.12.0

デプロイ手順

  1. AWS CDKをインストール
  2. AWS CDKでデプロイ用のコードを書く
  3. Create React AppでWEBアプリを作成
  4. AWS CDKでデプロイ

やってみた

AWS CDKをインストール

AWS CDKをインストールします。

npm i -g aws-cdk

プロジェクトを作成します。

mkdir aws-cdk-deploy-react
cd aws-cdk-deploy-react
cdk init app --language=typescript

AWS CDKでデプロイ用のコードを書く

必要なパッケージをインストールします。

npm install @aws-cdk/aws-cloudfront @aws-cdk/aws-s3 @aws-cdk/aws-s3-deployment --save

デプロイ用のコードを書きます。

lib/aws-cdk-deploy-react-stack.ts

import * as cdk from '@aws-cdk/core';
import * as cloudfront from '@aws-cdk/aws-cloudfront'
import * as s3 from '@aws-cdk/aws-s3'
import * as s3deploy from '@aws-cdk/aws-s3-deployment'
import * as iam from '@aws-cdk/aws-iam'

export class AwsCdkDeployReactStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const websiteBucket = new s3.Bucket(this, 'WebsiteBucket', {
      websiteErrorDocument: 'index.html',
      websiteIndexDocument: 'index.html',
    });

    const websiteIdentity = new cloudfront.OriginAccessIdentity(
      this,
      'WebsiteIdentity',
    );

    const webSiteBucketPolicyStatement = new iam.PolicyStatement({
      actions: ['s3:GetObject'],
      effect: iam.Effect.ALLOW,
      principals: [
        websiteIdentity.grantPrincipal,
      ],
      resources: [`${websiteBucket.bucketArn}/*`],
    });

    websiteBucket.addToResourcePolicy(webSiteBucketPolicyStatement);

    const websiteDistribution = new cloudfront.CloudFrontWebDistribution(
      this,
      'WebsiteDistribution',
      {
        errorConfigurations: [
          {
            errorCachingMinTtl: 300,
            errorCode: 403,
            responseCode: 200,
            responsePagePath: '/index.html',
          },
          {
            errorCachingMinTtl: 300,
            errorCode: 404,
            responseCode: 200,
            responsePagePath: '/index.html',
          },
        ],
        originConfigs: [
          {
            s3OriginSource: {
              s3BucketSource: websiteBucket,
              originAccessIdentity: websiteIdentity,
            },
            behaviors: [
              {
                isDefaultBehavior: true,
              },
            ],
          },
        ],
        priceClass: cloudfront.PriceClass.PRICE_CLASS_ALL,
      },
    );

    new s3deploy.BucketDeployment(this, 'WebsiteDeploy', {
      sources: [s3deploy.Source.asset('./web/build')],
      destinationBucket: websiteBucket,
      distribution: websiteDistribution,
      distributionPaths: ['/*'],
    });
  }
}

aws-s3-deploymentBucketDeploymentはローカルのファイルをS3バケットにデプロイします。また、distributiondistributionPathsを指定することでCloudFrontのキャッシュ削除まで実行してくれます。

Create React AppでWEBアプリを作成

Reactアプリを作成します。tsconfig.jsonpackage.jsonの競合を避けるため、プロジェクトのルートディレクトリに別のディレクトリを作成します。

npx create-react-app web --typescript
# 新しいバージョンの場合
# npx create-react-app web --template typescript
cd web
npm run build
cd ../

AWS CDKでデプロイ

CDKでデプロイするためのS3バケットを作成するため、最初の1回だけcdk bootstrapを実行します。

cdk bootstrap

tsconfig.jsonexcludeにReactアプリのディレクトリを追加します。

tsconfig.json

{
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
  "exclude": ["cdk.out", "web"]
}

CDKのソースコードをビルドします。

npm run build

デプロイします。初回デプロイは完了までに10分ほど時間がかかります。

cdk deploy

デプロイ後、CloudFrontのドメインでアクセスすると、以下のような画面が表示されます。

試しにEdit src/App.tsx and save to reload.Hello World!に変更してデプロイしてみます。

cd web
vim src/App.tsx # 内容を書き換え
npm run build
cd ../
cdk deploy

画面を更新するとHello World!が表示されることを確認できました。

まとめ

これまでCloudFormationとAWS CLIで実装していたデプロイが、AWS CDKだけで実現できるようになりました。キャッシュの削除もコンソールから手動で行う必要がなくなり、デプロイする際の負担が軽減されました。

参考

AWS CDK が GA! さっそく TypeScript でサーバーレスアプリケーションを構築するぜ【 Cloud Development Kit 】
[AWS CDK]S3へローカルファイルをデプロイしてWebサイトを公開する