Rのつく財団入り口

ITエンジニア界隈で本やイベント、技術系の話などを書いています。

【感想】『AWS Lambda実践ガイド』:PythonでLambda関数を書いていこう

AWS Lambda実践ガイド

 2014年にサービス開始以来、AWSのサーバーレス技術の中核を担っているAWS Lambda。そのLambda関数の実際の使い方を解説した本です。2017年の発売なのでよく本屋でも見かけます。コードはすべてPython3.6となっています。

AWS Lambda実践ガイド

AWS Lambda実践ガイド

第1章 Lambda で実現するサーバーレスシステム

Lambdaの概要の章。

  • EC2に比べると基本的にコストは減らせる。
  • 2017年の本なので実行環境はJS(Node.js), Java, C#, Pythonと記載。その後Ruby, Go, PowerShellが加わっています。

aws.amazon.com

  • ステートレスなので前回の状態は保持できない。
  • 最大稼働は5分。ずっと動き続ける処理はEC2上で実現したほうがよい。
  • 基本的に小さい機能を組み合わせて実装。SQSSNSで互いに知らせ合ったりできる。
  • 基本リージョンは関係ない。
  • 実行のトリガーになるものを「イベントソース」と呼ぶ。
  • CloudWatch Logsにログを残せるので、監視やデバッグにはこれを使う。

f:id:iwasiman:20210211171139p:plain
AWS Lambda 実践ガイド

第2章 Lambda 事始め

 簡単なサンプルからLambda関数を作っていく章。

  • 入力の引数はイベントの情報コンテキストの情報の2つ。(JavaScriptだと第3引数がcallbackでちょっと違ったりする。)
  • Lambda関数=ハンドラとも呼ばれるので、関数名は「機能名_handler」が通例。
  • Pythonであれば入力のJSON{"x": 10, "y": 2}のような値だとハンドラに来る時点でもうパースされているので、入力の引数 event からevent["X"]のようにして取れる。簡単。
  • 第2引数のcontextからは、様々な環境情報が採れる。
  • 通常のreturn文の中身が戻り値に。
  • 標準出力した内容は全て CloudWatch Logs に書き出される。Pythonだとprint関数とか。
  • IAMユーザとロールが必要。ユーザの権限は、作るのにlambda:createFunction、実行にlambda:InvokeFunction。ロギングに logs:PutLogEvents/CreateLogStream/CreateLogGroup
  • 開発者ユーザのポリシーが AWSLambdaReadOnlyAccess, 実行権限だけが AWSLambdaRole, フルが AWSLambdaFullAccess
  • 関数実行のIAMロールポリシーは基本が AWSLambdaBasicExecutionRoleBasicの部分にKinesis, DyamoDB, VPCが入ったりするポリシーも。

実際の作成はAWS管理コンソールから行えます。

  • 「設計図の選択」でブループリントからも作れるし「一から作成」もできる。
  • 最初にトリガーを選ぶ。
  • 関数の名前とハンドラは別。ハンドラはPythonの場合は「ファイル名.関数名」で、コンソールから作るとファイル名が自動で"lambda_function"になる。
  • 詳細設定はあまり弄らなくても動くっぽい。
  • 「テストイベント」の定義をすることで、入力と出力がそこで確認できる。
  • 管理コンソールの近くにあるところから CloudWatch Logs も確認できる。エラーもここで分かる。

第3章 AWS Lambda の仕組み

  • Lambda関数の実体は、OSでAmazon Linux が入ったAMIを元にした「Lambdaコンテナ」の中で動いている。
  • /tmp が一時的に使えて512MBまで。このへんAWS認定によく出ます。
  • EC2Amazon Linux AMIを元にした環境を立ち上げてそこでプログラムするのと同じことになる。こちらで開発・デバッグしてからLambdaに上げる方法がよく取られる。
  • コンテナは再利用されることで起動時間を短くしている。
  • このコンテナ使いまわしにより、/tmpに前回データが残る可能性、またLinux上での実行ユーザが異なる可能性がある。実行ユーザが違うと/tmpの前回実行分を消せない場合があるので、処理の最後でその回の分を自身でクリーンするとよい。
  • VPC上のサブネットに配置する場合はオプションがあるが、起動に時間が掛かり同時実行性が落ちる問題あり。

→これは2019年のアップデートで改善されていますね。2020年に出た『基礎から学ぶ サーバーレス開発』だと記述があります。

