AWS CLIを使ってLambdaでPythonスクリプトを動かす

投稿日:

更新日:

カテゴリ:

AWS CLIを使ってAWS LambdaでPythonスクリプトを動かしてみましたので、書き残したいと思います。
AWS CLIの設定は以前書いた「IAM Identity Centerで運用管理ユーザのAWS CLIが使えるまで」をご参考ください。

実行ロールを作成

Lambda実行できるようにロールを付けます

まず次のようなawsコマンドを利用してロールを作成します。

aws iam create-role --role-name lambda-ex --assume-role-policy-document '{"Version": "2012-10-17","Statement": [{ "Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}]}'

実行結果は次のようになります。

{
    "Role": {
        "Path": "/",
        "RoleName": "lambda-ex",
        "RoleId": "AROAUNUO7TBJ7ZDKPVKTF",
        "Arn": "arn:aws:iam::123456789012:role/lambda-ex",
        "CreateDate": "2024-01-10T15:26:21+00:00",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "Service": "lambda.amazonaws.com"
                    },
                    "Action": "sts:AssumeRole"
                }
            ]
        }
    }
}

次に以下のコマンドでロールにLambdaのポリシーを付与します。

aws iam attach-role-policy --role-name lambda-ex --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

特にエラーができれば結果は何も表示されません。

Lambda関数を作成

まず、実行するPythonのスクリプトを下記書きます。
次のように簡単な200応答をhello-world.pyとして保存します。

import json

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

次に、下記コマンドhello-world.pyをfuncion.zipとして圧縮します。

zip function.zip hello-world.py

最後に、function.zipで配置しているディレクトリで、次のコマンドを実行してLambdaの関数を作成します。

aws lambda create-function \
	--function-name my-function \
	--zip-file fileb://function.zip \
	--handler hello-world.lambda_handler \
	--runtime python3.11 \
	--role arn:aws:iam::123456789012:role/lambda-ex

実行結果は次のようになると思われます。

{
    "FunctionName": "my-function",
    "FunctionArn": "arn:aws:lambda:ap-northeast-1:123456789012:function:my-function",
    "Runtime": "python3.11",
    "Role": "arn:aws:iam::123456789012:role/lambda-ex",
    "Handler": "hello-world.lambda_handler",
    "CodeSize": 311,
    "Description": "",
    "Timeout": 3,
    "MemorySize": 128,
    "LastModified": "2024-01-10T15:31:03.432+0000",
    "CodeSha256": "UUzgcbLtWmzeQ6r1LRb7njgIEjQuasRtzN8rc/tIktA=",
    "Version": "$LATEST",
    "TracingConfig": {
        "Mode": "PassThrough"
    },
    "RevisionId": "86e16c4b-1b7f-48db-887a-8d5d81997208",
    "State": "Pending",
    "StateReason": "The function is being created.",
    "StateReasonCode": "Creating",
    "PackageType": "Zip",
    "Architectures": [
        "x86_64"
    ],
    "EphemeralStorage": {
        "Size": 512
    },
    "SnapStart": {
        "ApplyOn": "None",
        "OptimizationStatus": "Off"
    },
    "RuntimeVersionConfig": {
        "RuntimeVersionArn": "arn:aws:lambda:ap-northeast-1::runtime:a3304f2b48f740276b97ad9c52a9cc36a0bd9b44fecf74d0f1416aafb74e92fc"
    },
    "LoggingConfig": {
        "LogFormat": "Text",
        "LogGroup": "/aws/lambda/my-function"
    }
}

Lambda関数を実行

次のコマンで上で作ったLambda関数を実行します。

aws lambda invoke --function-name my-function out --log-type Tail

実行結果は次のように表示されます。

{
    "StatusCode": 200,
    "LogResult": "U1RBUlQgUmVxdWVzdElkOiA4MWI2Nj...",
    "ExecutedVersion": "$LATEST"
}

ここのLogResultはBase64でエンコードされますので、以下のコマンドでそれをデコードできます。

aws lambda invoke --function-name my-function out --log-type Tail \
--query 'LogResult' --output text |  base64 -d

そうしますと、実行結果は次のように表示されます。

START RequestId: 3127268e-97e4-4bc7-bffb-40d94604de09 Version: $LATEST
END RequestId: 3127268e-97e4-4bc7-bffb-40d94604de09
REPORT RequestId: 3127268e-97e4-4bc7-bffb-40d94604de09	Duration: 1.19 ms	Billed Duration: 2 ms	Memory Size: 128 MB	Max Memory Used: 41 MB

ちなみに、参考サイト1では、上記--handler hello-world.lambda_handler--handler hello-world.lambda-handlerで書かれてしまったせいで、関数を実行するときに、次のようなエラーになります。

