Help us understand the problem. What is going on with this article?

Amazon S3でSPAをサクッと公開する

はじめに

ストレージサービスとして有名&優秀なAmazon S3ですが、実は「静的ウェブサイトホスティング」という機能を使うことで、Vue.jsやReactで作ったSPAを簡単に公開することができます。また、AWS CLI を使用することでコマンド一発でサクッとデプロイすることができます。herokufirebaseなどのPaaSが充実している昨今、あまりS3でやるメリットない気もしますが。今回はその手順についてまとめてみました。

(ちなみに私がVue.jsをよく使うのでちょくちょくVue.jsが登場しますが、Reactでも同様の操作ができるはずなので、適宜読み替えていただければと思います。)

お値段

まず一番大事なお金の話から。
S3の料金は「利用したストレージの容量」「リクエスト件数」「リクエストに対するデータ送信量」の3軸で計算されます。

ストレージ料金
最初の 50 TB/月 0.025USD/GB
リクエスト料金
PUT、COPY、POST、または LIST リクエスト リクエスト 1,000 件あたり 0.0047USD
GET、SELECT および他のすべてのリクエスト リクエスト 1,000 件あたり 0.00037USD
データ転送料金
1 GB まで/月 0.00USD/GB
次の 9.999 TB/月 0.114USD/GB

料金 - Amazon S3 | AWSより一部抜粋

例えば、配信するコンテンツのデータサイズが1MB、リクエスト件数が100件/日の場合、
ストレージ料金:0.000025USD
リクエスト料金:0.00111USD
データ転送料金:0.228USD
で、合計約 0.229USD/月 (日本円で約 25.19円/月)です。ばちくそ安いですね。

アカウント開設から1年以内の無料枠を利用すればほぼ0円に抑えられると思います。
※参考 - AWS クラウド無料利用枠

SPAの準備

各フレームワークでのビルドを実行し、
index.htmlと各フォルダ(css/js/img等)が揃っている状態にしましょう。
スクリーンショット 2019-11-12 9.28.31.png

ちなみにVue.jsでのプロジェクト開始方法およびビルド方法はこちらの記事(Vue CLI スタートガイド)にまとめてありますので、フロントフレームワークを全く触ったことないという方はこちらを参考にしてみてください。

S3用のIAMユーザ作成

AWSルートアカウントの作成

AWSを初めて使うという方はAWSルートアカウントを作成しましょう。
こちらを参考にすると良いと思います。
AWS アカウント作成の流れ | AWS

S3用のIAMユーザの作成

ルートアカウントは全権限アカウントのため全てのAWSリソースへのアクセスができてしまいます。このルートアカウントで作業を続けることはセキュリティ上よろしくないので、S3のみ使用可能なIAMユーザを別途作成し、今後の作業はこのS3用IAMユーザで行います。

まずルートアカウントでログインし、マネジメントコンソールからIAMへ移動します(検索バーで「iam」と打てば出てきます)。
スクリーンショット 2019-11-10 22.48.28.png

「ユーザー」メニューを選択すると、作成したIAMユーザの一覧が表示されます。
今回は新規でユーザを作成するので、青色ボタンの「ユーザーを追加」をクリックしましょう。
スクリーンショット 2019-11-10 22.52.02.png

IAMユーザを作成するための設定画面が表示されます。

  • ユーザー名は任意の名前で構いません(公開しようとしているSPA用のIAMユーザであることが分かるネーミングだと良いです)
  • 「AWS マネジメントコンソールへのアクセス」にチェックを入れ、ログインパスワードを設定しましょう
    スクリーンショット 2019-11-10 23.05.31.png

  • 「既存のポリシーを直接アタッチ」から、AmazonS3FullAccessを選択し、チェックを入れましょう
    スクリーンショット 2019-11-10 23.10.52.png

それ以外はデフォルトの設定で問題ありません。

IAMユーザの作成が完了すると一覧に表示されるので、問題なく作成されているか確認しましょう。
スクリーンショット 2019-11-10 23.19.27.png

IAMユーザの作成が完了したら、早速ログインしてみましょう。
右上にIAMユーザ名 @ アカウント名と表示されていれば問題なくログインできています。
スクリーンショット 2019-11-11 9.57.50.png

S3以外のサービスへのアクセスがブロックされているか確認するために、試しにIAMを開いてみましょう。
先ほどIAMユーザを作成した画面に移動しても「アクセス権限が必要です」と表示され、ユーザを新規作成できないようになっているはずです。
スクリーンショット 2019-11-11 10.01.22.png

このように、利用用途ごとにIAMユーザを作成してAWSサービスへの権限を切り分け、意図しない操作が実行されないようにしましょう。

