The AWS Lambda service is one of the most used services by AWS customers. It is used to build event-driven and serverless architecture applications. Lambda supports various languages such as Java, Python, and NodeJS. Choosing the right language and managing the dependency is critical, as it may affect the size of the package, and eventually, the load time of the function when starting instances.
AWS Lambda Layers is one of the best ways to reduce the size of the deployment package. You can use Lambda layers for custom runtimes, libraries, and other dependencies.
In this article, we’ll review the AWS Lambda framework packaging, how Lambda Layers work, and best practices for Lambda Layers.
A Lambda function consists of the compiled code, a script, and the dependencies it needs to run the code. To deploy this code to the AWS cloud, you need to ZIP it. This is called a deployment package.
You can upload the package directly to Lambda if the deployment package size is less than 50 MB. If it’s bigger, you first have to upload the package to Amazon S3 and then deploy it to the Lambda service.
The problem with deployment packages is that over time, they will keep adding more and more dependencies to the code, which causes maintenance overhead. With every small change in a dependency’s code, the function’s code has to be changed, re-packaged, and tested.
Another issue is that the more code you write, the more shared code will be developed and may be used across several functions. AWS introduced Lambda Layers to enable more easily sharing that code.
Lambda Layers provides a mechanism to externally package dependencies that can be shared across multiple Lambda functions. This allows Lambda functions to reuse code that was already written. The benefit of Lambda Layers is reducing the number of lines of code and the size of application artifacts.
A Lambda function can use up to five layers. The maximum size of the total unzipped function and all layers is 250 MB. You need to be mindful of AWS Limits, which occasionally change to accommodate new requirements.
When a Lambda function (with a Lambda Layer) is invoked, AWS downloads the specified layers and extracts them to the /opt directory on the execution environment of the Function instance. Each runtime then looks for a language-specific (NodeJS, Java, Python, etc..) folder under the /opt directory.
You can create and upload your own Lambda layers and publish it for sharing with others. You can implement an AWS managed layer such as SciPi, or you can grab a third-party layer from an APN Partner or other reliable sources. Below is a typical workflow for a Lambda layer:
Image source: AWS
Each Function will have one or more runtime dependencies that can be moved out of the Function code by placing them in a Lambda layer. To include libraries in a layer, place them in one of the folders supported by your runtime, or modify that path variable for your language.
Node.js – nodejs/node_modules, nodejs/node8/node_modules (NODE_PATH)
Lambda runtimes ensure to include /opt directory in paths so that your function code has access to libs that are included in Lambda layers.
AWS provides Identity and Access Management (IAM) to manage the access to Functions and Layers. Layer usage permissions are managed on the resource. To configure a function with a layer, you need AWS Lambda permission to call GetLayerVersion on the layer version. You can get this permission by configuring your user policy or from the Function’s resource-based policy. A Lambda layer can be added to another account as well by providing permission on your user policy. Also, the owner of the other account must grant your account permission with a resource-based policy.
Below is a command add-layer-version-permission that is used to add the layer usage permission:
aws lambda add-layer-version-permission --layer-name log-sdk-nodejs --statement-id xaccount --action lambda:GetLayerVersion --principal 110927634125 --version-number 1 --output text
Permission is provided at layer version level so you have to repeat this step for each time you add a new version for the layer.
AWS SAM and its CLI is used to replicate the Lambda service environment in local and enable testing before moving the code to AWS cloud. To enable the Lambda layers support, it downloads all the configured layers and cache them in the local environment. You can use the –layer-cache-basedir flag to specify the target directory to store the local cache of the layer.
Downloading of layers happens when the first time you run either sam local invoke or sam local start-lambda or sam local start-api commands. To refresh the layer cache, you can use the –force-image-build flag.
The AWS::Serverless::LayerVersion resource type is used in the SAM template file to create a layer version that you can reference from your function configuration.
Below is an example of a SAM template for a NodeJS application that is using plain-nodejs-lib library as a layer.
AWSTemplateFormatVersion: '2010-09-09' Transform: 'AWS::Serverless-2016-10-31' Description: An AWS Lambda application for XRay demo. Resources: function: Type: AWS::Serverless::Function Properties: Handler: index.handler Runtime: nodejs12.x CodeUri: function/. Description: Call the AWS Lambda API for XRay demo Timeout: 5 # Function's execution role Policies: - AWSLambdaBasicExecutionRole - AWSLambdaReadOnlyAccess - AWSXrayWriteOnlyAccess Tracing: Active Layers: - !Ref libs libs: Type: AWS::Serverless::LayerVersion Properties: LayerName: plain-nodejs-lib Description: Dependencies for the plain nodejs app. ContentUri: lib/. CompatibleRuntimes: - nodejs12.x
Though, Lambda layers play a great role to distribute your code and share with others, there are few things to keep in mind:
In this article, we looked into the role of AWS Lambda layers in building Lambda Function code. We also talked about its features, how to enable it, secure it and apply it using SAM CLI. There are few things we need to keep in mind that this feature has to be used only in special circumstances that we discussed in this article else it may bring overhead in the maintenance of the Function code.