Lambda Layers – The Dependency Resolver
In our search for faster deployment times for our serverless solutions, we came across the idea of Lambda Layers, a way to help install dependencies once for several functions. But before we dive into Lambda Layers, let’s take a quick look at AWS Lambda functions.
Lambda Layers play a significant role in serverless architectures, particularly in enhancing AWS Lambda’s functionality. A Lambda Layer is a ZIP archive that contains libraries, custom runtimes, or other dependencies. These layers can be used with Lambda functions to easily manage and update common components across multiple functions without the need for duplication.
Why Use Lambda Layers?
When using Lambda functions as the main compute power of a certain product most people don’t want to handle different dependency trees for different lambdas, so what they do is just install all the dependencies that they would need for a specific lambda. That is where Lambda layers come in, as they allow for a much faster deployment time in addition to being able to share dependencies between different services
Main purposes and benefits of Lambda Layers:
- Code reusability and management: Lambda Layers allow developers to separate their function code from its dependencies. Common libraries or custom runtimes can be placed in a layer, which multiple Lambda functions can then reference. This separation simplifies code updates and management, as changes to the layer are automatically propagated to all functions using it.
- Simplified deployment: By using layers, the deployment package size of Lambda functions can be significantly reduced. This is because the dependencies are not included in each function’s deployment package but are instead referenced from the layer. Smaller deployment packages can lead to faster deployment times.
- Version control: Layers are versioned, allowing developers to control which version of a layer their functions are using. If a new version of a layer is published, functions can continue to use the old version until they are explicitly updated. This provides stability and control over the function’s runtime environment.
- Shared components across teams: Layers can be shared across different AWS accounts, enabling teams to use common components without having to duplicate efforts. This promotes collaboration and consistency in large-scale applications.
- Optimized resource utilization: Since layers are stored separately and can be shared among multiple functions, they help in optimizing storage and memory usage. This efficiency is particularly beneficial in serverless architectures where resource utilization directly impacts cost.
Types of Lambda Layers
Lambda Layers in AWS Lambda serve as a versatile feature, allowing the inclusion of various components that are essential for Lambda functions but are not necessarily part of the function’s core logic. Broadly, these layers can be categorized into three types: library dependencies, custom runtimes, and shared configurations. Each type addresses specific use cases within AWS Lambda:
- Library Dependencies:
- Overview: Library dependencies are one of the most common uses of Lambda Layers. These layers include external libraries or frameworks that your Lambda function depends on. Instead of bundling these dependencies with your function’s deployment package, you can place them in a separate layer.
- Use Case: This approach is particularly beneficial for languages that require a set of external libraries, like Python or Node.js. By keeping these libraries in a layer, you can easily share and manage common dependencies across multiple Lambda functions. It also keeps your Lambda function packages small and manageable.
- Custom Runtimes:
- Overview: AWS Lambda supports a limited set of runtime environments natively (e.g., Python, Node.js, Java). Custom runtime layers allow you to run your function in an environment that is not natively supported by AWS Lambda.
- Use Case: If you need to run your Lambda function in a specific language or version not natively supported by AWS Lambda, you can use a custom runtime layer. This layer includes everything required to interpret or compile your code, such as language interpreters or specific binaries. It is particularly useful for using newer language versions or entirely different languages.
- Shared Configurations:
- Overview: Shared configuration layers are used to store configuration files that multiple Lambda functions can reference. This might include database connection strings, external API keys, or other configuration data.
- Use Case: By using shared configuration layers, you can centralize and manage configurations for multiple Lambda functions. This is especially useful for maintaining consistency across various functions and simplifying the process of updating configuration data. Instead of updating each function individually, you update the layer, and all referencing functions get the updated configuration.
Each type of Lambda Layer addresses specific aspects of building and maintaining serverless applications on AWS:
- Library Dependencies simplify code management and reduce the size of deployment packages.
- Custom Runtimes extend the flexibility of AWS Lambda, allowing the use of a wide range of programming languages and runtime versions.
- Shared Configurations enhance maintainability and consistency, providing a central place to manage shared configuration data.
Creating a Lambda Layer with CDK TypeScript
There are many ways to deploy said resources onto different cloud providers such as AWS, Azure or GCP, In CDK there are several ways to generate a Lambda layer that we could use. Here is how we are going to generate the stack:
```typescript
import * as cdk from '@aws-cdk/core';
import * as lambda from '@aws-cdk/aws-lambda';
export class LambdaDemoStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Layer for the requests library
const layer = new lambda.LayerVersion(this, 'RequestsLayer', {
code: lambda.Code.fromAsset('lambda-layer'),
compatibleRuntimes: [lambda.Runtime.PYTHON_3_8],
description: 'A layer for the requests library',
});
// Python Lambda function that uses the RequestsLayer
const pythonLambda = new lambda.Function(this, 'PythonLambda', {
runtime: lambda.Runtime.PYTHON_3_8,
handler: 'lambda_function.lambda_handler',
code: lambda.Code.fromAsset('lambda'),
layers: [layer], // Attach the layer
});
}
}
In this example, we use `lambda.Code.fromAsset()`, which is one of the functions that we can use to generate a Lambda layer.
The AWS CDK’s `aws_lambda.Code` class provides different methods for defining the source of your Lambda function’s code:
- fromAsset(path: string): Specifies that the Lambda code will be uploaded from a local file path or directory.
- fromAssetImage(directory: string, props?: AssetImageCodeProps): Uses a Docker image asset as the Lambda code. The Docker container’s /asset-output directory is used.
- fromBucket(bucket: IBucket, key: string, objectVersion?: string): Uses a file from an S3 bucket as the Lambda code.
- fromDockerBuild(path: string, options?: DockerBuildOptions): Builds a Docker image from a local directory and uses the image for the Lambda function.
- fromEcrImage(repository: IRepository, props: EcrImageCodeProps): Uses a Docker image stored in an Amazon ECR repository.
Conclusion
Lambda Layers represent a powerful and flexible feature within AWS Lambda, offering significant benefits in terms of code management, deployment efficiency, and resource optimization. By effectively utilizing Lambda Layers, developers can not only simplify the complexity of serverless application architectures but also lower the amount of management needed for their applications. As serverless computing continues to evolve, mastering Lambda Layers will undoubtedly be a valuable skill for any developer looking to leverage AWS Lambda to its fullest potential.