Log目次

【AWS】SAMでSPAを公開する手順まとめ

作成日 2020-06-21更新日 2020-06-21

システム構成

今回作成するシステム構成は下記になります。

情報の収集はLambdaにRSSの情報を取得する関数を作成し、cloud watchのイベントで定期実行しDynamoDBに保存。

アクセスは、Cloud Front経由でApiGateway、S3にアクセス。

デプロイは、samコマンドでバックエンド(API、バッチ)をCodePipelineでフロントをデプロイする構成になります。

作成たサイトはこちら(サービス停止済)

SAMの環境構築

はじめに、aws-sam-cliをインストールします。

手順は、公式にのものを参考にします。

brew tap aws/tap brew install aws-sam-cli

特に問題なくインストール完了

続いて、プロジェクトを作成します。

コマンドは、sam initです。

ここでは、対話的にプロジェクトの設定を行なっていきます。

xxxxxxMacBook-Pro:aws_batch tomoki$ sam init SAM CLI now collects telemetry to better understand customer needs. You can OPT OUT and disable telemetry collection by setting the environment variable SAM_CLI_TELEMETRY=0 in your shell. Thanks for your help! Learn More: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-telemetry.html Which template source would you like to use? 1 - AWS Quick Start Templates 2 - Custom Template Location Choice: 1 Which runtime would you like to use? 1 - nodejs12.x 2 - python3.8 3 - ruby2.7 4 - go1.x 5 - java11 6 - dotnetcore2.1 7 - nodejs10.x 8 - python3.7 9 - python3.6 10 - python2.7 11 - ruby2.5 12 - java8 13 - dotnetcore2.0 14 - dotnetcore1.0 Runtime: 3 Project name [sam-app]: get-youtube-rss Cloning app templates from https://github.com/awslabs/aws-sam-cli-app-templates.git ----------------------- Generating application: ----------------------- Name: get-youtube-rss Runtime: ruby2.7 Dependency Manager: bundler Application Template: hello-world Output Directory: . Next steps can be found in the README file at ./get-youtube-rss/README.md

作成された階層構造以下の通りです。

├── Gemfile ├── README.md ├── events │ └── event.json ├── hello_world │ ├── Gemfile │ └── app.rb ├── template.yaml └── tests └── unit └── test_handler.rb

ここで、ローカルにbundlerがなかったので追加します。

gem install bundler

PermissionErrorになったのでここを参考にrubyを設定

# samで使用するバージョンに合わせて2.7をインストール rbenv install 2.7.0 xxxxMacBook-Pro:get-youtube-rss xxxx$ rbenv global 2.7.0 xxxxMacBook-Pro:get-youtube-rss xxxx$ rbenv local 2.7.0 xxxxMacBook-Pro:get-youtube-rss xxxx$ rbenv local 2.7.0 xxxxMacBook-Pro:get-youtube-rss xxxx$ rbenv global 2.7.0

インストールが完了したので、rubyのパスを通します。

echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.bash_profile source ~/.bash_profile # 確認 xxxxMacBook-Pro:get-youtube-rss xxxx$ which ruby /Users/xxxx/.rbenv/shims/ruby xxxxMacBook-Pro:get-youtube-rss xxxx$ which gem /Users/xxxx/.rbenv/shims/gem

最後にbundlerをインストールします。

xxxxMacBook-Pro:get-youtube-rss xxxx$ gem install bundler Fetching bundler-2.1.4.gem Successfully installed bundler-2.1.4 Parsing documentation for bundler-2.1.4 Installing ri documentation for bundler-2.1.4 Done installing documentation for bundler after 2 seconds 1 gem installed

成功!!

gemはlamdaの関数ごとに管理したかったので、gemを追加する場合は、hellow_word以下で下記のコマンドを実行しました。

bundle install --path vendor/bundle

バックエンド側のデプロイ

ソースはこんな感じで実装

はじめに、aws-cliをインストールします。

コマンドインストール後、パスを通す必要があったのであらかじめコマンドのインストール場所を確認します。

インストールについて

# インストールコマンド pip3 install awscli --upgrade --user # インストール結果 xxxxMacBook-Pro:get-youtube-rss xxxx$ pip3 install awscli --upgrade --user Requirement already up-to-date: awscli in /Users/xxxx/Library/Python/3.7/lib/python/site-packages (1.18.5) Requirement already satisfied, skipping upgrade: botocore==1.15.5 in /Users/xxxx/Library/Python/3.7/lib/python/site-packages (from awscli) (1.15.5) Requirement already satisfied, skipping upgrade: s3transfer<0.4.0,>=0.3.0 in /Users/xxxx/Library/Python/3.7/lib/python/site-packages (from awscli) (0.3.3)

.bash_profileにパスを追加します。

# パス指定 export PATH=/Users/xxxx/Library/Python/3.7/bin:$PATH # 反映 source ~/.bash_profile

次に、デプロイ用のIAMユーザーを作成します。