iwasiman.hatenablog.com

  • VPC内にLambdaコンテナを配置すると、振る舞いはEC2と同じでNATゲートウェイを通して外と繋がったりする。

 そしてLambda関数の実行には2タイプ。イベントソースがLambdaを呼び出すのが「プッシュモデル」

  • プッシュモデルの中で2種類、「同期呼び出し」は実行が終わってから戻り値が渡される。
  • 「非同期呼び出し」はキューに送信されて呼び出し元にすぐに戻り、戻り値は破棄。
  • イベントからキューが取り出されてLambdaが実行された後、エラーがあるとしばらくしてから2回リトライされる。
  • 合計3回実行で全失敗後のイベントはデフォルトは消失。設定の「DLQリソース」を設定するとDead Letter QueueとしてSNSに送信したりできる。
  • このリトライは、関数実行での例外発生時も自動で行われる。「エラー」と「例外」を別に扱う。
  • 実行順序は保証されない、また正常終了でもリトライすることがあるので、Lambda関数でべき等の工夫が必要。
  • 同時実行数はデフォルト1000。同期呼び出しで最大値を超えると単にエラー。非同期呼び出しで超えると最大6時間、遅らせながら再試行される。

マイクロサービスのサービス間連携で重要になる非同期の呼び出しがS3, SNS, SES, CloudFormation, CloudWatch Logs, CloudWatch Events 。一方同期呼び出しはCognito, Echo, API Gateway などでした。
べき等の話はクラウドの文脈でよく出てきますが、やはり大事なんですね。

 一方、実行の2タイプ目。流れるデータをLambda側で監視するのが「ストリームベース」DynamoDBKinesisが該当。

  • DynamoDBのレコードの追加更新削除でLambdaが起動。
  • このストリームベースではLambda側に、対象リソースへのアクセス権が必要なのでIAMロールを設定。
  • Lambdaが失敗するとストリームの有効期間(24H)、ずっと再試行して新しいデータは受信しない。
  • 同時実行数はシャード数でカウントされる。

続いてイベントソースの話。

  • 例えばCloudTrailはイベントソースにできないが、証跡を記録するS3バケットに設定すればCloudTrail→S3イベント→Lambdaといけるように、間接的に繋ぐやり方がある。
  • 同じようにCloudWatch→SNS→Lambdaなどもいける。
  • 関数の第一引数eventの内容は、イベントソースによって異なる。Lambda側ではなくイベントソースのサービス側の公式ドキュメントに載っている。

最後に定期実行の話。

  • 新規作成時にlambda-canaryという設計書を使うと良い。
  • スケジュール式はUNIXcron形式またはrate式。
  • サンプルに合わせた環境変数がそのまま設定されるが、消してもそのままでも動く。
  • 例えば定期的にCloudWatch Eventで起動するなら、テストの後はトリガーの有効化をしないと動かない。
  • CloudWatch Event 起動でも任意の固定の引数を与えて起動したりもできる。

第4章 S3 のイベント処理

 S3バケットにファイルがアップロードされたイベントを検知してLambda起動、そのファイルをダウンロードして暗号化し、別のバケットにアップロードする...という例を通して実際のコードを書いていく章。

  • この処理で同じバケットを指定すると実は無限ループしてしまう。そのケースではディレクトリやファイル名でチェックが必要。
  • S3バケットを作ったら、Lambda関数を実行するロールに対してAmazonS3FullAccessというポリシーを適用。実際はもっといろいろある。
  • イベントs3:ObjectCreatedを起点とする。イベント引数のJSONの中はRecordsキーの中のリストが1件1件。
  • この中のs3.object.key が「キー」という名前だが実際のファイル名が入っている。s3.bucket.nameバケット名。
  • Lambda関数作成は用意されている設計図(ブループリント)の s3-get-objectでやるとよい。イベントが起こったファイルのプレフィックスサフィックスで限定なども指定できる。
for rec in event['Records']:
    print(rec['s3']['object']['key'])

