AWSの静的ウェブサイトホスティングで入門するAWS Amplify(Console、CLI) - 構築編(Amplify CLI)

小西秀和です。
これまで「AWSの静的ウェブサイトホスティングで入門するAWS Amplify(Console、CLI) - 概要編」の記事でサーバーレスな静的ウェブサイトホスティングを題材に概要を、「AWSの静的ウェブサイトホスティングで入門するAWS Amplify(Console、CLI) - 構築編(Amplify Console)」でAWS Amplify Consoleの簡単な構築方法について説明してきました。
今回はその記事の続編としてAmplify CLIを使用したサーバーレスな静的ウェブサイトホスティングを構築する手順を見ていきます。

Amplify CLIによる静的ウェブサイトホスティング(Amazon S3+Amazon CloudFront)の構築例

概要編でも説明しましたがAmplify CLIからは次の2つのホスティング環境を作成することができます。

  • Amplify Consoleによるホスティング(AWS管理のユーザーが設定変更できないManaged Hosting)
  • Amazon S3+Amazon CloudFrontによるホスティング(Amplify CLIでAWS CloudFormationを自動生成して作成する)

Amplify Consoleによるホスティングは構築編(Amplify Console)と同じ話になるため、ここではAmplify CLIでAWS CloudFormationを自動生成して作成するAWS CloudAmazon S3+Amazon CloudFrontによるホスティングを見ていきたいと思います。
今回、構築したいアーキテクチャは次の図のようになります。

Amplify CLIによるS3+CloudFrontの構成とエンドユーザーアクセス
Amplify CLIによるS3+CloudFrontの構成とエンドユーザーアクセス

Amazon S3とAmazon CloudFrontのみで構成され、その他のバックエンドやフロントエンドアプリケーションも含まない非常にシンプルなものです。
それでは、まずAmplify CLIをインストールするところから始めていきたいと思います。

Amplify CLIのインストールと設定

Amplify CLIのインストール

Amplify CLIをインストールする方法にはいくつかありますが、どのOSでも共通してできるのが「Node.jsとNPMによるインストール」になります。
他にもcurlによるインストール方法がありますが、Amplify CLIはNode.jsとNPMを使用するためいずれにしてもこれらはインストールされます。

  • Node.jsとNPMによるインストール
    Node.js(バージョン12.x以上)、npm(バージョン6.x以上)をインストールして次のコマンドを実行する。
npm install -g @aws-amplify/cli
  • cURLコマンドによるインストール(MacとLinuxの場合)
    Mac、Linuxのターミナルで次のコマンドを実行する。
curl -sL https://aws-amplify.github.io/amplify-cli/install | bash && $SHELL
  • cURLコマンドによるインストール(Windowsの場合)
curl -sL https://aws-amplify.github.io/amplify-cli/install-win -o install.cmd && install.cmd
#curlコマンドが無い場合は「https://aws-amplify.github.io/amplify-cli/install-win」からブラウザでダウンロードしたファイルを「install-win.cmd」のように.cmd拡張子にして実行する。

参考:Get started - Installation - Amplify Docs

Amplify CLIの設定

次のコマンドを実行して設定を開始します。

amplify configure

対話形式で使用するAWSリージョン、IAMユーザーを設定します。

[iam@h-o2k.com ~]$ amplify configure
Follow these steps to set up access to your AWS account:

Sign in to your AWS administrator account:
https://console.aws.amazon.com/
Press Enter to continue

Specify the AWS Region
? region:  (Use arrow keys)
  us-east-1 
  us-east-2 
  us-west-2 
  eu-west-1 
  eu-west-2 
  eu-central-1 
❯ ap-northeast-1
(Move up and down to reveal more choices)
Specify the AWS Region
? region:  ap-northeast-1 ←【ここではap-northeast-1を選択しました】
Specify the username of the new IAM user:
? user name:  amplify-admin ←【ここではamplify-adminというIAMユーザーにしました】
Complete the user creation using the AWS console
https://console.aws.amazon.com/iam/home?region=ap-northeast-1#/users$new?step=final&accessKey&userNames=amplify-admin&permissionType=policies&policies=arn:aws:iam::aws:policy%2FAdministratorAccess
Press Enter to continue

