はじめに
決済チームには、注文合計を計算する関数が必要です。このラボでは、短い 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 に保存します:
ROLE_ARN=$(aws iam get-role \
--role-name labex-fn01-execution \
--query 'Role.Arn' \
--output text)
echo "$ROLE_ARN"
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 は、名前付きフィールドを持つオブジェクトを表します。数値には引用符を付けず、文字列には付けます。各呼び出しは、それぞれのイベントを受け取ります。
これらは同期呼び出しです。CLI は関数の応答を待ちます。Terminal には呼び出しのメタデータが表示され、応答ファイルにはハンドラーが返したオブジェクトまたはエラーが保存されます。両方を読んで、要求した注文計算が成功したかを判断してください。

最初のイベントを書き込みます。単価 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
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
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
アプリケーションを function.zip にパッケージ化します:
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 の手順で続けてください。

最初の注文と同じ数量と価格を、新しい対応付け用 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
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
Lambda 関数一覧を確認します:
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 イベントから合計を計算しました。デプロイ済みの計算を更新し、新しい結果を実行ログに対応付けました。最後に、参照データを保持しながら、関数とそのロググループだけを削除しました。