のコードでファイル名が取得できる。printしているのでCloudWatch Logsに渡る。

  • Lambda関数+利用するライブラリをzipしたものを「Lambdaデプロイパッケージ」という。Python以外の言語でも同じ。
  • 短いプログラムはWindowsMac上でもよいが、本格的にやる場合はLambdaコンテナと同じEC2インスタンス上でやるのがベター。EC2のIAMロールをLambda関数実行のロールと同じにしておくと良い。
  • 本書の例ではEC2環境にPythonの環境分離ツール virtualenv で環境作成。boto3 はこの開発でしか使わないので > pip install boto3
  • 暗号化ライブラリの動作に必要なgcczlibはsudo指定でインストール。
  • 暗号化ライブラリはこの開発用なので > pip install pyminzip とインストール方法に差がある。これらはPythonコードの中で普通にimportする。
s3 = boto3.resource('s3')
s3_obj = s3.Object('バケット名', 'ファイル名')

のようにバケット名とファイル名で取得可能となります。バケット名はAWS全体でユニーク、ファイル名はバケットの中でユニークで、同名のファイルをアップロードし直すと上書きになるからですね。

  • tmpdir = tempfile.TemporaryDirectory() のようにして作業用のディレクトリを作ってそこで作業できる。終わったら tmpdir.cleanup() でお片付け。
  • コードの外側で可変にしたい場合は管理コンソールの環境変数で設定、コード内からは os.environ['{環境変数名}'] のようにすればバケット名などを外出しできる。

  • 実は、管理コンソールのハンドラで指定した関数名(デフォルトはlambda_handler)しかAWS上での実際の実行時は実行されない。そのため、ファイルの後半に別の関数を入れたりも自由にできる。

  • Pythonならそのファイルを直接実行した時だけTrueになる
    if __name__ == '__main__': の後で、
    適当な辞書型のテストデータを変数 eventcontext に入れて、lambda_handler(event, context) を呼び出すように書いておけばローカル実行でもテストできる。

 このテスト方法は知りませんでした。いろいろ応用できそうですね。最後はデプロイパッケージの作り方。

  • Lambda関数本体の*.pyファイル、関連ライブラリ、全部階層なしのルートディレクトに置いてzipにする。
  • アップロードはAWS管理コンソールからできる。

なおLambda本体と一緒に関連ライブラリをアップロードする方法は、本書の記述の通り基本はZipで展開後に250MBが上限。その後「Lambdaレイヤー」の機能が追加されて複数の関数で共有が可能に。そして2020年12月から、最大10GBのコンテナイメージの形でもデプロイできるようになりました。

aws.amazon.com aws.amazon.com dev.classmethod.jp

第5章 API Gateway、DynamoDB、SES との連携

 今度はS3静的ホスティングにHTMLを上げてform要素のある入力フォームを用意。
そこからユーザーが送信するとAPI Gatewayで受けてLambda起動、送ってきたユーザ情報をDynamoDBに保存、S3の中にあるスペシャルコンテンツの署名付きURLを取得して、Amazon SESを使ってそのユーザにプレゼントする……という本格的な連携です。

  • API Gatewayの作成には管理ポリシー AmazonAPIGatewayFullAccess の他に AmazonAPIGatewayAdministrator が便利。
  • 他のサービスには Amazon{DynamoDB|S3|SES}FullAccess を使用。(実際はもっと細かく指定する。)
  • API Gateway+Lambdaを繋げる時は、細かく設定していく「マッピングテンプレート」より「Lambdaプロキシ統合」の方が簡単。ただし制限がいくつかある。

docs.aws.amazon.com

  • 管理コンソールから作る時の設計図(ブループリント)は microservice-http-endpoint を選び、Lambda関数を作っていく。

めっさ余談ですが作中の図の従来型のWebサーバーの説明に「PerlPHPJavaなどのプログラム」と例にPerl言語が出てきて、おっ作者さんベテランだしPerl世代の方かな?と思いました。本書は2017年刊行ですが、ネット上の2017年ごろの記事だともうほとんどPerlは出てこないですね。
また設計図の英語名に microservice が入っていて、なるほどまさにマイクロサービス用途なんだなあと思います。

  • 引数のevent の中にはpath, httpMethod, queryStringParameters などなどのキーで情報が採れる。requestContext.identify の中にクライアント側のIPやユーザーエージェントも入っている。
  • Lambdaプロキシ統合を使っている際は、関数の戻り値がHTTPレスポンスを表す指定の辞書型でなければならない。ステータスコードやヘッダやボディを一緒に指定する。

  • S3バケットを作ったときに、バケット単位で Static website hosting をONに。この時に ~amazonaws.com/ドメイン単位でアクセスされたときに表示されるインデックスドキュメント、エラー時に表示されるエラードキュメントも指定できる。

  • <form>要素のあるHTMLで入力フォームを作り、ボタン押下時はformタグでsubmitでなく一旦JavaScriptに飛んでそこで通信する形式に。
  • 完成したらS3バケットへアップロード。「パブリック読み取りアクセス権限を付与する」を選ぶ。
  • こうしてフォームから送信→API Gateway→Lambdaと飛ぶようになったら、Lambda関数では以下のように引数のeventに入っているリクエストのボディからフォーム内の値を取り出せる。
