AWS Lambda Layers with Serverless
AWS Lambda Layers was announced during 2018’s re:Invent as a new way bundle dependencies into functions. It allows us to include libraries, binaries and even runtimes into Lambdas.
Without Layers, dependencies need to be bundled together with the function code, inside the .zip
file that is pushed to Amazon servers. This results on large deployment packages and a slow development pipeline. Some dependencies can’t even be bundled with ease, since they exceed Lambda’s current 50 MB package size limit.
Layers allows us to package and deploy dependencies independently from our functions. Every Layer also gets an unique identifier that can be shared and re-used between other Lambdas.
This tutorial shows how to publish a function and a Layer using the Serverless Framework.
Creating a Screenshot service with Chromium and Puppeteer
Let’s see how we can deploy a Lambda Function that receives an URL, takes a screenshot of the page and returns it. Puppeteer will be the library of choice to handle page loading and screenshots. Since Puppeteer relies on a compiled version of Chromium to deal with pages, we also need to provide it as a dependency by using Layers.
Tip: The process for including other prebuilt binaries - such as FFmpeg or Imagemagick - should be very similar.
Setting up the project
First, let’s create an empty repository and add the project files:
Run the commands below to install the dependencies needed:
Tip: The
pupeteer
npm package downloads Chromium by default when installed. This would result in a huge deployment package. Since we’ll be providing the Chromium binary via Layer we can only installpuppeteer-core
, which doesn’t include Chromium. See more on puppeteer vs. puppeteer-core.
Tip: If you are using a global installation of
serverless
, make sure the version is higher than v1.34.0 (when support for Layers was added)
Downloading Chromium
Now let’s add Chromium to the project. For convenience, let’s grab one of the prebuilt binaries from the serverless-chrome
repository here.
Download the file, extract the binary and add it to the layer
folder:
Tip: You can add the
layer
folder (or whatever you call it) to your.gitignore
and avoid pushing large files to your Git server.
After following these steps you should end up with this structure on your project:
.
├── handler.js
├── layer
│ └── headless-chromium
├── package.json
├── serverless.yml
└── yarn.lock
Adding code and configuration
Now let’s add code to our files. Below is an example of how your serverless.yml
configuration should look like.
Note that we have a new top-level property called layers
. It contains the path to the folder where we store our dependencies - in this case, Chromium’s prebuilt binary.
To attach the Layer to our function, we can simply reference it on the function declaration and it will be available during the function execution.
On handler.js
we add the Puppeteer code to screenshot a page:
Note that, because we are using puppeteer-core
, we need to provide the path where the Chromium binary is hosted using the executablePath
option.
Another important thing about Layers is that they extract the dependencies on the /opt
folder during the function execution.
Deploying the function
At this point we are ready to deploy our function and the Layer containing the Chromium binary. Just run the command below in your terminal:
The output will look like this:
Here we can see that the Layer and the function code got split into two separate .zip
files and were uploaded independently.
The Layer ARN is also present on the output:
layers:
chromium: arn:aws:lambda:us-east-1:372768542448:layer:chromium:8
If we ever need to use Chromium on any other function we can simply reference this Layer’s ARN on the AWS Dashboard.
Tip: You can also publish the Layer without any function with Serverless. Just remove the
functions
section on yourserverless.yml
and run the deployment command normally.
To test the function just visit the url:
And you will see the screenshot:
Conclusion
Layers is a very welcome addition to the AWS Lambda toolset. Bundling dependencies on Lambdas used to be a difficult task, specially for large binaries. Now with Layers it became easier to manage, share and keep dependencies updated.
Serverless also provides a very simple and straightforward way to use and deploy Lambda Layers to AWS.