S3でSPAを公開

先ほどログインしたS3用IAMユーザで作業を進めます。

バケットの作成

S3の画面へ移動し、青色の「+バケットを作成する」ボタンをクリックしましょう。
バケット作成に際しての設定画面が表示されるので、情報を入力しましょう。

  • バケット名:任意の文字で構いません。ここで設定したバケット名が後ほど静的ホスティングする際のURLの一部として使われるので、それっぽい名前を付けましょう。
  • リージョン:これも任意で構いませんが、「アジアパシフィック(東京)」を選択するのが無難です。 スクリーンショット 2019-11-11 10.23.26.png

それ以外の設定は一旦デフォルトのままで問題ないです。

バケットが作成されるとバケット一覧に表示されるようになります。
スクリーンショット 2019-11-11 10.31.27.png

コンテンツのアップロード

バケット名をクリックするとバケットの詳細画面に遷移することができます。
青色の「アップロード」ボタンをクリックし、公開したいSPAの各ファイル(index.htmlとcss/js/imgフォルダ等)をローカルからアップロードしましょう。
初回アップロード時にバケットの設定について色々と聞かれますが、全てデフォルトで問題ないです。
無事アップロードが完了するとこのような画面になると思います。
スクリーンショット 2019-11-11 10.49.53.png

静的ウェブサイトホスティング機能の設定

「プロパティ」タブへ移動し、「Static website hosting」の設定を行います。

  • 「このバケットを使用してウェブサイトをホストする」にチェックを入れます
  • 「インデックスドキュメント」にindex.htmlを指定します スクリーンショット 2019-11-11 10.52.54.png

上記の設定が完了したら「保存」ボタンをクリックしましょう。

なお、この画面で表示されている「エンドポイント」のURLがウェブサイトへのアクセス用URLになります。が、今の状態でこのURLにアクセスしようとしても403エラーが返ってきてしまいます。URLでのアクセスを許可するために、次の章で説明するバケットポリシーを設定しましょう。
スクリーンショット 2019-11-11 11.00.11.png

バケットポリシーの設定

S3に格納したオブジェクトが不用意にネットに晒されないよう、デフォルトでは外部からS3バケットへのアクセスは全て拒否するようになっています。先ほど403エラーが返ってきたのもそのためです。正しくWebページを表示させるためにはURLによる外部からのリクエストを明示的に許可する必要があります。

アクセス制御に関することは「アクセス制御」タブで行います。

まず、「ブロックパブリックアクセス」を開きます。「編集」をクリックし、以下の設定を行います。

  • 「パブリックアクセスをすべてブロック」のチェックを外します
  • 下から2つ目、「新しいパブリックバケットポリシーを介して...」のチェックを外します
  • 一番下、「任意のパブリックバケットポリシーを介して...」のチェックを外します スクリーンショット 2019-11-11 22.28.31.png

これでバケットポリシーによるアクセス許可設定が有効になります。ここの設定を行わないと、いくらバケットポリシーで許可の設定を行ってもブロックされてしまうので注意しましょう。

次に「バケットポリシー」を開き、エディタ欄に以下のJSONをバケット名を置き換えて貼り付けましょう。
このJSONはsample-hosting-kiyokiyoバケットへのGetリクエストを許可するバケットポリシーです。AWS公式チュートリアルのものをそのまま抜粋しました。バケット名の部分のみ、自分が作成したバケット名に置き換えるのを忘れないようにしましょう。

{
   "Version":"2012-10-17",
   "Statement":[{
    "Sid":"PublicReadForGetBucketObjects",
         "Effect":"Allow",
      "Principal": "*",
       "Action":["s3:GetObject"],
       "Resource":["arn:aws:s3:::sample-hosting-kiyokiyo/*"
       ]
     }
   ]
 }

これで外部からS3に格納したファイルを取得できるようになりました。
先ほど403エラーが返ってきたURLでアクセスし直すと、今度は正しくWebページが表示されるようになっているはずです。
スクリーンショット 2019-11-11 22.45.49.png

S3へのデプロイコマンドを作る

上記の手順でWebページの公開はできるようになりましたが、Webページを更新するたびにIAMユーザでログインし、S3バケットに格納してあるファイルを削除して、ローカルにある新しいファイルをアップロードし直す、というのはかなり面倒です。Vue.jsでは
npm run serveでローカルサーバーを起動し、
npm run buildでビルドを行うことができます。
それと同じノリで、
npm run deployで、S3へのデプロイができるよう設定を組みましょう。

AWS CLI を使用する

AWS CLI を使うと、ターミナル等のコマンドラインツールからAWSサービスを操作できるようになります。これを利用して、S3上の対象バケットにあるファイルを削除し、ローカルにある新規ファイルをアップロードするスクリプトを組みます。