params = urllib.parse.parse_qs(event['body'])
username_textbox_value = params['username'][0]

 そして保存用にDynamoDBが登場します。

  • スキーマレスなのでテーブル新規作成時はプライマリーキーだけでよい。
  • RDBの列やレコード→アイテム(項目, item)RDBのカラムや列→アトリビュート(属性, attribute)。ややこしい……
  • 主なデータ型は文字列、数値、バイナリで、日付型がないのに注意。日付は文字列でISO 8601形式がオススメ。
  • 読み込みキャパシティユニット、書き込みキャパシティが低すぎると運用時に出るのは400 Bad Requestや、ProvisionedThroughputExceededException
  • DynamoDBには数値をカウントアップするRDBSequenceのような機能が元々ない。tablename, seq の2属性を持つ別テーブルで更新していく「アトミックカウンタ」を作ることで代用できる。

blog.serverworks.co.jp dev.classmethod.jp

  • LambdaでのDynamoDB更新は、boto3からテーブルのオブジェクトを取得したら属性を指定して更新が update_item() , 新規登録や置き換えるのが put_item()。辞書形式で対象のアイテムの各属性を指定する。
  • 完全一致でアイテムを一つ取り出すのが get_item()、範囲指定の検索が query()、全件検索で重くなるのが scan()
  • 数値のFloat型は使えないのでDecimal型に変換が必要。
  • メソッドのアンダーバーあるなしなどはプログラム言語によって若干違う。
  • json.dumps({検索結果}, cls=DecimalEncoder) のように結果をJSON文字列に展開する際は、Decimalオブジェクトを変換できるようにするとよい。

 そしてスペシャルコンテンツを別のS3バケットに作っていきます。

  • S3の別バケットを作り、該当のファイルをアップロード。
  • Lambdaのコードではboto3からs3のオブジェクトを取得したら、s3.generate_presigned_url({名前付き引数群...}) のようにして毎回違う署名付きURLを生成できる。題材ではこの値を含めてDynamoDBput_item()

そして最後はAmazon SESによるメール送信。

  • 本書の2017年時点では東京リージョンでは使えないので、SES作成時にバージニア北部(us-east-1)のリージョンを指定。

→その後2020年7月からめでたく東京リージョンでも使えるようになっていますね。 aws.amazon.com

  • 諸々設定して、検証は「メールアドレスの検証」にすると、送信者メールアドレスを指定してVerifyした後そのメアドにAWSからメールが届く。メール文中のURLクリックで検証完了。
  • Lambdaのコードでは 以下のようにしてSES用のオブジェクトを取得、メールが送信できる。リージョンを指定しないとその時Lambdaを実行しているリージョンになる。
client = boto3.client('ses', region_name='{リージョン名}')
client.send_email({名前付き引数で諸々})

この組み合わせで仕組みは完成なのですがCross-Origin Resource Sharing (CORS) 問題があります。S3の静的サイトホスティング上のHTMLページの中からフォーム内の値をもってJavaScriptAPI Gatewayに向かって通信して結果を得ようとすると、ドメインをまたがるのでブラウザが規約違反でエラーを出すのですね。

  • Lambda関数の戻り値でHTTPレスポンス相当の値を返すところで、'headers'
    'access-control-allow-origin': {S3静的ホスティングのドメイン}
    を指定してヘッダに追加、CORSを有効にする。
  • 実はAPI Gatewayの管理コンソールからの設定でも「CORSの有効化」ができる。が、Lambdaプロキシ統合の場合はこの手が使えない。

 このCORSの話はけっこう有名でいろんなシーンで出てきます。

docs.aws.amazon.com

 自分もAWS上ではないですがハマったことがあります。Webアプリのフロントの画面上で動いているJS→別ドメインで動いているWebアプリのサーバー側のAPIにアクセス しようとすると同じ事が起こります。
 このケースでは別ドメイン側のサーバーからのレスポンスにHTTPレスポンスのヘッダに'access-control-allow-origin'を加えるように、Webサーバー設定もしくはサーバーサイド(バックエンド)側のコードで対応すると解決します。S3静的ホスティング→API Gateway→Lambdaの場合も理屈は同じということですね。