aws lambda invoke --function-name basic-lambda-func out --log-type Tail \
--query 'LogResult' --output text |  base64 -d
# 実行結果:
START RequestId: c5dfa447-8295-4e87-ae99-cca4669bdb9f Version: $LATEST
[ERROR] Runtime.HandlerNotFound: Handler 'lambda-handler' missing on module 'hello-world'
Traceback (most recent call last):END RequestId: c5dfa447-8295-4e87-ae99-cca4669bdb9f
REPORT RequestId: c5dfa447-8295-4e87-ae99-cca4669bdb9f	Duration: 16.69 ms	Billed Duration: 17 ms	Memory Size: 128 MB	Max Memory Used: 41 MB

ですので、もし上記のようなRuntime.HandlerNotFoundが出ましたら、--handlerの引数を確認してみてください。

Lambda関数を更新

何故かログ取れなかったので、前述hello-world.pyをログ出力するに以下のように変えてみます。

import json
import os

def lambda_handler(event, context):
    print('## ENVIRONMENT VARIABLES')
    print(os.environ['AWS_LAMBDA_LOG_GROUP_NAME'])
    print(os.environ['AWS_LAMBDA_LOG_STREAM_NAME'])
    print('## EVENT')
    print(event)

    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

function.zipも同じように再圧縮します。

zip function.zip hello-world.py

Lambda関数のソースコード更新は次のコマンドになります。

aws lambda update-function-code \
	--function-name my-function \
	--zip-file fileb://function.zip

実行結果は次のように表示されます。

{
    "FunctionName": "my-function",
    "FunctionArn": "arn:aws:lambda:ap-northeast-1:123456789012:function:my-function",
    "Runtime": "python3.11",
    "Role": "arn:aws:iam::123456789012:role/lambda-ex",
    "Handler": "hello-world.lambda_handler",
    "CodeSize": 395,
    "Description": "",
    "Timeout": 3,
    "MemorySize": 128,
    "LastModified": "2024-01-10T15:45:13.000+0000",
    "CodeSha256": "ZrphDct4N2aF//kE0tvGJdaEuMCE4QhHQfqQmRxDalU=",
    "Version": "$LATEST",
    "TracingConfig": {
        "Mode": "PassThrough"
    },
    "RevisionId": "e1291a7a-d1b9-463a-95f5-c5e41a617a8a",
    "State": "Active",
    "LastUpdateStatus": "InProgress",
    "LastUpdateStatusReason": "The function is being created.",
    "LastUpdateStatusReasonCode": "Creating",
    "PackageType": "Zip",
    "Architectures": [
        "x86_64"
    ],
    "EphemeralStorage": {
        "Size": 512
    },
    "SnapStart": {
        "ApplyOn": "None",
        "OptimizationStatus": "Off"
    },
    "RuntimeVersionConfig": {
        "RuntimeVersionArn": "arn:aws:lambda:ap-northeast-1::runtime:a3304f2b48f740276b97ad9c52a9cc36a0bd9b44fecf74d0f1416aafb74e92fc"
    },
    "LoggingConfig": {
        "LogFormat": "Text",
        "LogGroup": "/aws/lambda/my-function"
    }
}

そしたら再実行します。

aws lambda invoke --function-name my-function out --log-type Tail \
--query 'LogResult' --output text |  base64 -d

実行結果は次のように変わります。

START RequestId: 98f35feb-a6e0-4304-8ab3-464252eb7c73 Version: $LATEST
## ENVIRONMENT VARIABLES
/aws/lambda/my-function
2024/01/10/[$LATEST]15dc4f14087f4fc0af06c7ea94339025
## EVENT
{}
END RequestId: 98f35feb-a6e0-4304-8ab3-464252eb7c73
REPORT RequestId: 98f35feb-a6e0-4304-8ab3-464252eb7c73	Duration: 1.35 ms	Billed Duration: 2 ms	Memory Size: 128 MB	Max Memory Used: 40 MB	Init Duration: 112.76 ms

それでも、次のようにログは取れませんでした。。まあ、ログは今回の本題じゃないので、一旦スルーします。

aws logs get-log-events --log-group-name /aws/lambda/my-function --log-stream-name $(cat out) --limit 5

# Result:
2024-01-11 00:43:19.778 Python[30707:16337649] CFPropertyListCreateFromXMLData(): Old-style plist parser: missing semicolon or value in dictionary on line 1. Parsing will be abandoned. Break on _CFPropertyListMissingSemicolonOrValue to debug.
2024-01-11 00:43:19.778 Python[30707:16337649] CFPropertyListCreateFromXMLData(): Old-style plist parser: missing semicolon or value in dictionary on line 1. Parsing will be abandoned. Break on _CFPropertyListMissingSemicolonOrValue to debug.

