This post is written by Joseph Keating, AWS Modernization Architect, and Virginia Chu, Sr. DevSecOps Architect.

Container image support for AWS Lambda enables developers to 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 a typical deployment process for image-based Lambda functions, the container and Lambda function are created or updated in the same process. However, some use cases require developers to create the image first, and then update one or more Lambda functions from that image. In these situations, organizations may mandate that infrastructure components such as Amazon S3 and Amazon Elastic Container Registry (ECR) are centralized and deployed separately from their application deployment pipelines.

This post demonstrates how to use AWS continuous integration and deployment (CI/CD) services and Docker to separate the container build process from the application deployment process.

Overview

There is a sample application that creates two pipelines to deploy a Java application. The first pipeline uses Docker to build and deploy the container image to the Amazon ECR. The second pipeline uses AWS Serverless Application Model (AWS SAM) to deploy a Lambda function based on the container from the first process.

This shows how to build, manage, and deploy Lambda container images automatically with infrastructure as code (IaC). It also covers automatically updating or creating Lambda functions based on a container image version.

Example architecture

Example architecture

The example application uses AWS CloudFormation to configure the AWS Lambda container pipelines. Both pipelines use AWS CodePipeline, AWS CodeBuild, and AWS CodeCommit. The lambda-container-image-deployment-pipeline builds and deploys a container image to ECR. The sam-deployment-pipeline updates or deploys a Lambda function based on the new container image.

The pipeline deploys the sample application:

  1. The developer pushes code to the main branch.
  2. An update to the main branch invokes the pipeline.
  3. The pipeline clones the CodeCommit repository.
  4. Docker builds the container image and assigns tags.
  5. Docker pushes the image to ECR.
  6. The lambda-container-image-pipeline completion triggers an Amazon EventBridge event.
  7. The pipeline clones the CodeCommit repository.
  8. AWS SAM builds the Lambda-based container image application.
  9. AWS SAM deploys the application to AWS Lambda.

Prerequisites

To provision the pipeline deployment, you must have the following prerequisites:

Infrastructure configuration

The pipeline relies on infrastructure elements like AWS Identity and Access Management roles, S3 buckets, and an ECR repository. Due to security and governance considerations, many organizations prefer to keep these infrastructure components separate from their application deployments.

To start, deploy the core infrastructure components using CloudFormation and the AWS CLI:

  1. Create a local directory called BlogDemoRepo and clone the source code repository found in the following location:
    mkdir -p $HOME/BlogDemoRepo
    cd $HOME/BlogDemoRepo
    git clone https://github.com/aws-samples/modernize-deployments-with-container-images-in-lambda
  2. Change directory into the cloned repository:
    cd modernize-deployments-with-container-images-in-lambda/
  3. Deploy the s3-iam-config CloudFormation template, keeping the following CloudFormation template names:
    aws cloudformation create-stack \ --stack-name s3-iam-config \ --template-body file://templates/s3-iam-config.yml \ --parameters file://parameters/s3-iam-config-params.json \ --capabilities CAPABILITY_NAMED_IAM

    The output should look like the following:

    Output example for stack creation

    Output example for stack creation

Application overview

The application uses Docker to build the container image and an ECR repository to store the container image. AWS SAM deploys the Lambda function based on the new container.

The example application in this post uses a Java-based container image using Amazon Corretto. Amazon Corretto is a no-cost, multi-platform, 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 image also consists of the Lambda Runtime Interface Client (RIC) that allows your runtime to send and receive to the Lambda service. Take some time to review the Dockerfile and how it configures the Java application.

Configure the repository

The CodeCommit repository contains all of the configurations the pipelines use to deploy the application. To configure the CodeCommit repository:

  1. Get metadata about the CodeCommit repository created in a previous step. Run the following command from the BlogDemoRepo directory created in a previous step:
    aws codecommit get-repository \ --repository-name DemoRepo \ --query repositoryMetadata.cloneUrlHttp \ --output text

    The output should look like the following:

    Output example for get repository

    Output example for get repository

  2. In your terminal, paste the Git URL from the previous step and clone the repository:
    git clone <insert_url_from_step_1_output>

    You receive a warning because the repository is empty.

    Empty repository warning

    Empty repository warning

  3. Create the main branch:
    cd DemoRepo
    git checkout -b main
  4. Copy all of the code from the cloned GitHub repository to the CodeCommit repository:
    cp -r ../modernize-deployments-with-container-images-in-lambda/* .
  5. Commit and push the changes:
    git add .
    git commit -m "Initial commit"
    git push -u origin main

Pipeline configuration

This example deploys two separate pipelines. The first is called the modernize-deployments-with-container-images-in-lambda, which consists of building and deploying a container-image to ECR using Docker and the AWS CLI. An EventBridge event starts the pipeline when the CodeCommit branch is updated.

The second pipeline, sam-deployment-pipeline, is where the container image built from lambda-container-image-deployment-pipeline is deployed to a Lambda function using AWS SAM. This pipeline is also triggered using an Amazon EventBridge event. Successful completion of the lambda-container-image-deployment-pipeline invokes this second pipeline through Amazon EventBridge.

Both pipelines consist of AWS CodeBuild jobs configured with a buildspec file. The buildspec file enables developers to run bash commands and scripts to build and deploy applications.

Deploy the pipeline

You now configure and deploy the pipelines and test the configured application in the AWS Management Console.

  1. Change directory back to modernize-serverless-deployments-leveraging-lambda-container-images directory and deploy the lambda-container-pipeline CloudFormation Template:
    cd $HOME/BlogDemoRepo/modernize-deployments-with-container-images-in-lambda/
    aws cloudformation create-stack \ --stack-name lambda-container-pipeline \ --template-body file://templates/lambda-container-pipeline.yml \ --parameters file://parameters/lambda-container-params.json  \ --capabilities CAPABILITY_IAM \ --region us-east-1

    The output appears:

    Output example for stack creation

    Output example for stack creation

  2. Wait for the lambda-container-pipeline stack from the previous step to complete and deploy the sam-deployment-pipeline CloudFormation template:
    aws cloudformation create-stack \ --stack-name sam-deployment-pipeline \ --template-body file://templates/sam-deployment-pipeline.yml \ --parameters file://parameters/sam-deployment-params.json  \ --capabilities CAPABILITY_IAM \ --region us-east-1

    The output appears:

    Output example of stack creation

    Output example of stack creation

  3. In the console, select CodePipelinepipelines:

  4. Wait for the status of both pipelines to show Succeeded:
  5. Navigate to the ECR console and choose demo-java. This shows that the pipeline is built and the image is deployed to ECR.
  6. Navigate to the Lambda console and choose the MyCustomLambdaContainer function.
  7. The Image configuration panel shows that the function is configured to use the image created earlier.
  8. To test the function, choose Test.
  9. Keep the default settings and choose Test.

This completes the walkthrough. To further test the workflow, modify the Java application and commit and push your changes to the main branch. You can then review the updated resources you have deployed.

Conclusion

This post shows how to use AWS services to automate the creation of Lambda container images. Using CodePipeline, you create a CI/CD pipeline for updates and deployments of Lambda container-images. You then test the Lambda container-image in the AWS Management Console.

For more serverless content visit Serverless Land.