Deploy .NET Lambda Functions As Containers

In this article, we will create a lambda function (dotnet core 3.1) and deploy it to AWS as a docker container. In December 2020 re:Invent AWS announced container support in lambda functions. It will help customers who have container tooling in place for their development workflows. Lambda will support container images up to 10 GB in size. AWS provides base images for Lambda development. 
 
We will be using dotnet CLI for creating, building and deploying lambda function. Amazon.Lambda.Templates nuget package provides templates to create lambda functions.
 
To install, lambda templates run dotnetnew-iAmazon.Lambda.Templates. Check installation of templates by running dotnet new -all command which will display a list of templates.

Deploy .NET Lambda Functions As Containers
 
Lets us create lambda function which will be triggered for S3 file upload event. We will use lambda.S3 templete to create function.
  1. dotnet new lambda.S3 --name s3Listener  
Open project folder in VS Code. You will see src and test folders created for lambda function. src folder will have Function.cs file. It contains a function handler which will get s3 file metadat from event object.
 
Deploy .NET Lambda Functions As Containers
 
We are going to deploy lambda function as container, hence we have to build docker image out of lambda code. To create image of lambda function, I will add Docker file to src folder. We will use public.ecr.aws/lambda/dotnet:core3.1 image as base image. Base images contain the Amazon Linux Base operating system, the runtime for a programming language, dependencies and the Lambda Runtime Interface Client (RIC), which implements the Lambda Runtime API.
 
For building and publishing lambda code artefacts, we will use mcr.microsoft.com/dotnet/sdk:3.1 image from microsoft repository. On successful build and publish steps, we will copy publish output to execution directory of labda i. e. var/task. Finally we will CMD to function handler path i. r. project name::namespace.class name::function name. 
  1. FROM public.ecr.aws/lambda/dotnet:core3.1 AS base  
  2.   
  3. FROM mcr.microsoft.com/dotnet/sdk:3.1 as build  
  4. WORKDIR /src  
  5. COPY ["s3Listener.csproj""base/"]  
  6. RUN dotnet restore "base/s3Listener.csproj"  
  7.   
  8. WORKDIR "/src"  
  9. COPY . .  
  10. RUN dotnet build "s3Listener.csproj" --configuration Release --output /app/build  
  11.   
  12. FROM build AS publish  
  13. RUN dotnet publish "s3Listener.csproj" \  
  14.             --configuration Release \   
  15.             --runtime linux-x64 \  
  16.             --self-contained false \   
  17.             --output /app/publish \  
  18.             -p:PublishReadyToRun=true    
  19.   
  20. FROM base AS final  
  21. WORKDIR /var/task  
  22. COPY --from=publish /app/publish .  
  23. CMD ["s3Listener::s3Listener.Function::FunctionHandler"]  
Build and Test
 
Let us build image using docker and run that image to test. Lambda functionality will be exposed over port 8080 which we will map to 9000, the host port. We will pass additional parameters as environment variables. It is required because we are creating S3 client in our code which will not be available in locally running container.
  1. docker build -t s3listener .  
  2. docker run -p 9000:8080 s3listener -e AWS_REGION="us-east-1" -e AWS_ACCESS_KEY_ID="AKIA***JNL" -e AWS_SECRET_ACCESS_KEY="FfDlcqZ7************"  
Open another command prompt instance. Run the following command to invoke lambda function. We are passing s3 event as data parameter, which contains s3 file metadata. 
  1. curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations"   
  2. -d '{ "Records":   
  3.         [{  
  4.             "s3":   
  5.             {  
  6.                 "bucket": { "name""example-bucket" },                                 
  7.                 "object": { "key""test/key" }        
  8.             }      
  9.         }]  
  10.     }'  
Deploy
 
If you see desired output while tesing, let us deploy the function to AWS environment. Before deploying add image as package type in aws-lambda-tools-defaults.json file. It will be used by lambda deployment command to get deployment parameters. 
Deploy .NET Lambda Functions As Containers
  1. dotnet lambda deploy-function s3listener --function-role lambda-s3Listener  
Command will,
  • Build docker image.
  • Create ECR repo and upload image to that repo.
  • Create lambda function using an image uri.
Great! We have deployed .Net core based lambda function to AWS as container. I will discuss more scenarios and solutions using AWS services in upcoming articles, until then stay tuned! :)