初めに
以下のチュートリアルをやってみました。このチュートリアルでは S3 を利用した静的ウェブサイトを Fargate や Network Load Balancer、API Gateway 利用して動的ウェブサイトにする過程を学ぶことができました。さらに CI/CD 環境の構築、クリックイベントに対するストリーミング処理の方法も学ぶことができます。このチュートリアルではほとんど CLI、時折 CloudFormation を使用してアプリケーションを構築していきます。
1. 静的 Web サイトの作成
開発環境として Cloud9 を用います。リージョンは us-east-1 を選択しました。以下の手順で開発環境を作成します。
開発環境の名前を入力します。
すべてデフォルトのまま進めます。
「Next step」をクリックします。
「Create environment」をクリックします。
チュートリアルに使用するコードをクローンし、そのルートディレクトリに移動します。
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 コンソール画面 → 設定したいバケット名を選択 → プロパティ → 静的ウェブサイトホスティング」 の手順で設定できます。
/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
を作成したバケット名で置き換えます。このチュートリアルではこのような置き換えが何度も出てきます。チュートリアル通りに進めているのにエラーが発生した場合は、この置き換えがされていないことが原因かもしれません。以下はバケット名を置き換えた後のポリシーです。
{
"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 コンソール画面で確認し、設定が反映されていることが確認してみます。
/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 サービスロールはタスク定義内で以下のように設定されます。
以下のコマンドで 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": {}
}
]
}
コンソール画面からでも作成状況を確認することができます。
スタックの作成が完了後、今後のアプリケーションインフラ構築を進めやすくするために以下のようにスタックの作成結果をファイルに書き出しておきます。ファイルに書き出した結果は、このスタックで作成したリソースの ARN を参照するために今後何度も使用することになります。
aws cloudformation describe-stacks --stack-name MythicalMysfitsCoreStack > ~/environment/cloudformation-core-output.json
2-2. Docker コンテナの準備
このコンテナで実行されるのは Flask アプリケーションです。以下のコードが実行されます。
-
/
にアクセスしたクライアントには 「'/mysfits' にアクセスしてください」というレスポンスを返す -
/mysfits
にアクセスしたクライアントには mysfits たちの名前や年齢などの情報が記載されたmysfits-response.json
をレスポンスとして返す
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」をクリックします。
URL の最後に「/myfits」を追加し、レスポンスとして JSON ドキュメントが確認できました。
イメージを 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
コンソールでもプッシュされたイメージを確認してみます。
次に 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
コンソール画面を確認するとタスクが実行されていることが確認できます。
ブラウザを開き、http://NLB_DNS_NAME/mysfits にアクセスします。以下の NLB_DNS_NAME
を NLB の DNS 名で置き換えます。ただし、http でアクセスします。証明書がないため、 https ではアクセスできません。以前 Cloud9 で Docker を起動したときのレスポンスが返ってきていれば、正常に Fargate が稼働しています。
REPLACE_ME
を http://NLB_DNS_NAME
で置き換えます。
<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
以下はプッシュ後のリポジトリです。
コンソール画面でパイプラインが実行されていることを確認してみます。
コンソール画面では以下のようにビルドが実行中です。
パイプラインの実行完了後、ウェブサイトを更新し、Evangeline の年齢が変更した値に更新されていることが確認できました。
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
コンソール画面で確認してみます。
3-2. DynamoDB を参照するようにコードを編集する
Flask アプリケーションで DynamoDB からデータを取得するために /aws-modern-application-workshop/module-3/app/service/mythicalMysfitsService.py を用います。このモジュールは boto3 という SDK を使用して DynamoDB からデータを取得します。例えば、以下のコードはテーブルに登録されている全データを取得します。
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
ビルドに失敗しました。
「詳細」をクリックして 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
なお、認証情報は以下のローカルファイルに保存されます。
[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
正常にビルドが完了しました。
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 によって処理されます。以下は該当ソースになります。
<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 に送信してユーザー登録を完了させるための該当ソースは以下の通りです。
<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 を確認してみます。
上図のスクリーンショットが良くなかったのですが、「認可」の部分が「なし」になっています。これは、/
にはオーソライザーが設定されていないからです。オーソライザーが設定されているのは /mysfits/{mysfitId}/like
と /mysfits/{mysfitId}/adopt
です。該当ソースは以下の通りです。
"/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
を置き換えます。
<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.
<script>
var cognitoUserPoolId = 'REPLACE_ME'; // example: 'us-east-1_abcd12345'
var cognitoUserPoolClientId = 'REPLACE_ME'; // example: 'abcd12345abcd12345abcd12345'
<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/
ウェブサイトを更新すると以下のようにログイン機能が実装されていることが確認できます。
サインアップができることを確認し、ユーザープールに登録されていることが確認できました。
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 関数は適切なフォーマットに変換します。該当ソースは以下の通りです。
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
を置き換えます。
<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
正常にレコードが処理されていることが確認できました。
以上でチュートリアルは終了です。
参考記事