0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

AWS モダンウェブアプリケーションを構築するチュートリアルをやってみた

Posted at

初めに

以下のチュートリアルをやってみました。このチュートリアルでは S3 を利用した静的ウェブサイトを Fargate や Network Load Balancer、API Gateway 利用して動的ウェブサイトにする過程を学ぶことができました。さらに CI/CD 環境の構築、クリックイベントに対するストリーミング処理の方法も学ぶことができます。このチュートリアルではほとんど CLI、時折 CloudFormation を使用してアプリケーションを構築していきます。

1. 静的 Web サイトの作成

開発環境として Cloud9 を用います。リージョンは us-east-1 を選択しました。以下の手順で開発環境を作成します。

開発環境の名前を入力します。

1.png

すべてデフォルトのまま進めます。

2.png

「Next step」をクリックします。

3.png

「Create environment」をクリックします。

4.png

チュートリアルに使用するコードをクローンし、そのルートディレクトリに移動します。

git clone -b python https://github.com/aws-samples/aws-modern-application-workshop.git
cd aws-modern-application-workshop

ウェブサイトをホスティングするバケットを作成します。mythical-mysfits-python-tutorial-bucket はバケット名です。バケット名はグローバルで一意である必要があります。

aws s3 mb s3://mythical-mysfits-python-tutorial-bucket

次に静的 Web ホスティングを有効にします。静的 Web ホスティングを有効化することで以下のようなウェブサイトエンドポイントを利用して、リクエスト先を index.html に指定することができます。

  • http://bucket-name.s3-website-Region.amazonaws.com
  • http://bucket-name.s3-website.Region.amazonaws.com

上記 2 つのうちどちらを選択するかどうかはリージョンごとに決まっています。以下のリンクにすべて記載があります。

ユーザーガイドに記載がある通り、これらのエンドポイントには https ではアクセスできません。

Amazon S3 ウェブサイトエンドポイントは HTTPS をサポートしていません。

静的 Web ホスティングを有効にするために以下のコマンドを実行します。

aws s3 website s3://mythical-mysfits-python-tutorial-bucket --index-document index.html

なお上記の CLI は以下のコンソール画面の操作を行うのと同じことです。「S3 コンソール画面 → 設定したいバケット名を選択 → プロパティ → 静的ウェブサイトホスティング」 の手順で設定できます。

image.png

/aws-modern-application-workshop/module-1/aws-cli/website-bucket-policy.json を編集します。

/aws-modern-application-workshop/module-1/aws-cli/website-bucket-policy.json
{
  "Id": "MyPolicy",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadForGetBucketObjects",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::REPLACE_ME_BUCKET_NAME/*"
    }
  ]
}

上記の REPLACE_ME_BUCKET_NAME を作成したバケット名で置き換えます。このチュートリアルではこのような置き換えが何度も出てきます。チュートリアル通りに進めているのにエラーが発生した場合は、この置き換えがされていないことが原因かもしれません。以下はバケット名を置き換えた後のポリシーです。

