はじめに
AWS認定試験の勉強している時にサーバレスアーキテクチャに関する問題がたくさん出てきました。
なので復習もかねて、今回はAWS Hands-on for Beginners Serverless #1を参考に、サーバレスアーキテクチャを実際に構築していきたいと思います。
学習するサービス
- AWS Lambda
- Amazon API Gateway
- Amazon DynamoDB
- Amazon Translate
AWS Hands-on for Beginners Serverless #1の概要
このハンズオンでは、"こんにちは" と入力すると "Hello" と返すWebAPIを作成します。
構築する構成図は以下になります。
引用:AWS Hands-on for Beginners Serverless #1
作成するWebAPIリクエストの流れ
- API Gatewayがリクエストを受け取けつけるとLambdaを呼び出す。
- LambdaはTranslateを呼び出し翻訳結果を取得する。
- 翻訳結果をAPIGatewayに返しAPIレスポンスを返す。
- リクエストのinput、outputの履歴をDynamoDBに保存する。
このハンズオンは以下の構成になっております。
Session | 分:秒 | |
---|---|---|
1 | Serverless アーキテクチャの概要 | 09:54 |
2 | AWS Lambda の概要 | 06:40 |
3 | AWS Lambda ハンズオン① Lambda を単体で使ってみる | 10:14 |
4 | AWS Lambda ハンズオン② 他のサービスを呼び出してみる | 07:41 |
5 | Amazon API Gateway の概要 | 08:12 |
6 | Amazon API Gateway ハンズオン① API Gateway を単体で使ってみる | 06:14 |
7 | Amazon API Gateway ハンズオン② API Gateway と Lambda を組み合わせる | 10:20 |
8 | Amazon DynamoDB の概要 | 07:44 |
9 | Amazon DynamoDB ハンズオン①テーブルを作ってみる | 04:41 |
10 | Amaozn DynamoDB ハンズオン② API Gateway と Lambda と DynamoDB を組み合わせる | 08:03 |
座学動画についてはこの記事では触れませんが、とても分かりやすいと思うので
気になった方はぜひAWS Hands-on for Beginners Serverless #1をご覧ください。
AWS Hands-on for Beginnersとは
AWS Hands-on for Beginnersとは、動画を見ながら実際にサービスを触って学習できるAWS公式提供の動画形式コンテンツです。
ハンズオン実践
細かいやり方や設定については省略させていただきます。
詳細については、ハンズオン動画をご覧いただければと思います。
3. AWS Lambda ハンズオン① Lambda を単体で使ってみる
イベントの中身をログとして出力できるLambda関数を実装します。
1. Lambda関数「translate-function」を作成する。
2. イベント「Test」を作成し、テストを実行する。
3. イベントの中身をログとして出力するように、「translate-function」を実装する。
4. CloudWatchでログを確認し、きちんと出力されているか確認する。
以下のように実装しました。
import json
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
logger.info(event)
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
以下のテストイベントを実行します。
{
"key1": "value1",
"key2": "value2",
"key3": "value3"
}
無事にイベントの中身をログとして出力できています。
START RequestId: b0a4fea6-e5dd-4fcc-9538-d576e1fcafd4 Version: $LATEST
[INFO] 2023-08-05T04:27:26.667Z b0a4fea6-e5dd-4fcc-9538-d576e1fcafd4 {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
END RequestId: b0a4fea6-e5dd-4fcc-9538-d576e1fcafd4
REPORT RequestId: b0a4fea6-e5dd-4fcc-9538-d576e1fcafd4 Duration: 2.08 ms Billed Duration: 3 ms Memory Size: 128 MB Max Memory Used: 36 MB Init Duration: 118.60 ms
CloudWatchでも、テストイベントの中身をログとして出力できました。
2023-08-05T13:27:26.544+09:00 INIT_START Runtime Version: python:3.7.v30 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:898e3ea3957b56a1999758f7a44db46ffe42dc979b385666bf4950b8611ec475
2023-08-05T13:27:26.667+09:00 START RequestId: b0a4fea6-e5dd-4fcc-9538-d576e1fcafd4 Version: $LATEST
2023-08-05T13:27:26.668+09:00 [INFO] 2023-08-05T04:27:26.667Z b0a4fea6-e5dd-4fcc-9538-d576e1fcafd4 {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
2023-08-05T13:27:26.670+09:00 END RequestId: b0a4fea6-e5dd-4fcc-9538-d576e1fcafd4
2023-08-05T13:27:26.670+09:00 REPORT RequestId: b0a4fea6-e5dd-4fcc-9538-d576e1fcafd4 Duration: 2.08 ms Billed Duration: 3 ms Memory Size: 128 MB Max Memory Used: 36 MB Init Duration: 118.60 ms
4. AWS Lambda ハンズオン② 他のサービスを呼び出してみる
Translateを呼び出す、Lambda関数を実装します。
1. Translateを呼び出せるようにLambda関数「translate-function」を実装する。
2. LambdaにアタッチされているIAMロールにポリシー「TranslateFullAccess」を追加する。
3. 正しく動作するか確認するため、テストを実行する。
以下のように実装しました。
import json
import boto3
translate = boto3.client('translate')
def lambda_handler(event, context):
input_text = 'おはよう'
response = translate.translate_text(
Text=input_text,
SourceLanguageCode='ja',
TargetLanguageCode='en',
)
output_text = response.get('TranslatedText')
return {
'statusCode': 200,
'body': json.dumps({
'output_text': output_text
})
}
続いて、Lambda関数がTranslateにアクセスできるようIAMロールにポリシーを追加していきます。
検索バーで「Translate」と検索します。
「TranslateFullAccess」を選択して「許可を追加」をクリックします。
6. Amazon API Gateway ハンズオン① API Gateway を単体で使ってみる
このセクションではまだLambda関数との連携は行いません。
Mockデータを返すAPIを作成します。
- 「translate-api」として、APIを作成する。
- 「sample」として、リソースを作成する。
- 統合タイプを「Mock」としてGETメソッドを作成する。
- GETメソッドのテストを行う。
- 新しく作成したステージ「dev」にAPIのデプロイを行う。
- デプロイしたAPIをURLで呼び出す。
統合レスポンスのマッピングテンプレート「application/json」を作成します。
{
"StatusCode": 200,
"body": {
{
"report_id": 5,
"report_title": "Hello, World"
},
{
"report_id": 7,
"report_title": "こんにちは"
}
}
}
7. Amazon API Gateway ハンズオン② API Gateway と Lambda を組み合わせる
API GatewayとLambdaを連携して、入力した日本語を英語に翻訳するAPIを作成します。
- すでに作成済みのAPI「translate-api」で「translate」リソースを作成する。
- 統合タイプを「Lambda関数」とし、作成済みのLambda関数「translate-function」を選択してGETメソッドを作成する。
- GETメソッドのメソッドリクエストで、URL クエリ文字列パラメータ「input_text」を追加する。
- APIGatewayのルールに従ってレスポンスを返すようにLambda関数「translate-function」を修正する。
- イベントテンプレート「Amazon API Gateway AWS Proxy」を修正し、イベント「APICall」を作成する。
- クエリパラメータの文字列を受け取れるように「translate-function」を修正する。
7.GETメソッドのURLの呼び出しでクエリパラメータを「こんばんは」としてAPIを叩いてみる。
以下のように実装しました。
import json
import boto3
translate = boto3.client('translate')
def lambda_handler(event, context):
input_text = event['queryStringParameters']['input_text']
response = translate.translate_text(
Text=input_text,
SourceLanguageCode='ja',
TargetLanguageCode='en',
)
output_text = response.get('TranslatedText')
return {
'statusCode': 200,
'body': json.dumps({
'output_text': output_text
}),
'isBase64Encoded': False,
'headers': {}
}
クエリパラメータ(input_text)として「こんにちは」を渡すテスト「APICall」を実行します。
翻訳結果として「Hi」が無事に返ってきました。
また、今回レスポンスとして追加した「isBase64Encoded」と「headers」も無事に確認できました。
{
"statusCode": 200,
"body": "{\"output_text\": \"Hi\"}",
"isBase64Encoded": false,
"headers": {}
}
ブラウザでのURL呼び出しを行います。クエリパラメータとして「こんばんは」をURLに入力します。
無事にレスポンスが返ってきました。※GETメソッドを作成するとき、「Lambdaプロキシ統合の使用」にチェックしていないとここで、エラーが発生します。
{"output_text": "Good evening"}
9. Amazon DynamoDB ハンズオン①テーブルを作ってみる
DynamoDBのテーブルを作っていきます。
- 「translate-history」テーブルを作成する。
- 手動で項目を作成する。
「timestamp」をパーティションキーとした「translate-history」テーブルを作成しました。
また、項目を作成しました。
10. Amaozn DynamoDB ハンズオン② API Gateway と Lambda と DynamoDB を組み合わせる
翻訳履歴をDynamoDBにPUTするよう、Lambda関数を実装していきます。
- 翻訳APIを叩くたびに、「timestamp」、「input_text」、「output_text」をDynamoDBにPUTするようLambda関数を修正する。
- Lambda関数にアタッチされているIAMロールにポリシー「AmazonDynamoDBFullAccess」をアタッチする。
- 作成済みのテスト「APICall」を実行し、実際にDynamoDBにPUTできているか確認する。
- GETメソッドのURLの呼び出しでURLにアクセスし、APIを叩いてDynamoDBにPUTできているか確認する。
以下のように実装しました。
import json
import boto3
import datetime
translate = boto3.client('translate')
dynamodb_translate_history_tbl = boto3.resource('dynamodb').Table('translate-history')
def lambda_handler(event, context):
input_text = event['queryStringParameters']['input_text']
response = translate.translate_text(
Text=input_text,
SourceLanguageCode="ja",
TargetLanguageCode="en"
)
output_text = response.get('TranslatedText')
dynamodb_translate_history_tbl.put_item(
Item = {
'timestamp': datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
'input_text': input_text,
'output_text': output_text
}
)
return {
'statusCode': 200,
'body': json.dumps({
'output_text': output_text
}),
'isBase64Encoded': False,
'headers': {}
}
クエリパラメータ(input_text)として「こんにちは」を渡すテスト「APICall」を実行します。
無事に「translate-history」テーブルにputされています。
続いて、ブラウザでのURL呼び出しを行います。クエリパラメータとして「ハンズオン完走しました」をURLに入力します。
無事に、レスポンスが返ってきました。
こちらも、無事に「translate-history」テーブルにputされています。
落ち穂拾い
- AWS Lambdaで、コンテナが再利用されるとグローバルスコープ(ハンドラ外)に記述されている部分はウォームスタートになり、ローカルスコープ(ハンドラ内)に記述されている部分は再利用されない。
- 今後どのようにサーバーレスを学んでいくかのラーニングパスの紹介
まとめ
無事にハンズオン完走することができました。
ハンズオンでの学習はアウトプットとして、とてもためになると感じたので、気になるサービス・学びたいサービスがあれば積極的に触ってみて学習していきたいと思います。