新しいIAMユーザーを作成する場合は上記のようにコマンドラインに表示されるリンクからAWSマネジメントコンソールを開いて設定します。

ユーザー名や付与するポリシーなどの情報を設定してIAMユーザーを作成します。
ポリシーにはAmplify CLIを使用して作成、変更、削除をするAWSリソースにあったものを適用します。
今回は個人の実験用AWSアカウントを使用しているのでGet started - Installation - Amplify Docsと同様にAdministratorAccessを付与しました。
IAMユーザーを作成後、コマンドラインに戻り、accessKeyIdsecretAccessKeyおよびこれらの設定を保存するプロフィール名を入力します。
ここで、プロフィール名にAWS CLIなどで使用している既存のもの(defaultなど)を入力してしまうと上書きされてしまうので注意が必要です

Enter the access key of the newly created user:
? accessKeyId:  ********************
? secretAccessKey:  ****************************************
This would update/create the AWS Profile in your local machine
? Profile Name:  amplify-admin ←【※既存のプロフィール名が上書きされるるので要注意】
Successfully set up the new user.

Amplify CLIによるホスティング環境(Amazon S3+Amazon CloudFront)の構築

続いてAmplify CLIを使用して実際にプロジェクトを作成していきます。
Amplify CLIのコマンドについては概要編の「Amplify CLIのコマンド一覧」に記載していますので、あわせて参照してください。

  1. まず最初にプロジェクトディレクトリを作成して、amplify initコマンドでプロジェクトの初期設定をします。この例では「AmplifyCLIDemo」というプロジェクト名を使用します。
    [iam@h-o2k.com ~]$ mkdir AmplifyCLIDemo
    [iam@h-o2k.com ~]$ cd AmplifyCLIDemo
    [iam@h-o2k.com AmplifyCLIDemo]$ amplify init
    Note: It is recommended to run this command from the root of your app directory
    ? Enter a name for the project (AmplifyCLIDemo) ←【今回はそのまま】
    The following configuration will be applied:
    
    Project information
    | Name: demo8
    | Environment: dev
    | Default editor: Visual Studio Code
    | App type: javascript
    | Javascript framework: none
    | Source Directory Path: src
    | Distribution Directory Path: dist
    | Build Command: npm run-script build
    | Start Command: npm run-script start
    
    ? Initialize the project with the above configuration? (Y/n) ←【今回はそのままY】
    ? Initialize the project with the above configuration? Yes
    Using default provider  awscloudformation
    ? Select the authentication method you want to use: (Use arrow keys)
    ❯ AWS profile ←【aws configureで作成したプロファイルを使用するためこちらを選択】
      AWS access keys
    ? Select the authentication method you want to use: AWS profile
    
    For more information on AWS Profiles, see:
    https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html
    
    ? Please choose the profile you want to use
      default
      iam
      standard
      rakuzando
      AmazonCloudWatchAgent
    ❯ amplify-admin ←【aws configureで作成したこのプロファイルを選択】
    
    ここまで入力と選択をするとAWS Amplify Consoleのバックエンド、AWS CloudFormationスタック、IAMロール、デプロイ用Amazon S3バケットといった必要なAWSリソースを自動的にプロビジョニングしてくれます。

    この状態でのディレクトリ構成は次のようになっていました。
    [iam@h-o2k.com AmplifyCLIDemo]$ tree
    .
    ├── amplify
    │   ├── #current-cloud-backend
    │   │   ├── amplify-meta.json
    │   │   └── tags.json
    │   ├── README.md
    │   ├── backend
    │   │   ├── amplify-meta.json
    │   │   ├── backend-config.json
    │   │   └── tags.json
    │   ├── cli.json
    │   └── team-provider-info.json
    └── src
        └── aws-exports.js
    
  2. 次に、amplify add hostingコマンドを使用して静的ホスティングのリソースであるAmazon S3とAmazon CloudFrontを追加していきます。
    [iam@h-o2k.com AmplifyCLIDemo]$ amplify add hosting
    ? Select the plugin module to execute
      Hosting with Amplify Console (Managed hosting with custom domains, Continuous deployment)
    ❯ Amazon CloudFront and S3 ←【Amplify Consoleを使用しないCloudFront+S3を選択】
    ? Select the plugin module to execute Amazon CloudFront and S3
    ? Select the environment setup:
      DEV (S3 only with HTTP)
    ❯ PROD (S3 with CloudFront using HTTPS) ←【S3+CloudFrontのPROD環境を選択】
    ? Select the environment setup: PROD (S3 with CloudFront using HTTPS)
    ? hosting bucket name (amplifyclidemo-20210717003719-hostingbucket)
    ? hosting bucket name amplifyclidemo-20210717003719-hostingbucket
    Static webhosting is disabled for the hosting bucket when CloudFront Distribution is enabled.
    
    You can now publish your app using the following command:
    Command: amplify publish
    
  3. 続いて、プロジェクトのトップディレクトリにpackage.jsonというファイルを作成して次のように内容を記述します。
    [iam@h-o2k.com AmplifyCLIDemo]$ vi package.json
    [iam@h-o2k.com AmplifyCLIDemo]$ cat package.json
    {
      "name": "AmplifyCLIDemo",
      "version": "1.0.0",
      "description": "AWS Amplify CLI Demo",
      "dependencies": {},
      "devDependencies": {
      },
      "scripts": {
        "start": "",
        "build": ""
      }
    }
    
    package.jsonはバックエンドにデプロイするアプリケーションのバージョンや依存関係、ビルドコマンドなどの設定を記載するファイルなのですが、今回はAmazon S3とAmazon CloudFrontとデモ用の静的ファイルのみをデプロイするため、最小限の記述にしています。

  4. 次に、S3+CloudFrontのホスティング環境にデプロイするためのディレクトリとファイルを作成します。
    [iam@h-o2k.com AmplifyCLIDemo]$ mkdir dist
    [iam@h-o2k.com AmplifyCLIDemo]$ vi ./dist/index.html
    [iam@h-o2k.com AmplifyCLIDemo]$ cat ./dist/index.html
    <!DOCTYPE html>
    <html>
    <head>
    <title>AWS Amplify CLI Demo</title>
    </head>
    <body>
    AWS Amplify CLI Hosting S3+CloudFront Demo
    </body>
    </html>
    
    ここまでの手順でディレクトリ構成は次のようになっていました。
    [iam@h-o2k.com AmplifyCLIDemo]$ tree
    .
    ├── amplify
    │   ├── #current-cloud-backend
    │   │   ├── amplify-meta.json
    │   │   └── tags.json
    │   ├── README.md
    │   ├── backend
    │   │   ├── amplify-meta.json
    │   │   ├── backend-config.json
    │   │   ├── hosting
    │   │   │   └── S3AndCloudFront
    │   │   │       ├── parameters.json
    │   │   │       └── template.json
    │   │   └── tags.json
    │   ├── cli.json
    │   └── team-provider-info.json
    ├── dist
    │   └── index.html
    ├── package.json
    └── src
        └── aws-exports.js
    
    7 directories, 13 files
    
  5. そして、amplify publishコマンドを使用して以上の設定とファイルをデプロイします。
    [iam@h-o2k.com AmplifyCLIDemo]$ amplify publish
    ✔ Successfully pulled backend environment dev from the cloud.
    
    Current Environment: dev
    
    | Category | Resource name   | Operation | Provider plugin   |
    | -------- | --------------- | --------- | ----------------- |
    | Hosting  | S3AndCloudFront | Create    | awscloudformation |
    ? Are you sure you want to continue? (Y/n) ←【「Y」を選択】
    ? Are you sure you want to continue? Yes
    ⠼ Updating resources in the cloud. This may take a few minutes...
    
    ~省略~
    
    ✔ All resources are updated in the cloud
    
    Hosting endpoint: https://d29v454ta49b1c.cloudfront.net
    
    frontend build command exited with code 0
    Publish started for S3AndCloudFront
    ✔ Uploaded files successfully.
    Your app is published successfully.
    https://d29v454ta49b1c.cloudfront.net
    
    デプロイが成功すると、Amazon CloudFrontのDistribution domain nameが表示されるので、そのURLにアクセスすれば作成したデモ用のファイルの内容が表示されるはずです。

    ただし、この記事の執筆時点ではデプロイ直後にアクセスするとAmaozn S3のアクセスエラーがでて表示されません。



    この問題は次の手順で解決します。

  6. このAWS Amplify CLIのHostingカテゴリでAmazon S3+Amazon CloudFront環境を作成するとAccessDeniedエラーが発生する問題は次のナレッジセンターのQAに関連しています。

    Amazon S3 での HTTP 307 エラーのトラブルシューティング

    簡単にまとめるとAmazon CloudFront側で登録しているAmazon S3バケットのオリジンドメイン名がグローバルエンドポイントであるからです。これによって、作成後24時間以内のAmazon S3バケットが表示されない可能性があります。
    そのため、すぐにサイトを表示させたい場合はリージョン毎のエンドポイントに書き換えることで解決を試みます。
    #グローバルエンドポイントを
    <Amazon S3バケット名>.s3.amazonaws.com
    #↓リージョン別のエンドポイントに変更
    <Amazon S3バケット名>.s3.ap-northeast-1.amazonaws.com
    
    ただ、AWS Amplify CLIはAWS CloudFormationを生成してAWSリソースをデプロイしているため、AWS CloudFormationテンプレートを修正する必要があります。
    ということで、AWS Amplify CLIの入門の途中ですが、少しAWS CloudFormationに入門することになります。
    まず、プロジェクトディレクトリ配下を確認すると先程のamplify publishコマンドで様々なディレクトリやファイルができあがっていることがわかります。
    [iam@h-o2k.com AmplifyCLIDemo]$ tree
    .
    ├── amplify
    │   ├── #current-cloud-backend
    │   │   ├── amplify-meta.json
    │   │   ├── backend-config.json
    │   │   ├── hosting
    │   │   │   └── S3AndCloudFront
    │   │   │       ├── parameters.json
    │   │   │       └── template.json
    │   │   └── tags.json
    │   ├── README.md
    │   ├── backend
    │   │   ├── amplify-meta.json
    │   │   ├── awscloudformation
    │   │   │   ├── build
    │   │   │   │   ├── awscloudformation
    │   │   │   │   │   └── nested-cloudformation-stack.yml
    │   │   │   │   └── hosting
    │   │   │   │       └── S3AndCloudFront
    │   │   │   │           └── template.json
    │   │   │   └── nested-cloudformation-stack.yml
    │   │   ├── backend-config.json
    │   │   ├── hosting
    │   │   │   └── S3AndCloudFront
    │   │   │       ├── parameters.json
    │   │   │       └── template.json
    │   │   └── tags.json
    │   ├── cli.json
    │   └── team-provider-info.json
    ├── dist
    │   └── index.html
    ├── package.json
    └── src
        └── aws-exports.js
    
    14 directories, 19 files
    
    このうち、S3+CloudFrontを構成しているAWS CloudFormationテンプレートファイルのCloudFrontDistributionのOriginを構成している部分を次のように修正します。
    (DomainNameをRegionalDomainNameに変更)
    [iam@h-o2k.com AmplifyCLIDemo]$ vi amplify/backend/hosting/S3AndCloudFront/template.json
    修正前------------------------------------------------------
                                "DomainName": {
                                    "Fn::GetAtt": [
                                        "S3Bucket",
                                        "DomainName"
                                    ]
                                },
    ------------------------------------------------------------
                                ↓131行~135行周辺
    修正後------------------------------------------------------
                                "DomainName": {
                                    "Fn::GetAtt": [
                                        "S3Bucket",
                                        "RegionalDomainName"
                                    ]
                                },
    ------------------------------------------------------------
    
    このようにAWS CloudFormationテンプレートでAmazon CloudFrontディストリビューションに設定するAmazon S3バケットのオリジンドメイン名をグローバルエンドポイントからリージョン別エンドポイントに変更しました。
    この修正をした後に再度amplify publishコマンドを実行します。
    [iam@h-o2k.com AmplifyCLIDemo]$ amplify publish
    ✔ Successfully pulled backend environment dev from the cloud.
    
    Current Environment: dev
    
    | Category | Resource name   | Operation | Provider plugin   |
    | -------- | --------------- | --------- | ----------------- |
    | Hosting  | S3AndCloudFront | Update    | awscloudformation |
    ? Are you sure you want to continue? (Y/n) Y ←【Yを選択】
    ? Are you sure you want to continue? Yes
    
    ~省略~
    
    ✔ All resources are updated in the cloud
    
    Hosting endpoint: https://d29v454ta49b1c.cloudfront.net
    
    frontend build command exited with code 0
    Publish started for S3AndCloudFront
    ✔ Uploaded files successfully.
    Your app is published successfully.
    
    再びAmazon CloudFrontのURLを開いてみるとデモ用のページが今後は表示されています。



    この一連の設定とデプロイによって何のアプリケーションも含まない純粋なAmazon S3+Amazon CloudFrontのホスティング環境を構築しました。
    AWS Amplify CLIを使用したAmazon S3+Amazon CloudFrontのホスティング環境の構築はここまでになります。