第6章 SQS と SNS トピックを使った連携

 最後は本格的、SQSとSNSも使い、メール送信を直列処理でなく並列に同時送信する連携の実例。

  • S3バケットにメール件名と本文が入ったテキストファイルがアップロード。
  • それをトリガーに第1のLambda関数起動、DynamoDBから宛先を取得、メール送信……ではなくてまずはメール送信の命令をSQSのキューに貯める。
  • 5分ごとにSQSをポーリングしている別の第2のLambda関数がそれに気づいてメール送信……でもなくて、10件づつSNSのトピックに同時に通知。
  • このSNSトピックを検知した数だけ、第3のLmabda関数が、Amazon SESを使って10件一気にメール送信、おまけのバウンス処理も。

という、小さな処理をする3種類のLambda関数が連携します。ここでもSQSからの取り出しではべき等が重要になります。

 まずはDynamoDBのテーブル作成から。

  • email, username, haserror, issendという属性を持たせる。haserrorは配信時にエラーがあったか。issendは送信済みかを記録してべき等処理。
  • 後の検索条件で必要になるので、haserrorセカンダリインデックスとして設定。自動的にインデックス名はhaserror-indexとなる。

テストデータや実データのインポート方法は以下があるそうです。

  • S3CSVExcelを置く->検知して登録してくれるLambda関数を作る
  • AWS Data Pipeline という機能を使ってJSONからインポート。管理コンソールのDynamoDBのところにある。
  • AWS CLI を使う。コマンドで > aws dynamodb put-item --table-name xxx --item '{JSON実物}'

aws.amazon.com qiita.com

多分こういう手段があるのだろうなとは思っていたのですが、CLIからだとコマンド1回=1アイテム登録なんですね。
手作業はめんどくさいという事で本書でも、Excelの最初の方の列に実データ記録、後半のセルでその値を自動でとってJSONの中に当てはめた文字列生成、最後のX列でアイテムぶんの登録コマンド実行のテキストが生成される……というテクを紹介しています。このX列分をコピーして貼り付けると aws dynamodb... のコマンド列がたくさん出来上がるという寸法です。

続いてS3SQSへ。

  • メール登録用のS3バケットを新規作成。
  • Lambda関数用にAmazonSQSFullAccessという管理ポリシー準備。
  • SQSのキュー作成は、「キュー名」だけあればとりあえずOK。デッドレターキューは今回設定せず。

  • 第一のLambda関数をつくる。設計図はs3-get-object-...がある。

  • 起動のトリガーで先ほど作ったS3バケットを指定、オブジェクト作成時を指定。
  • トリガーをこう指定すると引数の events['Records'] にリストでS3のイベント情報が渡ってくるので、forで回してバケット名とファイル名を取得。
  • DynamoDBからは属性haserrorが0であるという条件を指定してquery()。この時属性名の他にIndexNameも指定が必要。メールアドレスごとにリストで返ってくるので、ネストしたfor文でまた処理。
  • DynamoDBの対象アイテムは送信済みにupdate_item()していく。
  • SQSの操作は以下のような感じ。
sqs = boto3.resource('sqs');
queue = sqs.get_query_by_name(QueueName='{作ったキュー名}')
queue.send_message(
    MessageBody={メッセージ本体。このサンプルでは宛先メアド},
    MessageAttributes={メッセージ属性。辞書型でデータ型と内容を好きなだけ...}
    )

本書の例ではメッセージ属性にusername, backetname, filename を指定しています。SQSの操作も分かれば簡単でした。
また、DynamoDBのクエリの評価条件は等しいや大小、begins_withbetweencontainsはあるのですがそのぐらい。RDBSQL文だと書ける、左辺右辺にSQL関数を適用したりとかマニアックで高度なことはやはり根本的に出来ないのですね。このへん注意が必要そうです。

次に、5分ごとにこのSQSを見てメール送信の命令を10通ごとに処理する第2のLambda関数作成。たとえ処理しきれなかったキューがあっても次回の起動時に処理……という考えで設計されています。

  • 管理コンソールのSNSの画面でトピック名を指定してCreate topic。ARNは arn:aws:sns:{リージョン名}:{アカウントID}:{トピック名}
    リージョンとアカウントごとにユニークになる。
  • 設計図を元にLambda関数を作成。ルールの新規作成でcron式を書く。
  • Lambda内でのSQSアクセスは以下のような感じ。
