octochat-awsのLambda関数を直接terminalから動かしてみた #reinvent

DOP322-SセッションでDEMOに使われたアプリケーションのLambda Functionを直接動かしてみました。
2019.12.11

はじめに

DOP322-S - Continuous delivery to AWS with GitHub Actionsで用いられたDEMOアプリのLambda関数を直接動作させてみました。

[レポート]Github ActionsによるAWSの継続的デリバリ #DOP322-S #reinvent

一部手直しの必要な箇所があったため、forkした下記リポジトリに追加しています。

haoyayoi/octochat-aws

以下、実際に動かすための手順と修正内容です。

ソースコードの準備

DEMOアプリ全体をcloneした後で、スクリプトにてIAMロール作成・DynamoDB作成・Lambda関数作成を行います。事前に、Lambda関数として用いるパッケージをアップするためのバケットが一つ必要になります。

git clone git@github.com:haoyayoi/octochat-aws.git
cd octochat-aws/functions
pipenv install --python 3.7
pipenv shell
pipenv install awscli
export AWS_S3_BUCKET=${BUCKET_NAME}
aws s3 mb s3://${AWS_S3_BUCKET} #バケット作成
script/bootstrap.sh
script/pack_lambda .
script/push_lambda message_add package.zip
script/push_lambda messages_received_list package.zip
script/push_lambda messages_sent_list package.zip

追加した修正

DEMO用リポジトリのファイルはポリシー用JSONファイルのフォーマットエラーと、特定リージョンの決め打ちが入っており、それらを修正する必要があります。

github-developer/octochat-aws

ポリシーフォーマットの修正

bootstrap.shを実行すると、以下のエラーが発生します。

% script/bootstrap.sh
Creating lambda-default role...
An error occurred (MalformedPolicyDocument) when calling the PutRolePolicy operation: The policy failed legacy parsing

lambda-full-access-policy.jsonの1行目が空改行となっているため、削除します。

% vim .aws/lambda-full-access-policy.json
-
{
   "Version": "2012-10-17",

再実行します。

% ./script/bootstrap.sh
Creating Messages table...
{
    "TableDescription": {
        "AttributeDefinitions": [
            {
                "AttributeName": "fromId",
                "AttributeType": "N"
            },
            {
                "AttributeName": "receivedAt",
                "AttributeType": "N"
            },
            {
                "AttributeName": "toId",
                "AttributeType": "N"
            }
        ],
        "TableName": "Messages",
        "KeySchema": [
            {
                "AttributeName": "toId",
                "KeyType": "HASH"
            },
            {
                "AttributeName": "receivedAt",
                "KeyType": "RANGE"
            }
        ],
        "TableStatus": "CREATING",
        "CreationDateTime": 1575974698.814,
        "ProvisionedThroughput": {
            "NumberOfDecreasesToday": 0,
            "ReadCapacityUnits": 1,
            "WriteCapacityUnits": 1
        },
        "TableSizeBytes": 0,
        "ItemCount": 0,
        "TableArn": "arn:aws:dynamodb:ap-northeast-1:XXXXXXXXXXXX:table/Messages",
        "TableId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
        "GlobalSecondaryIndexes": [
            {
                "IndexName": "SentMessages",
                "KeySchema": [
                    {
                        "AttributeName": "fromId",
                        "KeyType": "HASH"
                    },
                    {
                        "AttributeName": "receivedAt",
                        "KeyType": "RANGE"
                    }
                ],
                "Projection": {
                    "ProjectionType": "ALL"
                },
                "IndexStatus": "CREATING",
                "ProvisionedThroughput": {
                    "NumberOfDecreasesToday": 0,
                    "ReadCapacityUnits": 1,
                    "WriteCapacityUnits": 1
                },
                "IndexSizeBytes": 0,
                "ItemCount": 0,
                "IndexArn": "arn:aws:dynamodb:ap-northeast-1:XXXXXXXXXXXX:table/Messages/index/SentMessages"
            }
        ]
    }
}

リージョンの決め打ち解除

以下のPythonスクリプトに対して修正を入れます。

  • message_add.py
  • messages_received_list.py
  • messages_sent_list.py
 def handler(event, context):
-    dynamodb = boto3.resource("dynamodb", region_name="eu-west-1")
+    dynamodb = boto3.resource("dynamodb")

生成されるリソース

IAMロール

lambda-defaultのIAMロールが生成されます。すでに存在する場合はポリシーが追加されます。

% aws iam get-role --role-name lambda-default
{
    "Role": {
        "Description": "Lambda execution role",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": "sts:AssumeRole",
                    "Effect": "Allow",
                    "Principal": {
                        "Service": "lambda.amazonaws.com"
                    }
                }
            ]
        },
        "MaxSessionDuration": 3600,
        "RoleId": "XXXXXXXXXXXXXXXXXXX",
        "CreateDate": "2019-12-10T10:38:48Z",
        "RoleName": "lambda-default",
        "Path": "/",
        "Arn": "arn:aws:iam::XXXXXXXXXXXX:role/lambda-default"
    }
}

DynamoDB Table

Messagesテーブルが生成されます。すでに存在する場合は作成されません。