AWS CloudFormationによるAmplify CLIプロジェクトの拡張について

前述の手順の中でAmplify CLIで自動生成されたAWS CloudFormationテンプレートで、Amazon CloudFrontディストリビューションに設定するAmazon S3バケットのオリジンドメイン名をグローバルエンドポイントからリージョン別エンドポイントに変更しました。

このようにAmplify CLIは生成されたAWS CloudFormationテンプレートをカスタマイズして機能を追加・変更することができます。
例えば、Amplify CLIで作成されたAmazon S3+Amazon CloudFrontのAWS CloudFormationテンプレートをカスタマイズして、

・AWS Certificate Managerの証明書をアタッチしてAmazon Route 53で管理しているドメインと関連付ける
・Amazon CloudFrontにLambda@Edgeを追加して基本認証をする設定を追加する

などの機能追加をしてAmplify ConsoleのManaged Hostingの構成に近づけるようなこともできます(CloudFrontのAWS Certificate Manager証明書やLambda@Edgeはus-east-1リージョンでのみ使用できるため、Amplify CLIでデプロイするリージョンによってはCloudFormationカスタムリソースやCloudFormation StackSetsが必要)。
また、Amplify ConsoleのManaged Hostingでは細かく設定できない内容をS3やCloudFrontのリソースに追加することもできます。

AWS Amplify CLIによって基本的なホスティング部分のAWS CloudFormationテンプレートは自動生成されているので、それを修正して機能追加することでテンプレートを最初から作成するよりもハードルが低くAWS CloudFormationの入門の題材にも良いでしょう。

ただ、内容としてはAWS Amplify CLIというよりAWS CloudFormationの内容になりますので、AWS Amplifyに関する記事は一旦ここまでとしてAWS CloudFormationに関する記事をいくつか書いてから戻ってこようと考えています。

小西秀和

執筆者小西秀和

ALL AWS Certifications Engineer(AWS認定全取得)の知識をベースに
AWSクラウドの活用に取り組んでいます。