usage: aws [options]   [ ...] [parameters]
To see help text, you can run:

  aws help
  aws  help
  aws   help

Unknown options: body:, \Hello, from, Lambda!\}, 200,

Lambda関数を削除

Lambda関数の削除は次のコマンドになります。

aws lambda delete-function --function-name my-function

正常終了した場合は特に何も表示されないので、削除されたかどうかを確認するには、次のコマンドで関数の一覧を取って確認するといいでしょう。

aws lambda list-functions

関数が1つもない場合は次のように表示されます。

{
    "Functions": []
}

実行ロールを削除

最後にきれいするため、作成したロールも削除したいところですが、何故か参考1や公式には紹介されませんでした。
調べたところ、参考4の順で削除する必要があり、それなりに面倒だったのが紹介されなかった理由かもしれません。

  1. まず次のコマンドでロールを確認します。
    aws iam list-roles

    実行結果はそれになり長くなりますが、該当部分を抜粋すると以下になります。

    ...
            {
                "Path": "/",
                "RoleName": "lambda-ex",
                "RoleId": "AROAUNUO7TBJ7ZDKPVKTF",
                "Arn": "arn:aws:iam::123456789012:role/lambda-ex",
                "CreateDate": "2024-01-10T15:26:21+00:00",
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Principal": {
                                "Service": "lambda.amazonaws.com"
                            },
                            "Action": "sts:AssumeRole"
                        }
                    ]
                },
                "MaxSessionDuration": 3600
            },
    ...
    
  2. 次に該当ロール最後のアクセス詳細を確認します。
    aws iam generate-service-last-accessed-details --arn arn:aws:iam::123456789012:role/lambda-ex # このarnは1つ前の実行結果にある"Arn"で置き換えてください
    

    実行結果は次のようになります。

    {
        "JobId": "58c67a0b-fae7-585d-6b68-0e3608342811"
    }
  3. そしたら、このジョブの詳細を確認します。
    aws iam get-service-last-accessed-details --job-id 58c67a0b-fae7-585d-6b68-0e3608342811 # このjob-idは1つ前の実行結果にある"JobId"で置き換えてください

    実行結果は次のようになります。

    {
        "JobStatus": "COMPLETED",
        "JobType": "SERVICE_LEVEL",
        "JobCreationDate": "2024-01-10T15:57:40.174000+00:00",
        "ServicesLastAccessed": [
            {
                "ServiceName": "Amazon CloudWatch Logs",
                "LastAuthenticated": "2024-01-10T15:46:18+00:00",
                "ServiceNamespace": "logs",
                "LastAuthenticatedEntity": "arn:aws:iam::123456789012:role/lambda-ex",
                "LastAuthenticatedRegion": "ap-northeast-1",
                "TotalAuthenticatedEntities": 1
            }
        ],
        "JobCompletionDate": "2024-01-10T15:57:43.088000+00:00",
        "IsTruncated": false
    }
    

    CloudWatch Logsが使ってましたとのことですが、、何故かログ確認できなかったんですよね。。

  4. 参考サイトには、次のようなインスタンスプロファイルの確認がありましたが、私の環境では該当するものはありませんでした。
    aws iam list-instance-profiles-for-role --role-name lambda-ex

    実行結果は次のようになります。

    
    {
        "InstanceProfiles": []
    }
  5. 次のコマンドでロールに付与したポリシーを取得します。
    aws iam list-attached-role-policies --role-name lambda-ex

    実行結果は次のようになります。

    {
        "AttachedPolicies": [
            {
                "PolicyName": "AWSLambdaBasicExecutionRole",
                "PolicyArn": "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
            }
        ]
    }
  6. 次のコマンドでロールに付与したポリシーを削除します。
    aws iam detach-role-policy --role-name lambda-ex --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

    実行結果は何も表示されません。

  7. 最後に次のコマンドを実行してロールを削除します。
    aws iam delete-role --role-name lambda-ex

    特にエラーにならなければ、実行結果はありません。

    ちなみに、前述のポリシーを削除しないで直接delete-roleを実行すると、次のようなエラー応答が返ってきます。

    An error occurred (DeleteConflict) when calling the DeleteRole operation: Cannot delete entity, must detach all policies first.
    

    このエラーメッセージを見る限り、付与されてポリシーさえ削除してあげれば、ロールを削除できるかもしれません。

参考

  1. How to create and manage functions in Lambda with AWS CLI
  2. Using Lambda with the AWS CLI
  3. AWS Lambda function logging in Python
  4. How to delete an IAM Role using AWS CLI

投稿日

カテゴリー:

投稿者:

タグ:

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です