% aws dynamodb describe-table --table-name Messages
{
    "Table": {
        "TableArn": "arn:aws:dynamodb:ap-northeast-1:XXXXXXXXXXXX:table/Messages",
        "AttributeDefinitions": [
            {
                "AttributeName": "fromId",
                "AttributeType": "N"
            },
            {
                "AttributeName": "receivedAt",
                "AttributeType": "N"
            },
            {
                "AttributeName": "toId",
                "AttributeType": "N"
            }
        ],
        "GlobalSecondaryIndexes": [
            {
                "IndexSizeBytes": 0,
                "IndexName": "SentMessages",
                "Projection": {
                    "ProjectionType": "ALL"
                },
                "ProvisionedThroughput": {
                    "NumberOfDecreasesToday": 0,
                    "WriteCapacityUnits": 1,
                    "ReadCapacityUnits": 1
                },
                "IndexStatus": "ACTIVE",
                "KeySchema": [
                    {
                        "KeyType": "HASH",
                        "AttributeName": "fromId"
                    },
                    {
                        "KeyType": "RANGE",
                        "AttributeName": "receivedAt"
                    }
                ],
                "IndexArn": "arn:aws:dynamodb:ap-northeast-1:XXXXXXXXXXXX:table/Messages/index/SentMessages",
                "ItemCount": 0
            }
        ],
        "ProvisionedThroughput": {
            "NumberOfDecreasesToday": 0,
            "WriteCapacityUnits": 1,
            "ReadCapacityUnits": 1
        },
        "TableSizeBytes": 0,
        "TableName": "Messages",
        "TableStatus": "ACTIVE",
        "TableId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
        "KeySchema": [
            {
                "KeyType": "HASH",
                "AttributeName": "toId"
            },
            {
                "KeyType": "RANGE",
                "AttributeName": "receivedAt"
            }
        ],
        "ItemCount": 0,
        "CreationDateTime": 1575974698.814
    }
}

Lambda関数

以下3つの関数となります。

  • message_add
  • messages_received_list
  • messages

message_add

% aws lambda get-function --function-name message_add
{
    "Code": {
        "RepositoryType": "S3",
        "Location": "https://awslambda-ap-ne-1-tasks.s3.ap-northeast-1.amazonaws.com/snapshots/....
    },
    "Configuration": {
        "TracingConfig": {
            "Mode": "PassThrough"
        },
        "Version": "$LATEST",
        "CodeSha256": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        "FunctionName": "message_add",
        "MemorySize": 128,
        "RevisionId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
        "CodeSize": 29399523,
        "FunctionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:message_add",
        "Handler": "message_add.handler",
        "Role": "arn:aws:iam::XXXXXXXXXXXX:role/lambda-default",
        "Timeout": 3,
        "LastModified": "2019-12-11T04:42:44.340+0000",
        "Runtime": "python3.7",
        "Description": ""
    }
}

messages_received_list

% aws lambda get-function --function-name messages_received_list
{
    "Code": {
        "RepositoryType": "S3",
        "Location": "https://awslambda-ap-ne-1-tasks.s3.ap-northeast-1.amazonaws.com/snapshots/...
    },
    "Configuration": {
        "TracingConfig": {
            "Mode": "PassThrough"
        },
        "Version": "$LATEST",
        "CodeSha256": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        "FunctionName": "messages_received_list",
        "MemorySize": 128,
        "RevisionId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
        "CodeSize": 29399523,
        "FunctionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:messages_received_list",
        "Handler": "messages_received_list.handler",
        "Role": "arn:aws:iam::XXXXXXXXXXXX:role/lambda-default",
        "Timeout": 3,
        "LastModified": "2019-12-11T04:43:07.340+0000",
        "Runtime": "python3.7",
        "Description": ""
    }
}

messages_sent_list

% aws lambda get-function --function-name messages_sent_list
{
    "Code": {
        "RepositoryType": "S3",
        "Location": "https://awslambda-ap-ne-1-tasks.s3.ap-northeast-1.amazonaws.com/snapshots/...
    },
    "Configuration": {
        "TracingConfig": {
            "Mode": "PassThrough"
        },
        "Version": "$LATEST",
        "CodeSha256": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        "FunctionName": "messages_sent_list",
        "MemorySize": 128,
        "RevisionId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
        "CodeSize": 29399523,
        "FunctionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:messages_sent_list",
        "Handler": "messages_sent_list.handler",
        "Role": "arn:aws:iam::XXXXXXXXXXXX:role/lambda-default",
        "Timeout": 3,
        "LastModified": "2019-12-11T04:43:42.376+0000",
        "Runtime": "python3.7",
        "Description": ""
    }
}

実際に操作してみる

リポジトリにあるサンプル操作を実行してみます。

メッセージの送信

% script/exec_lambda message_add '{"toId": 2993937, "to": "imjohnbo", "fromId": 27806, "from": "swinton", "message": "Hello, John, how are you?"}'
true

メッセージの受信

% script/exec_lambda messages_received_list '{"toId": 2993937}'
{"data": [{"receivedAt": 1576039472.0, "fromId": 27806.0, "message": "Hello, John, how are you?", "toId": 2993937.0, "to": "imjohnbo", "from": "swinton"}]}

送信したメッセージ

% script/exec_lambda messages_sent_list '{"fromId": 27806}'
{"data": [{"receivedAt": 1576039472.0, "fromId": 27806.0, "message": "Hello, John, how are you?", "toId": 2993937.0, "to": "imjohnbo", "from": "swinton"}]}

あとがき

octochat-awsリポジトリ内を確認していたところ、Lambda関数の実装が含まれているディレクトリを見つけ、単独起動にも対応していたので試したものの、製作者自身の環境で動かす前提になっていたというものでした。

Lambda関数をバッチ処理で更新する手続き等で参考になる点が多かったので、興味のある方は試してみて下さい。