Why Use AWS Lambda Layers? Advantages and Considerations

I'm originally a .NET developer, and the breadth and depth of this framework are impressive. You probably know the phrase, "When all you have is a hammer, everything looks like a nail." Nevertheless, although I wrote a few articles about .NET-based Lambda function, this time, I decided to leave the hammer aside and look for another tool to serve the purpose.

Background

Choosing Python was an easy choice; it is simple to program, has many prebuilt libraries, and is supported well by the AWS Lambda function. So, this challenge is accepted!

Here's the background for the problem I wanted to solve:

Our product uses an external system that sends messages to our server, but sometimes a message is dropped. This inconsistency may reveal a bigger problem, so the goal was to raise an alert whenever a message hasn't arrived. Simple.

So, I wrote a Python script that compares the outgoing messages (from the external system) to the incoming messages (our Elasticsearch DB). I tested this script locally when the ultimate goal was to run it on our AWS environment. AWS Lambda is perfect for running Python-based scripts. 

This article describes the journey for having a working AWS Lambda function based on Lambda layers.

First Hurdle: Connecting to Elasticsearch

Our data is stored on Elasticsearch, so I used the Python library to query our data and find this inconsistency. I thought it shouldn't be a problem until I ran the script for the first time and received the following error:

"The client noticed that the server is not Elasticsearch and we do not support this unknown product"

If you faced this problem too, you might not use the traditional Elastichsearch engine but its variant. In my case, I was using OpenSearch, a fork of Elasticsearch. Since the official Elasticsearch Python client checks for product compatibility, it rejected the connection to non-Elasticsearch servers.

It can be fixed by changing your library; instead of importing the Elasticsearch library, import OpenSearch.

Python
 
pip install opensearch-py

#and in the Python script - import OpenSearch instead of Elasticsearch library

#from elasticsearch import Elasticsearch 
from opensearchpy import OpenSearch


Besides the OpenSearch library, I also needed to install and import additional libraries for my sophisticated script:

To summarize, I wrote a Python script that worked perfectly fine on my workstation. The next step was running the same logic on the AWS environment. 

Second Hurdle: Python Packages in AWS Lambda Function

When I loaded the script to AWS, things went wrong.

First, I copied the Python libraries using my Lambda function; I downloaded them locally, for example:

Plain Text
 
pip install opensearch-py -t python/my-packages/


Then, I tried to run the Lambda function but received an error:

Plain Text
 
AttributeError: module 'requests' has no attribute 'get'


All the packages (e.g., requests, opensearch-py, etc.) were placed directly in the Lambda function's working folder, which led to namespace collisions and issues during import. When Python attempts to resolve imports, it may incorrectly reference your working folder as a module. 

Diving deeper into this problem, I understood Python mistakenly treats the local folder as the library and tries to resolve the method get() from it.

To isolate the problem, I disabled the code for my REST requests and tried to test the connection to Elasticsearch. A similar error occurred when running a method call for the opensearch:

Plain Text
 
ImportError: cannot import name 'OpenSearch' from 'opensearchpy'


To solve that problem, I could have changed the structure of the Python packages under the working directory. Nevertheless, I chose to move the Python libraries and place them elsewhere to better manage the packages, their version, and the dependencies.

In other words, I used Lambda layers.

The Solution: Using Layers

Why?

First, you can write a perfectly working AWS Lambda function without using Layers at all. Using external Python libraries, you can package them into your Lambda function by zipping the packages as part of the code. 

However, layers with Python provide several advantages that enhance code modularity, reusability, and deployment efficiency. Layers are considered cross-function additional resources, managed separately under the Lambda service.  

Lambda layers in Python streamline development, promote best practices, and simplify dependency management, making them a powerful tool for serverless application design.

Here's a summary of the key benefits:

1. Code Reusability: Sharing Across Multiple Functions

2. Reduced Deployment Package Size: Improve Simplicity and Cost Saving

3. Faster Iteration

4. Consistency Across Functions

5. Improved Development Workflow and Collaboration

6. Support for Complex Dependencies

7. Simplified Version Management

Why Use AWS Lambda Layers? Advantages and Considerations

In general, the usage of layers increases when multiple Lambda functions use the same Python libraries or shared code. Nevertheless, I suggest using layers even if you have only a few Lambda functions as you set the foundations for future growth. With that, you keep layers modular and can focus only on specific functionality.

Setting the Layers' Priority

After loading the layers, you can associate them with your Lambda function. The merge order is a valuable feature for building the Lambda function. Layers are applied in a stacked order of priority, determining how files from multiple layers and the Lambda function's deployment package interact. Here's how Lambda resolves files and directories when using layers:

Function Deployment Package Takes the Highest Priority

The Last-Applied Layer Has a Higher Priority

File System Union

Practical Implications of Using Layers

1. Overriding Dependencies

2. Custom Logic Overriding Layer Files

3. Debugging Conflicts

Layer Priority in Execution

When the Lambda function runs:

  1. AWS Lambda combines files from all layers and the deployment package into the /opt directory and the root file system.
  2. The Lambda environment resolves file paths based on the priority stack mentioned above:
    • Files from the deployment package override files from /opt.
    • Files from the last-added layer in /opt override earlier layers.

Best Practices for Managing Layer Priority

1. Separate Concerns

2. Version Control

3. Minimize Overlap

4. Test Layer Integration

By understanding the layer priority and resolution process, you can effectively design and manage Lambda functions to ensure predictable behavior and seamless integration of dependencies. Let me know if you'd like further clarification! 

Building Python Packages

Download the package's file locally if you want to use a pre-built Python package as a layer. You can specify the requested version for this package, but it's not mandatory. 

Python
 
pip install <package-name>==<version> --target <local-folder>

## for example:
pip install requests==2.32 --target c:\temp


Once you obtain the files locally, place them in a folder hierarchy. The Python layer should have the following structure: 

Python
 
├── <package-folder-name>/
│	├────── python/             
│	 	├────── lib/
│  			├────── python3/
│  				├────── site-packages/
│ 					└────── <package-content>


Do not overlook the Python version in the folder name (i.e. python3.0), which must align with your Lambda function's Python version. For instance:

Why Use AWS Lambda Layers? Advantages and Considerations

After creating this hierarchy with the Python package's files, you only need to zip and load it as a Lambda layer.

Here's how I copied the opensearch Python package locally:

Python
 
mkdir opensearch_layer

cd opensearch_layer

mkdir -p python/lib/python3.10/site-packages
pip install opensearch-py -t python/lib/python3.10/site-packages/
zip -r opensearch_layer.zip python


Since my Lambda function was based on Python3.10, I named the python folder accordingly. With that, you can create your own Python packages locally and load them as layers to your Lambda environment.

Wrapping Up

Lambda Layers make managing shared code and dependencies across multiple Lambda functions easy, keeping things organized and straightforward. By separating common libraries or utilities, layers help reduce the size of your deployment packages and make updates quicker — no need to redeploy your entire function to change a dependency. 

This not only saves time but also keeps your functions consistent and reusable. With Lambda Layers, building and maintaining serverless applications becomes smoother and more efficient, leaving you more time to focus on creating great solutions.

I hope you find this content valuable.  

Keep on coding!

 

 

 

 

Top