AWS Open Source Blog
Simplify development using AWS Lambda container image with a Serverless Framework
Container image support for AWS Lambda lets developers package function code and dependencies using familiar patterns and tools. With this pattern, developers use standard tools like Docker to package their functions as container images and deploy them to Lambda.
In this post, we demonstrate how to use open source tools and AWS continuous integration and deployment (CI/CD) services to deploy Lambda-based container images to AWS. Using Terraform, Serverless Framework, and Docker, you will deploy a CI/CD pipeline for deploying Lambda functions as container images. After going through this exercise, you will understand how to configure AWS services and open source tools to manage and update your container image-based Lambda functions.
Solution overview
There is a Java sample application that is deployed by the pipeline. The pipeline uses Docker to build and deploy the container image to the Amazon Elastic Container Registry (Amazon ECR). Next, Serverless versions and deploys the application to Lambda.
The below image shows how to build, version, and deploy Lambda container images with infrastructure as code (IaC) using the Serverless Framework. It also covers automatically updating or creating Lambda functions based on a container image version.
The pipeline deploys the sample application:
- The developer pushes code to the main branch.
- An update to the main branch invokes the pipeline.
- The pipeline clones the AWS CodeCommit repository.
- Docker builds the container image and assigns tags.
- Docker pushes the image to Amazon ECR.
- Serverless deploys the application to AWS Lambda.
- The application is running in AWS Lambda.
Prerequisites
To provision the pipeline deployment, you must have the following prerequisites:
- An AWS account with local credentials properly configured (typically under
~/.aws/credentials
). - An AWS Identity and Access Management (IAM) role, or user configured with administrative access.
- An IAM user with Git credentials.
- The latest version of the AWS Command Line Interface (AWS CLI). For more information, refer to the documentation for installing, updating, and uninstalling the AWS CLI.
- A Git client to clone the source code provided.
- A Bash shell.
Application overview
The application uses Docker to build the container image. The container image is stored and version controlled in an Amazon ECR repository. Finally, the Serverless Framework deploys the Lambda function based on the new container. The Serverless Framework is a command-line tool that use YAML syntax to deploy both your code and cloud infrastructure needed for serverless applications.
The example application in this post uses a Java-based container image using Amazon Corretto, which is a no-cost, multiplatform, production-ready Open Java Development Kit (OpenJDK).
The Lambda container image base includes the Amazon Linux operating system, and a set of base dependencies. The app uses the Lambda runtime interface client that allows your runtime to send and receive to the Lambda service. Take some time to review the Docker file and how it configures the Java application.
The solution
A container image file is required as a runtime environment for the Python application. Once the container image is built, the image will be stored and version controlled by an Amazon ECR repository. As the application changes, the different container images can be push or pull from the repository.
The pipeline you deploy uses the following AWS services: AWS Lambda container image, Amazon ECR repository, AWS CodePipeline, AWS CodeDeploy, AWS CodeCommit, and AWS Lambda. The pipeline configuration, IAM roles, and all other necessary infrastructure components of the solution are deployed using Terraform. Docker builds, tags, and deploys the Lambda container image to the AWS Cloud. Serverless deploys the Lambda container image living in ECR to Lambda. Additionally, Serverless versions the function so any updates to the Lambda application will be properly versioned and applied to the function.
The Terraform code is structured using modules for reusability and work spaces for different environments. Two Terraform modules are created for this solution. The first module, aws-s3-iam-roles, consists of the core infrastructure that the pipeline requires. This includes IAM roles, Amazon Simple Storage Service (Amazon S3) bucket, Amazon ECR, and CodeCommit repository. The second module, aws-codepipeline, includes the CodePipeline configuration. Here, a CodeDeploy job, lambda-container-code-build-project, is declared that includes all of the commands to build and deploy the Lambda container image.
Deployment:
You now configure and deploy the pipeline and test the configured application:
1. Create a local directory called DemoBuildRepo and clone the source code repository:
mkdir -p $HOME/DemoBuildRepo/
cd $HOME/DemoBuildRepo/
git clone https://github.com/aws-samples/simplify-development-lambda-container-image-serverless-framework.git
2. Change directory into the terraform directory:
cd $HOME/DemoBuildRepo/simplify-development-lambda-container-image-serverless-framework/terraform/
3. Preview the changes you are about to deploy:
make plan
4. Deploy the AWS Services:
make apply
5. Get URL of the CodeCommit repository you just created:
aws codecommit get-repository \
--repository-name DemoRepoLambda \
--query repositoryMetadata.cloneUrlHttp \
--output text
The output should look like the following:
https://git-codecommit.us-east-1.amazonaws.com/v1/repos/DemoRepoLambda
6. Clone the AWS CodeCommit repository:
git clone https://git-codecommit.us-east-1.amazonaws.com/v1/repos/DemoRepoLambda $HOME/DemoBuildRepo/DemoRepoLambda
The output should look like the following:
Cloning into '/Users/UserName/DemoBuildRepo/DemoRepoLambda'...
Username for 'https://git-codecommit.us-east-1.amazonaws.com (https://git-codecommit.us-east-1.amazonaws.com/)': username-at-1234567890
Password for 'https://username-at-1234567890@git-codecommit.us-east-1.amazonaws.com (https://username-at-1234567890@git-codecommit.us-east-1.amazonaws.com/)':
warning: You appear to have cloned an empty repository.
7. Configure the CodeCommit repository:
make configure-repo
The output should look like the following:
INFO: Copy code from repository simplify-development-lambda-container-image-serverless-framework after GIT clone command to local
Switched to a new branch 'main'
drwxr-xr-x 0 user group 0 Jan 15 20:22 codepipeline/
-rw-r--r-- 0 user group 507 Jan 15 20:22 codepipeline/buildspec.yml
-rw-r--r-- 0 user group 1625 Jan 15 20:22 codepipeline/version.sh
-rw-r--r-- 0 user group 6 Jan 15 20:22 codepipeline/version.txt
drwxr-xr-x 0 user group 0 Jan 15 20:22 java/
-rw-r--r-- 0 user group 1511 Jan 15 20:22 java/Dockerfile
-rw-r--r-- 0 user group 2750 Jan 15 20:22 java/pom.xml
-rw-r--r-- 0 user group 1285 Jan 15 20:22 java/README.md
drwxr-xr-x 0 user group 0 Jan 15 20:22 java/src/
drwxr-xr-x 0 user group 0 Jan 15 20:22 java/src/main/
drwxr-xr-x 0 user group 0 Jan 15 20:22 java/src/main/java/
drwxr-xr-x 0 user group 0 Jan 15 20:22 java/src/main/java/com/
drwxr-xr-x 0 user group 0 Jan 15 20:22 java/src/main/java/com/example/
drwxr-xr-x 0 user group 0 Jan 15 20:22 java/src/main/java/com/example/aws/
drwxr-xr-x 0 user group 0 Jan 15 20:22 java/src/main/java/com/example/aws/containerdemo/
-rw-r--r-- 0 user group 2069 Jan 15 20:22 java/src/main/java/com/example/aws/containerdemo/App.java
-rw-r--r-- 0 user group 1213 Jan 15 20:22 serverless.yml
drwxr-xr-x 0 user group 0 Jan 15 20:22 templates/
-rw-r--r-- 0 user group 14628 Jan 15 20:22 templates/s3-iam-config.yml
-rw-r--r-- 0 user group 7148 Jan 15 20:22 templates/lambda-container-pipeline.yml
-rw-r--r-- 0 user group 2791 Jan 15 20:22 templates/kms.yml
8. Upload the changes to the CodeCommit repository to trigger the pipeline:
make upload
9. In the AWS Management Console, open CodePipeline → Pipelines:
10. Wait for the Most recent execution status to change to Succeeded:
11. Back in your terminal, test the deployed application by running the following command:
aws lambda invoke \
--function-name container-image-demo-dev-app \
response.json
The output should look like the following:
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
12. In the previous step, you created a file called response.json with the Lambda function’s invocation, open the file to see the successful results of invoking the application. The output should look like the following:
{"statusCode":200,"headers":{"X-Custom-Header":"application/json","Content-Type":"application/json"},"body":"{ \"message\": \"hello world\", \"location\": \"java-lambda-container\" }"}%
You successfully deployed the application. Take some time to review the configuration. In the next section, you will clean up the deployed resource.
Clean up
1. Get the S3 bucket name using Terraform outputs:
terraform output aws-s3-iam-roles-s3-bucket-output
The output should look like the following:
"terraform-20220117005941604100000001"
2. Update bucket_name with the output from the previous step and run the following command to empty the S3 bucket:
aws s3 rm s3://<bucket_name> --recursive
The output should look like the following:
delete: s3://terraform-20220117005943104100000001/lambda-container-pip/source_out/BEuoCWQ
delete: s3://terraform-20220117005943104100000001/serverless/container-image-demo/dev/1642384518284-2022-01-17T01:55:18.284Z/compiled-cloudformation-template.json
delete: s3://terraform-20220117005943104100000001/lambda-container-pip/source_out/jKdSizO
delete: s3://terraform-20220117005943104100000001/serverless/container-image-demo/dev/1642383860672-2022-01-17T01:44:20.672Z/compiled-cloudformation-template.json
delete: s3://terraform-20220117005943104100000001/serverless/container-image-demo/dev/1642381712918-2022-01-17T01:08:32.918Z/compiled-cloudformation-template.json
delete: s3://terraform-20220117005943104100000001/lambda-container-pip/source_out/Z0tvMwP
3. Delete all of the deployed infrastructure:
terraform destroy --auto-approve
The command will result in a great deal of output. The final result should look like the following:
Destroy complete! Resources: 48 destroyed.
Conclusion
This post demonstrated how to use AWS services and open source tools to automate the creation of Lambda container images. Using CodePipeline, you created a CI/CD pipeline for updates and deployments of Lambda container images. You then verified a successful pipeline deployment by testing the Lambda container image application.