はじめに
決済チームには、注文合計を計算する関数が必要です。このラボでは、短い Python ハンドラーをデプロイし、2 つの JSON 入力を送ってから、手数料を加えるように計算を更新します。整数のセント単位を使って計算を簡単にし、最後に自分の関数とログを削除します。
最初に LabEx で AWS を使い始める、IAM ロールで一時認証情報を使う、CloudWatch Logs で失敗したリクエストを見つける を完了してください。この新しい環境には、CLI、作業ディレクトリ、実行ロールが用意されています。
認定試験との関連
このラボでは、次の試験トピックに関連する実践的な演習を行います。
- Cloud Practitioner (CLF-C02) · タスク 3.3: Lambda のデプロイ、JSON イベント、計算結果のレスポンス。
- Solutions Architect – Associate (SAA-C03) · タスク 2.1: Lambda のデプロイ、JSON イベント、計算結果のレスポンス。
- Developer – Associate (DVA-C02) · タスク 1.2: Lambda のデプロイ、JSON イベント、計算結果のレスポンス。
注文の計算をデプロイする
このステップでは、未完成のハンドラーを置き換え、関数をデプロイします。AWS Lambda は、関数を呼び出すとコードを実行します。イベントは、その呼び出しに渡す入力です。ハンドラーは、Lambda がその入力を渡して呼び出す Python 関数です。app.handler という設定は、app.py 内の handler という関数を意味します。
準備済みの作業ディレクトリに移動し、ひな形を確認します。現在は空のオブジェクトを返すため、注文を計算できません。
cd /home/labex/project
cat app.py
Python は、インデントで関数内の文をまとめます。event["quantity"] は、受信した JSON オブジェクトから値を読み取ります。* は数量と単価を掛け合わせ、return は計算したオブジェクトを呼び出し元に返します。context は呼び出しの情報を提供しますが、今回の計算ではまだ使いません。
ひな形を、以下の完成したハンドラーに置き換えます。cat > app.py は、<<'PY' と最後の PY の間の行をファイルに書き込みます。終了行には PY だけを書いてください。
cat > app.py <<'PY'
import json
def handler(event, context):
order_id = event["order_id"]
quantity = event["quantity"]
unit_price = event["unit_price_cents"]
total = quantity * unit_price
print("EVENT " + json.dumps(event))
return {"order_id": order_id, "total_cents": total}
PY
print 文は入力を実行ログに書き込みます。レスポンスを返すものではありません。顧客の秘密情報をログに含めないでください。これらのイベントには、架空の識別子と数値だけが含まれています。
Lambda がデプロイするアーカイブである Zip パッケージを作成します。ハンドラーを見つけられるように、app.py をアーカイブの最上位に置きます。実行ロールは、コードの実行中に Lambda が使うアイデンティティです。準備済みのロールはログ出力に対応しています。データへのアクセスは後のラボで設定します。ロールの ARN をシェル変数に読み込みます。ARN は特定のリソースを識別するもので、変数を使うと手作業でコピーせずに済みます。
zip -q function.zip app.py
ROLE_ARN=$(aws iam get-role --role-name labex-fn01-execution --query 'Role.Arn' --output text)
Python 3.12 ランタイムと 5 秒のタイムアウトでデプロイします。fileb:// はアーカイブをバイトとして読み込みます。ランタイムは言語の実行環境を選び、タイムアウトは 1 回の呼び出しの実行時間を制限します。
aws lambda create-function --function-name labex-fn01-quote --runtime python3.12 --handler app.handler --role "$ROLE_ARN" --zip-file fileb://function.zip --timeout 5 --query '{Name:FunctionName,Runtime:Runtime,Handler:Handler,Timeout:Timeout,CodeSize:CodeSize}'
Name は labex-fn01-quote、Runtime は python3.12、Handler は app.handler、Timeout は 5 で、CodeSize は正の値になるはずです。関数の作成はコードをデプロイしますが、ハンドラーを呼び出すわけではありません。
AWS View には、関数、ハンドラー、コードのフィンガープリントが表示されます。呼び出しログはまだ空です。参照ロググループは無関係なプラットフォームのデータなので、変更せずに保持してください。
2 つの JSON イベントで呼び出す
このステップでは、デプロイした関数を 2 つの異なる注文で呼び出し、レスポンスを読み取ります。JSON は、名前付きフィールドを持つオブジェクトを表します。数値には引用符を付けず、文字列には付けます。各呼び出しは、それぞれのイベントを受け取ります。

