Context
I'm able to deploy to AWS lambda using Docker and CDK.
Here is what I did:
I have a Java package TestLambda
. I use docker build -t test-lambda .
there to build the docker image.
FROM public.ecr.aws/lambda/java:11
# /var/task should only contains *.class files
#COPY build/classes/java/main ${LAMBDA_TASK_ROOT}
# Always use /var/task/lib for dependencies
COPY build/dependency/* ${LAMBDA_TASK_ROOT}/lib/
COPY src/main/resources/log4j2.xml ${LAMBDA_TASK_ROOT}
ARG jarFile=TestLambda-0.0.1.jar
# Looks
COPY build/libs/${jarFile} ${LAMBDA_TASK_ROOT}/lib/
RUN cd ${LAMBDA_TASK_ROOT} && jar -xf ${LAMBDA_TASK_ROOT}/lib/${jarFile}
# Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)
CMD [ "com.mywebsite.TestLambda::handle" ]
I have a CDK package where I defined Lambda Stack:
export interface LambdaStackProps extends cdk.StackProps {
readonly env : cdk.Environment
}
export class LambdaStack extends cdk.Stack {
// Make it public so that can be binded to Api Gateway
public readonly testLambda : lambda.Function;
constructor(scope: cdk.App, id: string, props: LambdaStackProps) {
super(scope, id, props);
this.testLambda = this.createLambda();
}
private createLambda() {
// Configure path to Dockerfile
const dockerfile = path.join(__dirname, "../../TestLambda/");
// Because here it uses Asset,
// need run cdk bootstrap aws://<AwsAccountId>/us-east-1
return new lambda.DockerImageFunction(this, 'TestLambdaHandler', {
functionName: 'TestLambdaHandler',
description: 'Lambda that render presigned url for S3 bucket.',
code: lambda.DockerImageCode.fromImageAsset(dockerfile),
timeout: cdk.Duration.minutes(2),
memorySize: 512,
role: this.createLambdaExecutionRole(),
tracing: lambda.Tracing.ACTIVE,
});
}
private createLambdaExecutionRole() {
return new iam.Role(this, "TestLambdaHandlerRole", {
description: "Execution role for TestLambdaHandler.",
assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
inlinePolicies: {
"TestLambdaHandlerRoleInlinePolicies" : new iam.PolicyDocument(
{
statements : [
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
resources: ["*"],
actions: [
"s3:Create*",
"s3:List*",
"s3:Set*",
"s3:Put*",
"s3:Get*",
]
}),
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
resources: ["*"],
actions: [
"logs:Get*", "logs:Describe*", "logs:Create*", "logs:Put*"
]
})
]
}
)
}
});
}
}
With the above code, I'm able to upload the docker image and deploy to AWS Lambda with commandcdk deploy LambdaStack
.
My question
Above code works for one Java Lambda function. And now I want add more Java functions to my Java package, and use the CDK package to deploy the docker image as a whole.
How can I do that?
As you can see in my Dockerfile, there is a line CMD [ "com.mywebsite.TestLambda::handle" ]
specified the function that should be run, and Dockerfile can only have one CMD.
I tried to add another CMD for my new function and make the Dockerfile looks like:
CMD [ "com.mywebsite.GetS3PresignedUrl::handleRequest" ]
CMD [ "com.mywebsite.activity.Test::handleRequest" ]
Of course, I also updated the TypeScript CDK package to add corresponding code for the second lambda function. Basically a copy of my above code.
After deployment, I see two AWS lambda functions. But both lambda functions call com.mywebsite.activity.Test::handleRequest
. As mentioned here, "If you list more than one CMD
then only the last CMD
will take effect."
I want the single docker image to hold all my Lambda functions, how can I do that?
CodePudding user response:
Use the lambda.Function
construct insead. It allows you to reuse a docker asset and override the handler. Remove the CMD
entries from the Dockerfile.
const my_code = lambda.DockerImageCode.fromImageAsset(dockerfile);
const my_lambda = new lambda.Function(this, 'TestLambdaHandler', {
functionName: 'TestLambdaHandler',
description: 'Lambda that render presigned url for S3 bucket.',
code: my_code,
handler: 'com.mywebsite.activity.Test::handleRequest',
runtime: lambda.Runtime.FROM_IMAGE,
timeout: cdk.Duration.minutes(2),
memorySize: 512,
role: this.createLambdaExecutionRole(),
tracing: lambda.Tracing.ACTIVE,
});