IAMユーザーにはデプロイ中使用する権限を付与しておきます。

ここでは、下記の権限を付与しました。(本当はFullAccessじゃなくて、必要なものだけの方が良い。。)

次にAWSへの認証情報をaws configで設定します。

設定内容は以下のものです。(参照元)

ここまで設定できたら、デプロイを行います。

デプロイ用のコマンドはsam deploy –guided

–guidedでデプロイの初期設定を行います。

2回目以降は、sam deployでデプロイできます。

xxxxMacBook-Pro:get-youtube-rss xxxx$ sam deploy --guided Configuring SAM deploy ====================== Looking for samconfig.toml : Not found Setting default arguments for 'sam deploy' ========================================= Stack Name [sam-app]: batch-youtube-rss AWS Region [us-east-1]: ap-northeast-1 #Shows you resources changes to be deployed and require a 'Y' to initiate deploy Confirm changes before deploy [y/N]: y #SAM needs permission to be able to create roles to connect to the resources in your template Allow SAM CLI IAM role creation [Y/n]: y Save arguments to samconfig.toml [Y/n]: y

フロント側のデプロイ

フロントのソースをS3にデプロイします。

デプロイには、CodePipelineを使用します。

ここでは、Source、Build、Deployの3つをCodePipelineに定義し、GitHubにソースをPushすると自動でS3にデプロイできるようにします。

Sourceの設定

Githubの対象のリポジトリを指定します。

Buildの設定

CodeBuildのプロジェクトは、ほとんと規定値で作成しました。

Deployの設定

デプロイ用のバケットはあらかじめ作成しておきます。 入力アーティファクトにはBuild工程の出力アーティファクトを指定します。

最終的にCodePipelineは、以下のようなフローになります。

ドメインの設定

公開するサイトのドメインをRoute53に登録します。

ドメインは事前に取得しています。

Route53のコンソールで「ホストゾーン作成」より取得したドメイン名を入力し、作成を行います。

CloudFrontの設定

CloudFrontの設定を行います。

CloudFrontのコンソールでCreate Distributionsを選択します。

次の画面では、Webを選択します。

Origin SettingsはフロントのコードをデプロイしたS3を指定します。

また、Origin Access IdentityではCreate a New Identityを選択し、Identity作成と対象のS3バケットのバケットポリシーを更新します。

Default Cache Behavior Settingsはキャッシュの時間の設定です。(ここでは、デフォルトのまま)

ここまでの設定内容で一旦、distributionを作成します。

次にRoute53に戻り、CNAMEレコードを作成します。

値には作成したdistributionのIDを指定します。

CloudFrontの設定に戻り、作成したdistributionを編集します。 Distribution Settingsでは先ほど作成したCNAMEの名前をつけて指定します。

SSL CertificateはCustom SSL Certificate (example.com)を選択します。

SSL証明書を発行するため、「Request or Import Certificate with ACM」を押下します。

ドメイン名の追加では、先ほど入力したドメインを入力します。次の検証方法の選択ではDNSを選択します。

この画面では、「Route53でのレコードを作成」を押下し、検証が完了するのを待ちます。

完了すれば、Custom SSL Certificate で証明書の選択ができるので、選択し設定を保存します。

次にバックエンドのAPI用のOriginを追加します。

作成したDistributionから「Create Origin」を行い、以下の設定し、作成します。

エンドポイントはAPI Gatewayのコンソールで確認できます。(黒塗りの部分)

最後にBehaviorsを作成します。

最初にS3の定義を作成します。(Path Patternがデフォルトになるように)

次にAPIの定義を作成します

Minimun、Maximum、Default TTLはオブジェクトを CloudFront キャッシュに保持する時間を指定します。(詳細)

動作確認

ブラウザで下記URLにアクセスし、ちゃんと表示されることを確認します。

https://www.latg.site/ (停止済)

反省点

lambdaでのバッチ実行は30分間隔で実行していたが、lambdaの立ち上がりが遅すぎて15分を超えてタイムアウトになる。(Gemなどライブラリをインストールしているから?)

間隔を5分にしてlambdaが毎回コールドスタートになるのを防ごうとするとDynamoDB側で「The level of configured provisioned throughput for the table was exceeded. Consider increasing your provisioning level with the UpdateTable API.」エラーが発生(参考)

今回は、RSSで取得したデータを日付でソートし、先頭N件のデータを取得するために日付項目をソートキーに設定。

加えて、DynamoDBは検索時にパーティションキーの指定が必須(scanの場合は不要だがソートできない)なので、固定値を設定するようにしていた。

結果、1つにパーティションキーにアクセスが集中することになった。(当然だが。。。)

DynamoDBのDB設計(そもそもDynamoDBを使用するのか?データ構造、使い方的にはRDBの方が合っているのでは?)

そもそもlambdaでやるべきことなのかその辺りも考量して設計しなくてはいけなかった。

参考