最初のイベントを書き込みます。単価 375 セントの商品が 2 個です。
cat > small.json <<'JSON'
{"order_id":"fn01-small","quantity":2,"unit_price_cents":375}
JSON
関数を呼び出し、レスポンスを保存します。--cli-binary-format raw-in-base64-out により、CLI は通常の JSON をペイロードとして受け取れます。file:// はイベントのテキストを読み込み、最後に指定するファイル名に返されたペイロードを保存します。
aws lambda invoke --function-name labex-fn01-quote --cli-binary-format raw-in-base64-out --payload file://small.json small-response.json
cat small-response.json
コマンドは StatusCode 200 を報告します。レスポンスファイルには {"order_id":"fn01-small","total_cents":750} が入るはずです。サービスのリクエストステータスと、ハンドラーが返したデータは、異なる証拠です。ペイロードも確認してください。
コードを再デプロイせずに、2 件目の注文を送ります。単価 120 セントの商品が 5 個なので、異なる合計になるはずです。
cat > large.json <<'JSON'
{"order_id":"fn01-large","quantity":5,"unit_price_cents":120}
JSON
aws lambda invoke --function-name labex-fn01-quote --cli-binary-format raw-in-base64-out --payload file://large.json large-response.json
cat large-response.json
{"order_id":"fn01-large","total_cents":600} が返るはずです。同じ関数の計算は、入力値によって変わります。
AWS View で、注文 ID、数量、価格、合計を比較します。関数の設定は同じままで、呼び出しの記録が変わります。どちらかの注文の Show logs を開き、入力と返された結果を確認してください。
コードを更新し、結果を追跡する
このステップでは、100 セントの手数料を追加し、新しい呼び出しが更新した計算を実行することを確認します。ローカルの app.py を編集しても、デプロイ済みのコードは変わりません。パッケージを更新し、Lambda に送る必要があります。
ハンドラーを以下の改訂版に置き換えます。変わるのは計算だけで、+ 100 が掛け算の後に手数料を追加します。
cat > app.py <<'PY'
import json
def handler(event, context):
order_id = event["order_id"]
quantity = event["quantity"]
unit_price = event["unit_price_cents"]
total = quantity * unit_price + 100
print("EVENT " + json.dumps(event))
return {"order_id": order_id, "total_cents": total}
PY
zip -q function.zip app.py
aws lambda update-function-code --function-name labex-fn01-quote --zip-file fileb://function.zip --query '{Name:FunctionName,CodeSHA:CodeSha256}'
デプロイは、名前とコードの SHA フィンガープリントを返します。AWS View には変わったフィンガープリントが表示されます。以前の呼び出し結果は、ログに残っています。
Console と比較するため、公式の例では Python ファイルの隣に Deploy と Test の操作が表示されています。例の lambda_function.py と lambda_handler は、このラボの app.py と handler に対応します。ここでは Terminal の手順で続けてください。

出典:AWS Lambda ガイド。
最初の注文と同じ数量と価格を、新しい対応付け用 ID で使います。
cat > revised.json <<'JSON'
{"order_id":"fn01-revised","quantity":2,"unit_price_cents":375}
JSON
aws lambda invoke --function-name labex-fn01-quote --cli-binary-format raw-in-base64-out --payload file://revised.json revised-response.json
cat revised-response.json
{"order_id":"fn01-revised","total_cents":850} が返るはずです。商品代金の 750 セントに、100 セントの手数料が加わります。最初のレスポンスは 750 のままです。コードの更新は履歴を書き換えません。
実行ログは /aws/lambda/<function-name> に保存されます。この注文 ID を含むメッセージを取得し、イベントと計算されたレスポンスを結び付けます。
aws logs filter-log-events --log-group-name /aws/lambda/labex-fn01-quote --filter-pattern '"fn01-revised"' --query 'events[].message'
EVENT の入力と、合計 850 の返されたオブジェクトが表示されるはずです。ストリーム全体には、注文のレスポンスとは別に、呼び出しの開始、終了、ランタイムのレポートも含まれます。
AWS View に戻ります。実際の 3 件の記録を比較し、fn01-revised の Show logs を開いて、入力と 850 セントの結果が一致することを確認します。参照データは変更されていません。

関数を削除し、参照ログを保持する
このステップでは、関数とその実行ロググループだけを削除し、無関係な参照データが残っていることを確認します。関数とロググループは別々のリソースです。関数だけを削除しても、保存されたログは削除されません。
正確な名前で関数を削除し、正常に一覧を読み取ります。
aws lambda delete-function --function-name labex-fn01-quote
aws lambda list-functions --query 'Functions[].FunctionName'
空のリストが返るはずです。認証や接続のエラーは、削除の証明にはなりません。
所有する実行ログを削除し、残っているグループを一覧表示します。
aws logs delete-log-group --log-group-name /aws/lambda/labex-fn01-quote
aws logs describe-log-groups --query 'logGroups[].logGroupName'
/labex/labex-fn01-reference だけが残るはずです。そのメッセージを読み取り、削除作業で無関係なデータを保持したことを確かめます。
aws logs get-log-events --log-group-name /labex/labex-fn01-reference --log-stream-name platform --query 'events[].message'
INFO platform reference keep unchanged が返るはずです。AWS View には、デプロイ済みの関数と呼び出しログがなくなり、参照データが残った状態が表示されます。準備済みのロールとアイデンティティは、環境の準備用リソースです。認証情報の失効と環境の終了は、リソース確認の後に行われます。
まとめ
Python ハンドラーを書き、Zip パッケージをデプロイして、2 つの JSON イベントから合計を計算しました。デプロイ済みの計算を更新し、新しい結果を実行ログに対応付けました。最後に、参照データを保持しながら、関数とそのロググループだけを削除しました。