こちらの記事でAWS CLI を使うための手順がまとめられているので参考にしてみてください。
【初心者向け】MacユーザがAWS CLIを最速で試す方法 | Developers.IO

かいつまんで説明しますと、

1:まずpipをインストールします(Python3.4以降であればPythonのインストールと同時に使えるそうです)。pip -Vと打ってバージョンが表示されれば問題ないです。

$ pip -V
pip 19.3.1 from /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pip (python 3.7)

2:次にAWS CLI をインストールします

$ pip install awscli

3: ルートアカウントでS3用IAMユーザのアクセスキーとシークレットアクセスキーを生成・取得します。IAMメニューで先ほど作成したS3用IAMユーザを選択し、「認証情報」タブの「アクセスキーの作成」ボタンをクリックします。アクセスキーとシークレットアクセスキーが表示されるので、手元に控えておきましょう。
スクリーンショット 2019-11-11 23.24.42.png

4:ターミナルにaws configureと入力しS3を操作するための設定を行います。Access Key IDSecret Access Keyに先ほど取得した情報を入力しましょう。Default regionはS3バケットで指定したリージョン(アジアパシフィック(東京)の場合はap-northeast-1)を入力しましょう。Default output formatはとりあえずtextで問題ありません。

$ aws configure
AWS Access Key ID [None]: XXXX
AWS Secret Access Key [None]: XXXXXXXX
Default region name [None]: ap-northeast-1
Default output format [None]: text

動作確認として、aws s3 lsでS3に登録しているバケットが一覧表示されればOKです。

$ aws s3 ls
2019-11-11 22:45:22 sample-hosting-kiyokiyo

デプロイ用のシェルスクリプトを組む

index.html等が格納されているディレクトリをdistとします。
distと同じ階層にデプロイ用のスクリプトを記載したdeploy-s3.shを配置します。
ディレクトリ構造のイメージはこんな感じです。

(any directory)
 ├dist/
 │ ├css/
 │ ├img/
 │ ├js/
 │ └index.html
 └deploy-s3.sh

deploy-s3.shの中身はこんな感じで書きます。

deploy-s3.sh
#!/bin/sh

aws s3 rm s3://sample-hosting-kiyokiyo/ --recursive
aws s3 cp dist s3://sample-hosting-kiyokiyo/ --recursive

1行目はシェルスクリプトを走らせるためのおまじないです。詳しく知りたい方はこちらの記事(#!/bin/sh は ただのコメントじゃないよ! Shebangだよ!)とかが参考になると思います。
2行目ではsample-hosting-kiyokiyoバケットの中身を再帰的(--recursive)に削除(rm)しています。
3行目ではdistディレクトリの中身をsample-hosting-kiyokiyoバケットにコピー(cp)しています。

AWS CLI でできることはこちらのAWS CLI Command Referenceにまとまっているので、他のスクリプトを走らせたい方は調べてみてください。

デプロイ用コマンドを作る

最後に、npm run deployと入力したら先ほど作成したdeploy-s3.shが呼び出されるようにします。
npm runコマンドはpackage.jsonscriptsブロックで設定できます。
"deploy": "bash deploy-s3.sh"をscriptsブロック内に追加しましょう。

package.json
{
  (省略)
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "deploy": "bash deploy-s3.sh"
  },
  (省略)
}

これで作業としては完了です。
試しにローカルでの変更をS3にデプロイできるか確かめてみましょう。

まず、ローカルで適当に変更を行います。
サンプルとして今回はとりあえずApp.vueのHelloWorldタグを以下のように変えてみます。

(変更前)
<HelloWorld msg="Welcome to Your Vue.js App"/>
(変更後)
<HelloWorld msg="Hi! My name is Kiyokiyo! Nice to meet you!"/>

ビルドコマンドを走らせます。

$ npm run build

これでローカルのdistディレクトリ以下に必要なファイルが揃いました。

最後にデプロイコマンドを走らせます。

$ npm run deploy

S3上のファイルがdeleteされ、ローカルのファイルがS3にアップロードされたことが、ターミナルの出力からも分かると思います。

WebページのURLにアクセスするとしっかり変更が反映されていますね。
スクリーンショット 2019-11-12 9.17.36.png

おわりに

これでローカルで作成していた静的ウェブサイトを公開できるようになりました。
デプロイもコマンド一発で簡単にできるようになったので、開発速度もかなり向上したんじゃないでしょうか。

個人的な今後としては、LambdaやDynamoDBを利用したサーバーレスAPIとの通信にチャレンジしてみたいと思います。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away