前回は代替ベースイメージからの作成を試した。
今回は、公式イメージを使って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オブジェクトの読み書き