sqs = boto3.resource('sqs')
queue = sqs.get_queue_by_name(QueueName='{作ったキュー名}')
n = queue.attributes['ApproximateNumberOfMessages'] # 貯まったキューの数
  • SNSの操作は以下のような感じ。
sns = boto3.resource('sns')
topic = sns.Topic('{トピック名のARN表記}')
topic.publish(Message='{トピックに送りたいメッセージ。ここではSQSに作ったキュー名}')

SNSの操作も他と同様で簡単です。本書ではSNSトピックに通知が来たらメールが来るようにして動作を確認しています。 最後の第3のLambda関数作成が以下。

  • 設計図にsns-message-pythonがあるのでこれを利用。この時ランタイムが古いPython2.6なので注意とのこと。
  • この設定だと引数eventの中に、event['Records'] の中にリストでメッセージが入っているのでfor文で回して処理。メッセージの内容がここではキュー名なのでSQSと繋がる。
  • SQSのキューから最大10件でメッセージを読み取り。
sqs = boto3.resource('sqs')
queue = sqs.get_queue_by_name(QueueName='{作ったキュー名}')
messages = queue.receive_messages(MessageAttributeNames=['All'], MaxNumberOfMessages = 10)
for m in messages:
    xxxx = m.body # メッセージ本文
    yyyy = m.message_attributes.get('{作った属性名}').get('StringValue') #キュー内に自由につけた属性が読み取れる
  • S3バケットからもメールのタイトルと本文を読み取って入れ子のfor文の中でメールを作っていく。
  • 送信処理の前に、DynamoDBの該当アイテムを送信済みにupdate_item()する。
  • メール送信でのSESの操作は以下のような感じ。
client = boto3.client('ses', region_name='{リージョン名}')
client.send_email(
    Source={送信元メアド},
    ReplyToAddress=[{配列でリプライ先}],
    Destination={'ToAddress': [{配列で送信先メアド}]},
    Message={辞書形式でタイトルやメール本文を指定。それぞれごとにキャラセットも指定}
)

ここも順を追って見ていくとコードはそれほど難しくない形でした。
最後にはSESで宛先不明で戻ってきてしまうメール、バウンスメールの処理についても処理例が記されています。バウンスメールがSES到着→SNSへ通知する→このトリガーでLambda関数起動、DynamoDBの対象アイテムを更新する、という流れで同様です。
 重箱の隅をつつくと本書後半のコードの変数名ではS3のバケットbacket となっているのですが、これは bucket であるべきな気がする…!(笑)

 そして付録としてLambda関係のアカウントや実行ロールの作成、AWS CLIの使い方やバージョニングの方法なども豊富なスクショ入りで説明されています。

まとめ:Lambdaの実際の使い方がわかる本

 2017年の本なので多少古くなっているのかな…と思ったのですがそんなこともなく、2021現在でも十分学びになる本でした。言語を問わずプログラミング経験のある方でAWSの主要サービスの概要が分かっている方なら、順を追って読んでいけば比較的すんなりと実際のコードの実物も理解していけると思います。
 イベントトリガーとの対応が分かっていれば大抵の情報は引数のeventから取ってこれるし、AWSの各種サービスの呼び出しはPythonであれば全部Boto3ライブラリで、呼び出し方は大体似たようなものです。本書の題材のような小さな処理を行うちょっとした関数には、Pythonはやはり使い勝手が良いなと感じました。実際のLambda利用でも言語の分布は半分ぐらいがPython、ついでJavaScript(Node.js)でこの2つが圧倒的にシェアを占めているらしいですね。

 本書の前書きで作者さんが「勘所さえ掴めば、Lambdaはとても簡単」と述べているように、とっかかりがよく分かりました。使う予定が控えていたので参考になりました。PythonでLambda完全に理解した...(※フラグ)

AWS Lambda実践ガイド

AWS Lambda実践ガイド

関連書籍

以前上げた『基礎から学ぶ サーバーレス開発』の感想記事に、日本語で読める書籍は列挙してあります。 iwasiman.hatenablog.com

f:id:iwasiman:20210211171139p:plain
LambdaでPython!