0
0

s3にJSON読み書きを行うaws lambda に docker imageを cdkでデプロイしたメモ

Posted at

前回は代替ベースイメージからの作成を試した。
今回は、公式イメージを使ってS3へつないでファイルの読み書きを行うことをテストする。
ソース

ディレクトリイメージ

.
├─cdk
│ ├── bin
│ │   └── python-docker-lambda-s3.ts
│ ├── lib
│ │   └── python-docker-lambda-s3-stack.ts
│ └ package.json
└─python-lambda-project
  ├── s3Data
  │   └── test.json
  └─ s3
      ├── Dockerfile
      ├── lambda_function.py # lambdaで実行したいコード
      └── requirements.txt # 使用するライブラリ

Hello world

久しぶりなのでまずはHello Worldを行った。
ソース

python-lambda-project/s3/lambda_function.py
import sys
import os
def handler(event, context):
    return 'Hello ' + os.environ.get("TEST", "default") +' from AWS Lambda using Python' + sys.version + '!'
python-lambda-project/s3/Dockerfile
FROM public.ecr.aws/lambda/python:3.11
COPY requirements.txt ${LAMBDA_TASK_ROOT}
RUN pip install -r requirements.txt
COPY lambda_function.py ${LAMBDA_TASK_ROOT}
CMD [ "lambda_function.handler" ]
python-lambda-project/s3/lambda_function.py
import sys
import os
def handler(event, context):
    return 'Hello ' + os.environ.get("TEST", "default") +' from AWS Lambda using Python' + sys.version + '!'
cdk/lib/python-docker-lambda-s3-stack.ts
import { Aspects, Duration, Stack, StackProps, Tag, Tags } from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';

interface PythonDockerLambdaS3StackProps extends StackProps {}

export class PythonDockerLambdaS3Stack extends Stack {
  constructor(scope: Construct, id: string, props: PythonDockerLambdaS3StackProps) {
    super(scope, id, props);

    new lambda.DockerImageFunction(this,'AssetFunction',
      {
        code: lambda.DockerImageCode.fromImageAsset('../python-lambda-project/s3/'),
        environment: { TEST: 'test' }
      },
    );
  }
}
cdk/bin/python-docker-lambda-s3.bin
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { PythonDockerLambdaS3Stack } from '../lib/python-docker-lambda-s3-stack';

const env = {account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION};
const app = new cdk.App();
new PythonDockerLambdaS3Stack(app, 'PythonDockerLambdaS3Stack', { env });
cdk/package.json
{
  "name": "cdk",
  "scripts": {
    "docker-lambda-s3": "cdk -a \"npx ts-node --prefer-ts-exts bin/python-docker-lambda-s3.ts\" deploy PythonDockerLambdaS3Stack --profile produser"
  }
}

デプロイ

cd cdk && npm run docker-lambda-s3

実行結果

AWSのコンソール上から、テスト実行。
実行結果は以下。

"Hello test from AWS Lambda using Python3.11.6 (main, Nov 16 2023, 11:06:00) [GCC 7.3.1 20180712 (Red Hat 7.3.1-17)]!"

S3に読み書きできるようにする。

アップロードするJSONは以下にした。

python-lambda-project/s3Data/test.json
{
  "test": "test data",
  "version": 1.1,
  "descritpion": "テスト用データ",
  "other": null
}

CDK修正

cdk/lib/python-docker-lambda-s3-stack.ts
import {Aspects,Duration,RemovalPolicy,Stack,StackProps,Tag,Tags,} from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import {BlockPublicAccess,Bucket,BucketAccessControl,} from 'aws-cdk-lib/aws-s3';
import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment';
import { Construct } from 'constructs';

interface PythonDockerLambdaS3StackProps extends StackProps {
+  projectDirectory: string;
}

export class PythonDockerLambdaS3Stack extends Stack {
  constructor(scope: Construct,id: string,props: PythonDockerLambdaS3StackProps,) {
    super(scope, id, props);
+    const bucket = new Bucket(this, 'Bucket', {
+      removalPolicy: RemovalPolicy.DESTROY,
+      autoDeleteObjects: true,
+    });
+    new BucketDeployment(this, 'DeployFiles', {
+      destinationBucket: bucket,
+      sources: [Source.asset(`${props.projectDirectory}/s3Data/`)],
+    });

    const helloImageFunction = new lambda.DockerImageFunction(this,'AssetFunction',
      {
        code: lambda.DockerImageCode.fromImageAsset(
          `${props.projectDirectory}/s3/`,
        ),
+       environment: { S3_BUCKET_NAME: bucket.bucketName },
      },
    );
+    bucket.grantReadWrite(helloImageFunction);
  }
}

cdk/bin/python-docker-lambda-s3.ts
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { PythonDockerLambdaS3Stack } from '../lib/python-docker-lambda-s3-stack';

const env = {
  account: process.env.CDK_DEFAULT_ACCOUNT,
  region: process.env.CDK_DEFAULT_REGION,
};
const app = new cdk.App();
new PythonDockerLambdaS3Stack(app, 'PythonDockerLambdaS3Stack', {
  env,
+  projectDirectory: '../python-lambda-project',
});

コード修正

python-lambda-project/s3/lambda_function.py
import sys
import os
import json
import boto3

def handler(event, context):
    bucket_name = os.environ.get("S3_BUCKET_NAME")
    s3_client = boto3.client('s3')
    s3_object = s3_client.get_object(Bucket=bucket_name, Key='test.json')
    json_data = s3_object['Body'].read()
    data = json.loads(json_data)
    data['test'] = 'world'
    s3_client.put_object(Bucket=bucket_name, Key='test2.json', Body=json.dumps(data))
    return 'Hello ' + data['test']
python-lambda-project/s3/requirements.txt
boto3[crt]

実行結果

AWSのコンソールからlambdaをテスト実行。
S3にtest2.jsonが作成されていることを確認。
ダウンロードすると下記になる。
文字コードの問題で、日本語が変換されてしまった模様。
今回は、ファイルの読み書きを確認のため、この問題の解決まではしない。

{
  "test": "world",
  "version": 1.1,
  "descritpion": "\u30c6\u30b9\u30c8\u7528\u30c7\u30fc\u30bf",
  "other": null
}

余談

pythoのバージョンが上がって、参照するライブラリのパスや優先順位が少し変わったもよう。

version ランタイム pip 優先順位
3.11 /var/lang/lib/python3.11/site-packages /var/lang/lib/python3.11/site-packages /var/runtimeより/var/lang/libを優先
3.7-3.10 /var/runtime /var/lang/lib/python3.x/site-packages /var/lang/libより/var/runtimeを優先

参考

公式 - python-image
CDK - DockerImageFunction
boto3
Python(boto3)でS3にデータをファイル保存せず直接アップロードする方法
boto3でファイルの読み書き
Boto3のS3オブジェクトの読み書き

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0