Open3

AWS Lambda学習記録

MasaHeroMasaHero

Lambdaを学ぶ目的

  • 10年使われているサービスで、今後も使われていきそう
  • 小さいプロダクトを作るところからAWSを学べる気がする
  • 汎用性が高いサービスだから、これを学ぶと汎用性が上がりそう
  • サーバレスアプリケーションに興味ある

参考資料

AWS Lambda とは - AWS Lambda

Lambdaを使用するタイミング

上記資料から引用

  • ファイル処理: Amazon Simple Storage Service (Amazon S3) を使用して、アップロード後に Lambda データ処理をリアルタイムでトリガーします。
  • ストリーム処理: Lambda と Amazon Kinesis を使用して、アプリケーションアクティビティの追跡、取引注文の処理、クリックストリーム分析、データクレンジング、ログのフィルタリング、インデックス作成、ソーシャルメディア分析、モノのインターネット (IoT) デバイスデータのテレメトリ、および計測のためにリアルタイムのストリーミングデータを処理します。
  • ウェブアプリケーション: Lambda と他の AWS サービスを組み合わせて、自動的にスケールアップおよびスケールダウンし、複数のデータセンターにまたがる高可用性設定で実行される強力なウェブアプリケーションを構築します。
  • IoT バックエンド: Lambda を使用してサーバーレスバックエンドを構築し、ウェブ、モバイル、IoT、およびサードパーティの API リクエストを処理します。
  • モバイルバックエンド: Lambda と Amazon API Gateway を使用してバックエンドを構築し、API リクエストを認証して処理します。AWS Amplify を使用すると、iOS、Android、ウェブ、React Native フロントエンドと簡単に統合できます。

最初のLambda関数を作成する

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/getting-started.html

やったこと

  • 関数を作成
  • ブラウザ上のエディタでコード編集とデプロイ
  • テスト用のラムダのトリガイベントを作成と実行

MasaHeroMasaHero

コンテナイメージのデプロイ

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/python-image.html

ランタイムインターフェイスクライアントで代替ベースイメージを使用する

例となったDockerfileがマルチステージビルドの教材としてとても参考になった。

# グローバルスコープでの定義
# 定義されたARGは各ステージで自動的に共有されない
ARG FUNCTION_DIR="/function"

# ステージ1:build-image
# このステージは依存関係のインストール用のステージ
FROM python:3.12 AS build-image

# ARGを再度宣言
ARG FUNCTION_DIR

RUN mkdir -p ${FUNCTION_DIR}
COPY . ${FUNCTION_DIR}

# 指定されたディレクトリ (${FUNCTION_DIR}) にインストール
RUN pip install --target ${FUNCTION_DIR} awslambdaric

# ステージ2:最終イメージ 
FROM python:3.12-slim

# ARGを再度宣言
ARG FUNCTION_DIR
WORKDIR ${FUNCTION_DIR}

# ステージ1からコピーさせる
COPY --from=build-image ${FUNCTION_DIR} ${FUNCTION_DIR}

# ENTRYPOINTはコンテナ起動時必ず実行される
ENTRYPOINT [ "/usr/local/bin/python", "-m", "awslambdaric" ]

# CMDはENTRYPOINTへ引数として渡される
# 最終的には下記が実行される
# /usr/local/bin/python -m awslambdaric lambda_function.handler
CMD [ "lambda_function.handler" ]

CMDとENTRYPOINTの違いを理解した。
Docker Best Practices: Choosing Between RUN, CMD, and ENTRYPOINT | Docker

MasaHeroMasaHero

Python の Lambda 関数ハンドラーの定義

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/python-handler.html

def handler_name(event, context): 
    ...
    return some_value
  • デフォルトはlambda_function.pyのlambda_handler
  • ファイル名やハンドラー名を変える場合は編集が必要

引数

event

  • イベントオブジェクト:JSON形式ドキュメント

下記のような構造をしている。
Pythonだと辞書で取得すれば良さそう

{
  "TemperatureK": 281,
  "WindKmh": -3,
  "HumidityPct": 0.55,
  "PressureHPa": 1020
}
{
  "Records": [
    {
      "Sns": {
        "Timestamp": "2019-01-02T12:45:07.000Z",
        "Signature": "tcc6faL2yUC6dgZdmrwh1Y4cGa/ebXEkAi6RibDsvpi+tE/1+82j...65r==",
        "MessageId": "95df01b4-ee98-5cb9-9903-4c221d41eb5e",
        "Message": "Hello from SNS!",
        ...

context

ランタイムから渡されるオブジェクト

Lambda コンテキストオブジェクトを使用して Python 関数の情報を取得する - AWS Lambda

import time

def lambda_handler(event, context):   
    print("Lambda function ARN:", context.invoked_function_arn)
    print("CloudWatch log stream name:", context.log_stream_name)
    print("CloudWatch log group name:",  context.log_group_name)
    print("Lambda Request ID:", context.aws_request_id)
    print("Lambda function memory limits in MB:", context.memory_limit_in_mb)
    # We have added a 1 second delay so you can see the time remaining in get_remaining_time_in_millis.
    time.sleep(1) 
    print("Lambda time remaining in MS:", context.get_remaining_time_in_millis())

ベストプラクティス

  • コアロジックと分けること
    • 1つの巨大なlambda_handlerにしないこと
  • 再帰呼び出ししないこと
  • 冪等性にすること