/aws-modern-application-workshop/module-1/aws-cli/website-bucket-policy.json
{
    "Version": "2012-10-17",
    "Id": "MyPolicy",
    "Statement": [
        {
            "Sid": "PublicReadForGetBucketObjects",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::mythical-mysfits-python-tutorial-bucket/*"
        }
    ]
}

編集を保存した後、以下のコマンドを実行しバケットポリシーを設定します。

aws s3api put-bucket-policy --bucket mythical-mysfits-python-tutorial-bucket --policy file://~/environment/aws-modern-application-workshop/module-1/aws-cli/website-bucket-policy.json

S3 コンソール画面で確認し、設定が反映されていることが確認してみます。

image.png

/aws-modern-application-workshop/module-1/web/index.html をバケットにアップロードします。

aws s3 cp ~/environment/aws-modern-application-workshop/module-1/web/index.html s3://mythical-mysfits-python-tutorial-bucket/index.html

ウェブサイトエンドポイントの
http://mythical-mysfits-python-tutorial-bucket.s3-website-us-east-1.amazonaws.com
にアクセスし、ホスティングが正常に行われていることを確認します。

2. 動的ウェブサイトの構築

この章は動的なウェブサイトを構築するためのステップです。Python を使用して、 Docker コンテナに Flask アプリケーションを作成します。

2-1. CloudFormation でインフラを構築する

Fargate は VPC 内に配置されるサービスであり、VPC や サブネットなどを作成する必要があるため、このチュートリアルでは CloudFormation を使用します。

リソース 用途 個数
VPC Fargate を配置する 1
NAT Gateway 用 Elastic IP NAT Gateway の変換グローバル IP アドレスとして使用する 2
NAT Gateway プライベートサブネットからインターネットにアクセスする 2
Internet Gateway パブリックサブネットとインターネットを接続する 1
Fargate 用 セキュリティグループ Fargate が NLB からのトラフィックを許可するために使用する 1
パブリックサブネット NLB を配置し、インターネットと通信する 2
プライベートサブネット Fargate をセキュアに配置する 2
DynamoDB VPC エンドポイント Fargate がプライベートサブネットから DynamoDB にアクセスするために使用する 1
ECS タスクロール Fargate が DynamoDB にアクセスすることを許可する 1
ECS サービスロール トラフィックがコンテナに到達できるように ECS がリソースを管理することを許可する。イメージのプルや、ログの書き出しを許可する。 1
CodeBuild 用 ロール ビルドの実行に必要なアクションを許可する 1
CodePipeline 用 ロール パイプラインの実行に必要なアクションを許可する 1

上記の ECS タスクロールと ECS サービスロールはタスク定義内で以下のように設定されます。

19.png

以下のコマンドで CloudFormation のスタックを作成します。--capabilities CAPABILITY_NAMED_IAM はスタックリソースに IAM ロールが含まれているので必要なオプションです。

カスタム名を持つIAMリソースがある場合は、CAPABILITY_NAMED_IAMを指定する必要があります。

aws cloudformation create-stack --stack-name MythicalMysfitsCoreStack --capabilities CAPABILITY_NAMED_IAM --template-body file://~/environment/aws-modern-application-workshop/module-2/cfn/core.yml

以下のコマンドでスタックの作成状況を確認します。

aws cloudformation describe-stacks --stack-name MythicalMysfitsCoreStack

結果は以下のように返ってきます。StackStatus というキーを確認し、この値が CREATE_COMPLETE になるまでしばらく待ちます。

{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/MythicalMysfitsCoreStack/3a8d94b0-eb6a-11eb-8b9c-0e443e7db6f3", 
            "DriftInformation": {
                "StackDriftStatus": "NOT_CHECKED"
            }, 
            "Description": "This stack deploys the core network infrastructure and IAM resources to be used for a service hosted in Amazon ECS using AWS Fargate.", 
            "Tags": [], 
            "EnableTerminationProtection": false, 
            "CreationTime": "2021-07-23T03:58:24.697Z", 
            "Capabilities": [
                "CAPABILITY_NAMED_IAM"
            ], 
            "StackName": "MythicalMysfitsCoreStack", 
            "NotificationARNs": [], 
            "StackStatus": "CREATE_IN_PROGRESS", 
            "DisableRollback": false, 
            "RollbackConfiguration": {}
        }
    ]
}

コンソール画面からでも作成状況を確認することができます。

image.png

スタックの作成が完了後、今後のアプリケーションインフラ構築を進めやすくするために以下のようにスタックの作成結果をファイルに書き出しておきます。ファイルに書き出した結果は、このスタックで作成したリソースの ARN を参照するために今後何度も使用することになります。

aws cloudformation describe-stacks --stack-name MythicalMysfitsCoreStack > ~/environment/cloudformation-core-output.json

2-2. Docker コンテナの準備

このコンテナで実行されるのは Flask アプリケーションです。以下のコードが実行されます。

  • / にアクセスしたクライアントには 「'/mysfits' にアクセスしてください」というレスポンスを返す
  • /mysfits にアクセスしたクライアントには mysfits たちの名前や年齢などの情報が記載された mysfits-response.json をレスポンスとして返す
/aws-modern-application-workshop/module-2/app/service/mythicalMysfitsService.py
from flask import Flask, jsonify, json, Response, request
from flask_cors import CORS

app = Flask(__name__)
app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False
CORS(app)

@app.route("/")
def healthCheckResponse():
    return jsonify({"message" : "Nothing here, used for health check. Try /mysfits instead."})

@app.route("/mysfits")
def getMysfits():

    response = Response(open("mysfits-response.json", "rb").read())
    response.headers["Content-Type"]= "application/json"

    return response

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8080)

Fargate を開始するためのインフラ構築後、Fargate でコンテナを起動するために、まず Docker イメージを作成します。

cd ~/environment/aws-modern-application-workshop/module-2/app
docker build . -t 123456789012.dkr.ecr.us-east-1.amazonaws.com/mythicalmysfits/service:latest

ビルドが完了すると最後に以下のような出力があります。この ID はイメージの ID です。

Successfully built 4611ce22a1cc
Successfully tagged 123456789012.dkr.ecr.us-east-1.amazonaws.com/mythicalmysfits/service:latest

上記イメージ ID を渡してコンテナをローカルで起動します。

docker run -p 8080:8080 4611ce22a1cc

以下の「Preview Runnig Application」をクリックします。

7.png

URL の最後に「/myfits」を追加し、レスポンスとして JSON ドキュメントが確認できました。

8.png

イメージを ECR リポジトリにプッシュします。以下のようにリポジトリを作成します。その後、ログインします。

aws ecr create-repository --repository-name mythicalmysfits/service
$(aws ecr get-login --no-include-email)
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/mythicalmysfits/service:latest

コンソールでもプッシュされたイメージを確認してみます。

image.png

次に Fargate クラスターを作成します。以下のコマンドでクラスターと CloudWatch Logs のロググループを作成します。

aws ecs create-cluster --cluster-name MythicalMysfits-Cluster
aws logs create-log-group --log-group-name mythicalmysfits-logs

/cloudformation-core-output.json を参照しながら /aws-modern-application-workshop/module-2/aws-cli/task-definition.json を編集します。編集するのは以下3点です。その後、タスク定義を登録します。

  • REPLACE_ME_ECS_SERVICE_ROLE_ARN
  • REPLACE_ME_ECS_TASK_ROLE_ARN
  • REPLACE_ME_IMAGE_TAG_USED_IN_ECR_PUSH
aws ecs register-task-definition --cli-input-json file://~/environment/aws-modern-application-workshop/module-2/aws-cli/task-definition.json

2-3. NLB を作成する

Network Load Balancer を作成します。--subnets オプションには 2 つのパブリックサブネット ID を渡します。この実行結果を nlb-output.json というファイルに書き出しておきます。

aws elbv2 create-load-balancer --name mysfits-nlb --scheme internet-facing --type network --subnets subnet-0ebf9d3a8 subnet-fa7bdfa5 > ~/environment/nlb-output.json

ターゲットグループを作成します。この実行結果は target-group-output.json というファイルに書き出しておきます。

aws elbv2 create-target-group --name MythicalMysfits-TargetGroup --port 8080 --protocol TCP --target-type ip --vpc-id vpc-0ebf9d3a8fakm8fa5 --health-check-interval-seconds 10 --health-check-path / --health-check-protocol HTTP --healthy-threshold-count 3 --unhealthy-threshold-count 3 > ~/environment/target-group-output.json

リスナーを作成します。

aws elbv2 create-listener --default-actions TargetGroupArn=arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/MythicalMysfits-TargetGroup/0249b754ae522df7,Type=forward --load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/net/mysfits-nlb/e7795589l86fc2d7 --port 80 --protocol TCP

2-4. Fargate でタスクを実行する

/aws-modern-application-workshop/module-2/aws-cli/service-definition.json を編集します。以下を置き換えます。

  • REPLACE_ME_SECURITY_GROUP_ID
  • REPLACE_ME_PRIVATE_SUBNET_ONE
  • REPLACE_ME_PRIVATE_SUBNET_TWO
  • REPLACE_ME_NLB_TARGET_GROUP_ARN

以下のコマンドを実行しサービスを作成します。

aws ecs create-service --cli-input-json file://~/environment/aws-modern-application-workshop/module-2/aws-cli/service-definition.json

コンソール画面を確認するとタスクが実行されていることが確認できます。

image.png

ブラウザを開き、http://NLB_DNS_NAME/mysfits にアクセスします。以下の NLB_DNS_NAME を NLB の DNS 名で置き換えます。ただし、http でアクセスします。証明書がないため、 https ではアクセスできません。以前 Cloud9 で Docker を起動したときのレスポンスが返ってきていれば、正常に Fargate が稼働しています。

REPLACE_MEhttp://NLB_DNS_NAME で置き換えます。

/aws-modern-application-workshop/module-2/web/index.html
  <script>

    var mysfitsApiEndpoint = 'REPLACE_ME'; // example: 'http://mythi-publi-abcd12345-01234567890123.elb.us-east-1.amazonaws.com'

    var app = angular.module('mysfitsApp', []);

このエンドポイントは ajax 呼び出しの URL に渡されます。/aws-modern-application-workshop/module-2/web/index.html の該当ソースは以下の通りです。

    function getAllMysfits(callback) {

      var mysfitsApi = mysfitsApiEndpoint + '/mysfits';

      $.ajax({
        url : mysfitsApi,
        type : 'GET',
        success : function(response) {
          callback(response.mysfits);
        },
        error : function(response) {
          console.log("could not retrieve mysfits list.");
          console.log(response.message);
        }
      });

変更を保存した後、バケットにアップロードします。

aws s3 cp ~/environment/aws-modern-application-workshop/module-2/web/index.html s3://mythical-mysfits-python-tutorial-bucket/index.html

2-5. CI/CD 環境を構築する

コードの変更を自動でデプロイするために、CodeCommit、CodeBuild、CodePipeline を使用して CI/CD 環境を構築します。

CodeBuild の出力アーティファクトを格納するバケットを作成します。

aws s3 mb s3://mythical-mysfits-python-tutorial-artifacts-bucket

/aws-modern-application-workshop/module-2/aws-cli/artifacts-bucket-policy.json を編集します。以下を置き換えます。その後バケットポリシーを設定するコマンドを実行します。

  • REPLACE_ME_CODEBUILD_ROLE_ARN
  • REPLACE_ME_CODEPIPELINE_ROLE_ARN
aws s3api put-bucket-policy --bucket mythical-mysfits-python-tutorial-artifacts-bucket --policy file://~/environment/aws-modern-application-workshop/module-2/aws-cli/artifacts-bucket-policy.json

CodeCommit にリポジトリを作成します。

aws codecommit create-repository --repository-name MythicalMysfitsService-Repository

ビルドプロジェクトを作成するために /aws-modern-application-workshop/module-2/aws-cli/code-build-project.json を編集します。以下を置き換えます。

  • REPLACE_ME_ACCOUNT_ID
  • REPLACE_ME_REGION
  • REPLACE_ME_CODEBUILD_ROLE_ARN
aws codebuild create-project --cli-input-json file://~/environment/aws-modern-application-workshop/module-2/aws-cli/code-build-project.json

パイプラインを作成するために /aws-modern-application-workshop/module-2/aws-cli/code-pipeline.json を編集します。以下を置き換えます。

  • REPLACE_ME_CODEPIPELINE_ROLE_ARN
  • REPLACE_ME_ARTIFACTS_BUCKET_NAME
aws codepipeline create-pipeline --cli-input-json file://~/environment/aws-modern-application-workshop/module-2/aws-cli/code-pipeline.json

ECR のリポジトリポリシーを設定します。以下を置き換えます。

  • REPLACE_ME_CODEBUILD_ROLE_ARN
aws ecr set-repository-policy --repository-name mythicalmysfits/service --policy-text file://~/environment/aws-modern-application-workshop/module-2/aws-cli/ecr-policy.json

コンソール画面ではリポジトリポリシーを確認できなかったので、CLI で確認してみました。以下のコマンドで確認できます。

aws ecr get-repository-policy --repository-name mythicalmysfits/service

CodeCommit のリポジトリをクローンし、ローカルリポジトリを作成します。

git clone https://git-codecommit.us-east-1.amazonaws.com/v1/repos/MythicalMysfitsService-Repository

CodeCommit のローカルリポジトリにアプリケーションコードをコピーします。

cp -r ~/environment/aws-modern-application-workshop/module-2/app/* ~/environment/MythicalMysfitsService-Repository/

パイプラインが正常に機能しているかをチェックするために Evangeline の年齢を変更します。

"species": "Chimera",
"age": 999,

変更を CodeCommit リポジトリにプッシュします。

git add .
git commit -m "I changed the age of one of the mysfits."
git push

以下はプッシュ後のリポジトリです。

image.png

コンソール画面でパイプラインが実行されていることを確認してみます。

image.png

コンソール画面では以下のようにビルドが実行中です。

image.png

パイプラインの実行完了後、ウェブサイトを更新し、Evangeline の年齢が変更した値に更新されていることが確認できました。

image.png

3. MYSFIT データの保存

この章では mysfit を JSON ファイルにで管理するのではなく、データベースに保存する設定を行います。データベースには DynamoDB を利用します。

3-1. テーブルを作成し、アイテムを追加する

テーブルを作成しアイテムを追加します。

aws dynamodb create-table --cli-input-json file://~/environment/aws-modern-application-workshop/module-3/aws-cli/dynamodb-table.json
aws dynamodb batch-write-item --request-items file://~/environment/aws-modern-application-workshop/module-3/aws-cli/populate-dynamodb.json

コンソール画面で確認してみます。

image.png

3-2. DynamoDB を参照するようにコードを編集する

Flask アプリケーションで DynamoDB からデータを取得するために /aws-modern-application-workshop/module-3/app/service/mythicalMysfitsService.py を用います。このモジュールは boto3 という SDK を使用して DynamoDB からデータを取得します。例えば、以下のコードはテーブルに登録されている全データを取得します。

/aws-modern-application-workshop/module-3/app/service/mythicalMysfitsService.py
import boto3

...
...
def getAllMysfits():
    response = client.scan(
        TableName='MysfitsTable'
    )

リポジトリに変更を加え、プッシュします。

cp ~/environment/aws-modern-application-workshop/module-3/app/service/* ~/environment/MythicalMysfitsService-Repository/service/
cd ~/environment/MythicalMysfitsService-Repository
git add .
git commit -m "Add new integration to DynamoDB."
git push

ビルドに失敗しました。

image.png

「詳細」をクリックして CodeBuild のビルドログを確認します。

[Container] 2021/07/23 08:24:48 Running command docker build -t mythicalmysfits/service:latest .
Sending build context to Docker daemon  19.97kB

Step 1/13 : FROM ubuntu:latest
latest: Pulling from library/ubuntu
toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limit

[Container] 2021/07/23 08:24:49 Command did not exit successfully docker build -t mythicalmysfits/service:latest . exit status 1

公式ドキュメントに以下の記述があります。

プルリクエストを発行し、アカウントタイプの制限を超えた429場合、マニフェストがリクエストされると、DockerHubは次の本文のレスポンスコードを返します。

You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limits

チュートリアルに記載のあった Git 認証を飛ばしていたので、匿名ユーザーに対してレート制限が適用されたようです。Git 認証を追加し再度プッシュします。

git config --global user.name "xxxx"
git config --global user.email yyyy@example.com
git config --global credential.helper '!aws codecommit credential-helper $@'
git config --global credential.UseHttpPath true

なお、認証情報は以下のローカルファイルに保存されます。

~/.gitconfig
[credential]
        helper = !aws codecommit credential-helper $@
        UseHttpPath = true
[core]
        editor = nano
[user]
        name = xxxx
        email = yyyy@example.com

プッシュします。

git add .
git commit -m "set git config.I retry PiPeline execution"
git push

正常にビルドが完了しました。

image.png

4. ユーザーの登録

Cognito を使用してユーザー管理を行います。Cognito のユーザープール・アプリクライアントを設定して認証されていないクライアントがサインアップ・サインインできるように実装します。

まずユーザープールを作成します。ユーザープールとはユーザーディレクトリのことです。

aws cognito-idp create-user-pool --pool-name MysfitsUserPool --auto-verified-attributes email

上記で作成したユーザープール ID を使用してアプリクライアントを作成します。

aws cognito-idp create-user-pool-client --user-pool-id us-east-1_BaCZvuQrU --client-name MysfitsUserPoolClient

ユーザープール ID と アプリクライアント ID は、JavaScript for SDK によって処理されます。以下は該当ソースになります。

/aws-modern-application-workshop/module-4/web/register.html
  <script>
  var cognitoUserPoolId = 'REPLACE_ME';  // example: 'us-east-1_abcd12345'
  var cognitoUserPoolClientId = 'REPLACE_ME'; // example: 'abcd12345abcd12345abcd12345'
...
...
    var poolData = {
      UserPoolId : cognitoUserPoolId,
      ClientId : cognitoUserPoolClientId
    };

    var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
...
...
      userPool.signUp(email, pw, attributeList, null, function(err, result){
          if (err) {
              alert(err.message);
              return;
          }
          cognitoUser = result.user;
          console.log(cognitoUser);
          localStorage.setItem('email', email);
          window.location.replace('confirm.html');
      });

上記のコードでの最後に window.location.replace('confirm.html'); とあります。こちらは登録したメールアドレスに送信される認証コードを確認するためのページです。認証コードはサインアップ後、 Cognito から送信されます。認証コードを Cognito に送信してユーザー登録を完了させるための該当ソースは以下の通りです。

/aws-modern-application-workshop/module-4/web/confirm.html
  <script>

  var cognitoUserPoolId = 'REPLACE_ME';  // example: 'us-east-1_abcd12345'
  var cognitoUserPoolClientId = 'REPLACE_ME'; // example: 'abcd12345abcd12345abcd12345'
...
...
    var confirmCode = document.getElementById('confirmCode').value;

    var poolData = {
      UserPoolId : cognitoUserPoolId,
      ClientId : cognitoUserPoolClientId
    };

    var userName = localStorage.getItem('email');

    var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
    var userData = {
        Username : userName,
        Pool : userPool
    };

    var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
    cognitoUser.confirmRegistration(confirmCode, true, function(err, result) {
        if (err) {
            alert(err.message);
            return;
        }
        window.location.replace("index.html");
    });

ここからは Cognito によるオーソライザーを使用して、登録されたユーザーのみが特定の機能を使用できるようにします。そのためにはAPI Gateway を NLB に統合する必要があります。

VPC リンクを使用すると、Application Load Balancer または Amazon ECS コンテナベースのアプリケーションなどの、HTTP API ルートを VPC 内のプライベートリソースに接続するプライベート統合を作成できます。

ただし、このチュートリアルでは NLB がパブリックであり、プライベートリソースではありません。この点について、以下の注意書きがあります。

実際の環境では、API Gateway がインターネット接続した API 承認向けの戦略であることがわかっているため、最初から内部用に NLB を作成する必要があります (または、新しい内部ロードバランサーを作成して、既存のものと置き換える必要があります)。ただし、時間を節約するため、既に作成した NLB をパブリックにアクセスできる状態のまま使用します。

以下のコマンドを実行し、VPC リンクを作成します。

aws apigateway create-vpc-link --name MysfitsApiVpcLink --target-arns arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/net/mysfits-nlb/e7795560f86fc2d7 > ~/environment/api-gateway-link-output.json

REST API を作成します。/aws-modern-application-workshop/module-4/aws-cli/api-swagger.json の REPLACE_ME の箇所を置き換えます。その後以下のコマンドを実行します。

aws apigateway import-rest-api --parameters endpointConfigurationTypes=REGIONAL --body file://~/environment/aws-modern-application-workshop/module-4/aws-cli/api-swagger.json --fail-on-warnings

コンソール画面で作成された REST API を確認してみます。

image.png

上図のスクリーンショットが良くなかったのですが、「認可」の部分が「なし」になっています。これは、/ にはオーソライザーが設定されていないからです。オーソライザーが設定されているのは /mysfits/{mysfitId}/like/mysfits/{mysfitId}/adopt です。該当ソースは以下の通りです。

/aws-modern-application-workshop/module-4/aws-cli/api-swagger.json
"/mysfits/{mysfitId}/like": {
  "post": {
      "parameters": [{
          "name": "mysfitId",
          "in": "path",
          "required": true,
          "type": "string"
      }],
      "responses": {
          "200": {
              "description": "Default response for CORS method",
              "headers": {
                  "Access-Control-Allow-Headers": {
                      "type": "string"
                  },
                  "Access-Control-Allow-Methods": {
                      "type": "string"
                  },
                  "Access-Control-Allow-Origin": {
                      "type": "string"
                  }
              }
          }
      },
      "security": [{
          "MysfitsUserPoolAuthorizer": [

          ]
      }],

なお、オーソライザーオブジェクトの設定方法のドキュメントは以下になります。

続いて API をデプロイします。

aws apigateway create-deployment --rest-api-id hnypyxgqve --stage-name prod

バックエンドを更新し、プッシュします。

cd ~/environment/MythicalMysfitsService-Repository/
cp -r ~/environment/aws-modern-application-workshop/module-4/app/* .
git add .
git commit -m "Update service code backend to enable additional website features."
git push

S3 バケットのオブジェクトも更新します。以下 3 ファイルの REPLACE_ME を置き換えます。

/aws-modern-application-workshop/module-4/web/index.html
<script>
    var mysfitsApiEndpoint = 'REPLACE_ME'; // example: 'https://abcd12345.execute-api.us-east-1.amazonaws.com/prod'
    var cognitoUserPoolId = 'REPLACE_ME';  // example: 'us-east-1_abcd12345'
    var cognitoUserPoolClientId = 'REPLACE_ME'; // example: 'abcd12345abcd12345abcd12345'
    var awsRegion = 'REPLACE_ME'; // example: 'us-east-1' or 'eu-west-1' etc.
/aws-modern-application-workshop/module-4/web/register.html
<script>
  var cognitoUserPoolId = 'REPLACE_ME';  // example: 'us-east-1_abcd12345'
  var cognitoUserPoolClientId = 'REPLACE_ME'; // example: 'abcd12345abcd12345abcd12345'
/aws-modern-application-workshop/module-4/web/confirm.html
<script>
  var cognitoUserPoolId = 'REPLACE_ME';  // example: 'us-east-1_abcd12345'
  var cognitoUserPoolClientId = 'REPLACE_ME'; // example: 'abcd12345abcd12345abcd12345'

その後 S3 バケットにアップロードします。

aws s3 cp --recursive ~/environment/aws-modern-application-workshop/module-4/web/ s3://mythical-mysfits-python-tutorial-bucket/

ウェブサイトを更新すると以下のようにログイン機能が実装されていることが確認できます。

10.png

サインアップができることを確認し、ユーザープールに登録されていることが確認できました。

11.png

5. ユーザークリックの把握

ストリーミング処理をするコードを格納するために、新たに CodeCommit にリポジトリを作成します。

aws codecommit create-repository --repository-name MythicalMysfitsStreamingService-Repository

Lambda 関数のコードを S3 にアップロードするために新たにバケットを作成します。

aws s3 mb s3://mythical-mysfits-python-tutorial-lambda-package-bucket

Kinesis Firehose から送信されるレコードを Lambda 関数は適切なフォーマットに変換します。該当ソースは以下の通りです。

/aws-modern-application-workshop/module-5/app/streaming/streamProcessor.py
def processRecord(event, context):
    output = []

    for record in event['records']:
        print('Processing record: ' + record['recordId'])
        click = json.loads(base64.b64decode(record['data']))

        mysfitId = click['mysfitId']
        mysfit = retrieveMysfit(mysfitId)

        enrichedClick = {
                'userId': click['userId'],
                'mysfitId': mysfitId,
                'goodevil': mysfit['goodevil'],
                'lawchaos': mysfit['lawchaos'],
                'species': mysfit['species']
            }

        output_record = {
            'recordId': record['recordId'],
            'result': 'Ok',
            'data': base64.b64encode(json.dumps(enrichedClick).encode('utf-8') + b'\n').decode('utf-8')
        }
        output.append(output_record)

    print('Successfully processed {} records.'.format(len(event['records'])))

    return {'records': output}

SAM CLI を利用して CloudFormation テンプレートを作成します。real-time-streaming.yml が transformed-streaming.yml に変換されます。

sam package --template-file ./real-time-streaming.yml --output-template-file ./transformed-streaming.yml --s3-bucket mythical-mysfits-python-tutorial-lambda-package-bucket

SAM によって変換された CloudFormation のテンプレートを使用してスタックを作成します。

aws cloudformation deploy --template-file /home/ec2-user/environment/MythicalMysfitsStreamingService-Repository/transformed-streaming.yml --stack-name MythicalMysfitsStreamingStack --capabilities CAPABILITY_IAM

このスタックによって作成されるリソースは以下の通りです。

リソース 用途
API Gateway Kinesis Firehose と統合するREST API
S3 バケット Kinesis のログを格納する
FirehoseDeliveryRole Lambda、S3 へのアクションを許可する
Lambda Kinesis Firehose のレコードを変換する
Kinesis Firehose クリックデータを受信し Lambda、S3 に送信する

ストリーム用のエンドポイントを追加した新しい index.html を S3 バケットにアップロードします。以下の REPLACE_ME を置き換えます。

/aws-modern-application-workshop/module-5/web/index.html
  <script>

    var mysfitsApiEndpoint = 'REPLACE_ME'; // example: 'https://abcd12345.execute-api.us-east-1.amazonaws.com/prod'
    var streamingApiEndpoint = 'REPLACE_ME'; // example: 'https://abcd12345.execute-api.us-east-1.amazonaws.com/prod'

    var cognitoUserPoolId = 'REPLACE_ME';  // example: 'us-east-1_abcd12345'
    var cognitoUserPoolClientId = 'REPLACE_ME'; // example: 'abcd12345abcd12345abcd12345'
    var awsRegion = 'REPLACE_ME'; // example: 'us-east-1' or 'eu-west-1' etc.

以下のコマンドで編集した index.html をアップロードします。

aws s3 cp ~/environment/aws-modern-application-workshop/module-5/web/index.html s3://mythical-mysfits-python-tutorial-bucket/

S3 バケットに送信された、変換されたクリックイベントのストリーミングデータファイルをダウンロードして確認してみます。

{"userId": "7c25e02a-05fe-4fcc-8569-6e8688933805", "mysfitId": "a901bb08-1985-42f5-bb77-27439ac14300", "goodevil": "Good", "lawchaos": "Neutral", "species": "Haetae"}
{"userId": "7c25e02a-05fe-4fcc-8569-6e8688933805", "mysfitId": "a901bb08-1985-42f5-bb77-27439ac14300", "goodevil": "Good", "lawchaos": "Neutral", "species": "Haetae"}
{"userId": "7c25e02a-05fe-4fcc-8569-6e8688933805", "mysfitId": "b6d16e02-6aeb-413c-b457-321151bb403d", "goodevil": "Evil", "lawchaos": "Chaotic", "species": "Troll"}
{"userId": "7c25e02a-05fe-4fcc-8569-6e8688933805", "mysfitId": "a901bb08-1985-42f5-bb77-27439ac14300", "goodevil": "Good", "lawchaos": "Neutral", "species": "Haetae"}

上記の処理を行った Lambda が出力したログを CloudWatch Logs で確認してみます。

START RequestId: ba9b88c5-a552-4c6e-8df6-9ccb2ba2b10e Version: $LATEST
Processing record: 49620403830958916807586905640547610254069909630134255618000000
Processing record: 49620403830958916807586905640568161993003359356896411650000000
Processing record: 49620403830958916807586905640572997696281818079753666562000000
Processing record: 49620403830958916807586905640602011915952570485616672770000000
Successfully processed 4 records.
END RequestId: ba9b88c5-a552-4c6e-8df6-9ccb2ba2b10e
REPORT RequestId: ba9b88c5-a552-4c6e-8df6-9ccb2ba2b10e	Duration: 653.45 ms	Billed Duration: 654 ms	Memory Size: 128 MB	Max Memory Used: 53 MB	

正常にレコードが処理されていることが確認できました。

以上でチュートリアルは終了です。

参考記事

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?