本記事の概要
AWS Lambda、Amazon API Gateway、Amazon DynamoDB のうち、DynamoDB及びAWS Lambdaについて概要を理解したい思いから記事にしました。
参考サイト:
作成する構成
API Gatewayがリクエストを受け付け、Lambdaを呼出し、Lambdaが翻訳機能であるTranslateを呼出してAPI GatewayからResponseを返します。最後にヒストリーテーブルとしてDynamoDBに保存します。
ハンズオン開始
まずLambdaについて公式のコメントを確認しましょう。
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/welcome.html
AWS Lambda はサーバーのプロビジョニングや管理をする必要がなく、コードを実行できるコンピューティングサービスです。
私なりのまとめですが、ミドルウェアの準備なく、小規模システムをコードで実現できるもの。と理解して進めます。
Lambdaを単体で使用してみる。
Lambda Function作成(デフォルトから設定を変更したりします。)
「関数の作成」から、「設計図の使用」を選択すると、設計図(ブループリント)を利用することができる。S3を呼び出す際にPythonを使用する等の指定ができる。
- 「一から作成」を選択
- 関数名「translate-function(任意)」
- ランタイムは「Python」を選択
- デフォルトの実行ロールは、「基本的な Lambda アクセス権限で新しいロールを作成」を選択
- オプションを参考に貼ります。
- このまま関数を作成します。
現時点で呼出可能なサービスが表示されます。
送信先を追加から、送信先の設定を確認してみます。
同じようにトリガーを確認してみます。
多様なサービスとの連携可能なことが確認できます。
-
設定タブからメモリを変更し、256MBに設定。
ここにあるEphemeralStorageとは、私の解釈ですがRAMに似た機能であり、無料でキャッシュを一時的に保存してくれます。これはインスタンスが動作している間のみ機能する。S3やEBSに保存することも可能。Linux システムの /tmpディレクトリと目的は同じようです。 -
タイムアウトをデフォルトの3秒から10秒に変更してみます。
-
「保存」をクリックし、「テスト」実行を行います。
イベント名を「test1(任意)」と名付けています。
テンプレートのオプション設定や、共有が可能です。
このまま「テスト」をクリックします。
Helloが表記されており、問題なく実行できたようです。
ステータスコード:200です。
CloudWatch logsにてログを確認することができます。
- ソースコードを編集していきます。
Pythonを使用している場合のドキュメントを確認していきます。
Python の AWS Lambda 関数ログ作成:
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/python-logging.html
loggingモジュールを使用して詳しくログを確認していきます。
import logging
logger = logging.getLogger()
logger.setLevel("INFO")
loggerをインポートしてlogger変数にINFOレベルのログを格納します。
ここでちょこっとCCNAの復習です。
CRITICAL
ERROR
WARNING
INFO(今回はココです。)
DEBUG
赤枠にペーストします。
続けて、loggingモジュールを実行する上で不足がありますので、次のコードを関数に追加します。
logger.info(event)
赤枠の箇所です。
5. 「test」をクリックします。
するとFunction logsが出ています。
Lambdaを動かす前にIAMロールにポリシーを追加する。
Traslateへのアクセスを可能にするため、IAMを設定していきます。
「設定」タブから「アクセス権限」をクリックします。
そして、「ロール名」をクリックしてIAMに遷移します。
「許可を追加」をクリックし、「ポリシーをアタッチ」します。
検索窓から「Translate」と検索し、「TranslateReadOnly」を選択します。
これで許可を追加完了です。
LambdaでAmazon Translateを呼出していく。
ここのサイトには、Lambdaで使用できるPythonコードがサービス毎に綺麗に分けられています。
「traslate」と検索窓に入力して検索します。このサイトを開いたまま、次に進みます。
前準備として
1.loggingに関するコードを消します。
2.リソースを操作するためのライブラリを追加します。
import boto3
client = boto3.client('translate')
3.更に、次の構文を追加して、日本語から英語へ翻訳する。といった構文を完成させます。
response = client.translate_text(
Text='おやすみなさいませご主人様',
#ここで特定の言語グループを指定することができます。
#TerminologyNames=[
#'string',
#],
#日本語から、英語へ翻訳します。
SourceLanguageCode='ja',
TargetLanguageCode='en',
#ここで言葉遣い、不適切な表現、端的に翻訳するか否かを決めることができます。
Settings={
'Formality': 'INFORMAL',
'Profanity': 'MASK',
'Brevity': 'ON'
}
)
4.出力させるために以下のようにjson形式コードを編集します。
output = response.get('TranslatedText')
# TODO implement
return {
'statusCode': 200,
'body': json.dumps({
'output' = output
})
}
全体のコードを記載しておきます!(パターン1)
import json
import boto3
client = boto3.client('translate')
def lambda_handler(event, context):
response = client.translate_text(
Text='おやすみなさいませご主人様',
SourceLanguageCode='ja',
TargetLanguageCode='en',
Settings={
'Formality': 'INFORMAL',
'Profanity': 'MASK',
'Brevity': 'ON'
}
)
output = response.get('TranslatedText')
return {
'statusCode': 200,
'body': json.dumps({
'output': output
})
}
眠いのです(-_-;)
それではテストを実行していきます。
ソースコードの項目に貼り付けたら、Ctrl+Sで上書き保存します。
その後、「Deploy」をクリックした後、「test」をクリックします。
出力結果
Test Event Name
(unsaved) test event
Response
{
"statusCode": 200,
"body": "{\"output\": \"Good night, master\"}"
}
Function Logs
START RequestId: 4e91ce47-19c8-439a-9a88-8e06fa3a35e7 Version: $LATEST
END RequestId: 4e91ce47-19c8-439a-9a88-8e06fa3a35e7
REPORT RequestId: 4e91ce47-19c8-439a-9a88-8e06fa3a35e7 Duration: 646.73 ms Billed Duration: 647 ms Memory Size: 128 MB Max Memory Used: 76 MB Init Duration: 508.21 ms
Request ID
4e91ce47-19c8-439a-9a88-8e06fa3a35e7
グッドナイトマスターって(´▽`)
パターン2(公式さん作成のデフォルトになります。)
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
})
}
出力結果
Test Event Name
(unsaved) test event
Response
{
"statusCode": 200,
"body": "{\"output_text\": \"Good morning\"}"
}
Function Logs
START RequestId: ac45a998-e6bf-477a-bcf7-d69accd177c1 Version: $LATEST
END RequestId: ac45a998-e6bf-477a-bcf7-d69accd177c1
REPORT RequestId: ac45a998-e6bf-477a-bcf7-d69accd177c1 Duration: 617.51 ms Billed Duration: 618 ms Memory Size: 128 MB Max Memory Used: 76 MB Init Duration: 428.80 ms
Request ID
ac45a998-e6bf-477a-bcf7-d69accd177c1
真剣にハンズオンを続けます。
API
これはAPIというと天気予報APIなどを想像する方もいると思います。アプリからAPIに接続して天気予報を表示させることができる一種のアプリからアプリを呼び出すイメージのものと理解しちゃって問題ないと思います。
一方、Amazon API Gatewayは、API+αの機能を有したエンドポイントと理解しちゃいましょう。裏にはLambdaなどが控えており、スケールできる高機能なエンドポイントがあるイメージです。
+αの部分は調べた方が良いかと思います。
https://aws.amazon.com/jp/api-gateway/
ひとまず手を動かします。
APIの画面に移動します。
構築をクリックします。
translate-api(任意)
エンドポイントタイプは、プライベートでもなく、世界からの接続を要している訳ではないので、「リージョン」を選択します。
+αの部分になりますね。サーバーではなくAmazon API Gateway自身に仕事をさせます。
「リソースを作成」をクリックします。
リソース名のみsample(任意)と入力して作成します。
画面下の「メソッドを作成」をクリックします。
「GET」を選択し、「Mock」を選択します。これで、API自身の動作(XMLからJSONに変換するなど。)を決めることができます。
ここでちょっと復習です。ここで使用するのはGET(取得)ですね。
CRUD | 処理内容 | HTTPメソッド |
---|---|---|
Create | データの作成 | POST |
Read | データの取得 | GET |
Update | データの更新 | PUT |
Delete | データの削除 | DELETE |
少し参考に設定画面を貼ります。ここで、APIキーを設定することができます。
クエリも設定できるようです。
このままデフォルトで「作成」をクリックします。
そして、スクロールし、「統合レスポンス」タブを選択し、「編集」をクリックします。
ここで細かく設定できますね。ここは今回スルーします。
マッピングテンプレートに次のjsonコードをペーストします。
設定する中で様々なレスポンスのテンプレが存在しますね!APIを使いたい用途が異なるので無視します。
{
"statusCode": 200,
"body": {
{
"report_id": 5,
"report_title" : "Hello, world"
},
{
"report_id": 7,
"report_title" : "Good morning!"
}
}
}
「テスト」タブからデフォルトの設定で、テストを実行します。
するとAPIがhello worldをステータス200で返してますね。
画面上の「APIをデプロイ」をクリックします。
「新しいステージ」を選択し、「development(任意)」という名前を付けてデプロイをクリックします。
ステージ内(development)のGETをクリックし、「URL を呼び出す」にあるURLをブラウザに貼り付けて、APIが機能しているか確認することができます。
すると次のように表示されます。
Amazon API GatewayとLambdaの連携
先に先程作成したリソースとメソッドを削除します。
リソースの削除
新たにリソースを作成します。
「translate(任意)」
画面下の「メソッドを作成」をクリックし、再び「GET」を指定します。
次は、Mock(APIも仕事をする設定)ではなく、Lambda(APIは素通りさせることを想定)を選択します。
「Lambdaプロキシ統合」にチェックを入れて、先程作成した関数を指定し、メソッドを作成します。
続いて、スクロールして「メソッドリクエスト」タブから「編集」をクリックします。
クエリ文字列を追加をクリックします。
text(任意)と入力して、クエリを必須に設定して、保存します。
続いて、Lambdaの画面に移動し、コードをAPIに適用するため、エンコードとヘッダーについて設定を追加します。人が読める状態のコードなので、エンコードはFalseです。また、headersも特に設定しません。
公式サイト(APIに接続するためのあれこれ):
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-integration-settings-integration-response.html
完成コード
import json
import boto3
client = boto3.client('translate')
def lambda_handler(event, context):
response = client.translate_text(
Text=event['queryStringParameters']['Text'],
SourceLanguageCode='ja',
TargetLanguageCode='en',
Settings={
'Formality': 'INFORMAL',
'Profanity': 'MASK',
'Brevity': 'ON'
}
)
output = response.get('TranslatedText')
return {
'statusCode': 200,
'body': json.dumps({
'output': output
}),
'isBase64Encoded': False,
'headers': {}
}
次に、テストのタブから、新しいイベントを作成します。
名前はtest01(任意)です。「Amazon API Gateway proxy」を選択します。
すると、コードがずらっと出てきますが、次の箇所に手を加えます。
該当箇所にコピペして使用されてください。
なお、このコードは、すぐ上に記載しているコードの「Text」を呼出しますので、上記コードを使用する場合は、このままの下記コードをイベントjsonの該当箇所に貼り付けましょう。
"queryStringParameters": {
"Text": "こんばんわ"
貼り付けたら、「保存」をクリックします。
ソースコードタブに移動し、上記完成コードを貼り付けて、Ctrl+Sで保存し、デプロイをクリックし、テストを実行します。
実行結果
Test Event Name
test01
Response
{
"statusCode": 200,
"body": "{\"output\": \"Good evening\"}",
"isBase64Encoded": false,
"headers": {}
}
Function Logs
START RequestId: a41cfab9-0a88-455e-ae28-af5a9ccfb59e Version: $LATEST
END RequestId: a41cfab9-0a88-455e-ae28-af5a9ccfb59e
REPORT RequestId: a41cfab9-0a88-455e-ae28-af5a9ccfb59e Duration: 668.80 ms Billed Duration: 669 ms Memory Size: 128 MB Max Memory Used: 77 MB Init Duration: 450.30 ms
Request ID
a41cfab9-0a88-455e-ae28-af5a9ccfb59e
次にAPIの画面に戻ります。
「APIをデプロイ」から、先程作成した「development」を選択し、デプロイをクリックします。
先程と同じように、「URLを呼び出す」の箇所のURLをブラウザに貼り付けると次のようなエラーが出ます。
ブラウザのURL欄の末尾に「?Text=おはようございますご主人様」と手打ちします。
DynamoDB
やっとの思いで作成できます。DynamoDB
key,value型を体験できるのですね。
現在の構成
テーブルの作成をクリックし、テーブル名translate-history(任意)と入力し、パーティションキーにtimestampと入力します。型は文字列のままで大丈夫です。
つまり、レコードに時間を文字列で追加(今回は手動)します。ということ。
キャパシティユニット(同時処理可能なキャパ)は、デフォルトを解除して、設定します。
結果整合性は参照した時に、誤差がある状態で返される可能性があります。読み取りの正確性が必要がない時に設定するものです。
このまま設定を継続します。
読み取り書き込みのキャパを事前に設定するかしないかの設定を行います。今回は事前に設定していきます。
セカンダリインデックスも設定しないのでこのまま進みます。
複合キーのようなもの。
このままテーブルを作成します。
項目(フィールド)を追加していきます。レコードを手動追加してみましょう。
フィールドと値が手動によって追加されました。
AWS Lambda、Amazon API Gateway、Amazon DynamoDBを組み合わせて構成します。
Lambda最終形態
まず、ロールにDynamoDBを追加して接続できるようにします。
設定タブからアクセス権限、ロール名をクリックします。
許可を追加をクリックし、PutItemとUpdateItem権限を追加したいのですが、デフォルトのポリシーに丁度良いのがないので、ひとまずFullAccessでいきます。
DynamoDBを使います。
公式リファレンス:
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/table/index.html
import json
import boto3
import datetime
client = boto3.client('translate')
dynamodb = boto3.resource('dynamodb').Table('translate-history')
def lambda_handler(event, context):
response = client.translate_text(
Text=event['queryStringParameters']['Text'],
SourceLanguageCode='ja',
TargetLanguageCode='en',
Settings={
'Formality': 'INFORMAL',
'Profanity': 'MASK',
'Brevity': 'ON'
}
)
output = response.get('TranslatedText')
# テーブルへの書き込みには put_item メソッドを使用する
dynamodb.put_item(
Item={
'timestamp': datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
'Text': event['queryStringParameters']['Text'],
'output': output
}
)
return {
'statusCode': 200,
'body': json.dumps({
'output': output
}),
'isBase64Encoded': False,
'headers': {}
}
コードを編集しましたので、Ctrl+Sで保存し、デプロイをクリック、testをクリックしていきます。
出力結果
Test Event Name
test01
Response
{
"statusCode": 200,
"body": "{\"output\": \"Good evening\"}",
"isBase64Encoded": false,
"headers": {}
}
Function Logs
START RequestId: 6ac13179-a0ef-44cd-b95a-ad66be6ae701 Version: $LATEST
END RequestId: 6ac13179-a0ef-44cd-b95a-ad66be6ae701
REPORT RequestId: 6ac13179-a0ef-44cd-b95a-ad66be6ae701 Duration: 1075.79 ms Billed Duration: 1076 ms Memory Size: 128 MB Max Memory Used: 79 MB Init Duration: 470.03 ms
Request ID
6ac13179-a0ef-44cd-b95a-ad66be6ae701
DynamoDBを確認してきます。
レコードが無事追加されています。
DynamoDBに対する私見
- 少しだけ使ってみてのDynamoDBの私見ですが、使いにくさをあまり感じさせませんが、設定中の翻訳なのかそもそもの機能が違うのか解釈が不足いているものの、「通常のデータベースで使用する言葉」にしたら使いやすい気がしました。
- テーブル設計をする必要のないKeyValueの関係であるものは扱えると理解しました。簡単に言うと、「1はa」です。といった公式のデータを大量かつリアルタイムに残したい時に使う。と理解しました。RDBと同じに考えたらいけないですね。データ型も制限があります。
- 具体的な使用方法は次のサイトから確認しましょう。
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/best-practices.html
リソースの削除
DynamoDB
項目を削除します。
テーブルを削除します。
API Gateway
ステージを削除します。
メソッドを削除します。
リソースを削除します。
勉強になりました!
では!