Borislav Hadzhiev
Sat Sep 18 2021·5 min read
Photo by Sam Barber
In this article we will create a node.js lambda function with 2 layers using AWS CLI.
The layers consist of:
date-fns
Before creating the lambda function, we must create a role for it. The role
needs to have a trust policy
that allows the lambda service to assume it.
Save the following json
into a trust-policy.json
file:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
Open your terminal in the directory where you stored the trust-policy.json
file and pass it to the create-role
command:
aws iam aws iam create-role --role-name lambda-layers-role --assume-role-policy-document file://trust-policy.json
role arn
into a notepad because we'll need it when creating the lambda function.Next, attach a policy to the role, which grants permissions to log to cloudwatch:
aws iam attach-role-policy --role-name lambda-layers-role --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Now that we have the role, let's create the node.js
lambda function, create an
index.js
file with the following code:
const {format} = require('date-fns'); const {double} = require('calc'); exports.handler = async event => { const response = { statusCode: 200, body: JSON.stringify({ today: format(new Date(), "'Today is a' eeee"), doubled: double(15), }), }; return response; };
The function imports the layers and uses them to form the response.
Let's zip
the lambda function code so we can create it using the CLI:
zip -r9 lambda.zip index.js
And finally, let's create the function using the AWS CLI, open your terminal in
the directory where you stored the lambda.zip
file and run the
create-function
command:
aws lambda create-function --function-name layers-function --runtime nodejs14.x --zip-file fileb://lambda.zip --handler index.handler --role "arn:aws:iam::YOUR_ACCOUNT_NUMBER:role/lambda-layers-role"
At this point we've created the node.js
function, however we haven't packaged
and deployed the layers it makes use of.
The directory paths for the layers are kind of tricky because lambda expects a specific folder structure.
Create the following folders and files in the directory where you stored the
lambda's index.js
file:
layers calc nodejs node_modules calc.js date-fns nodejs package.json index.js
If you get confused about the folder structure, check out the github repository.
Let's take care of the calc
layer first. Open the calc.js
file and enter the
following code in it:
exports.double = (number) => { return number * 2; }
The file exports a utility function that we can include as a layer and reuse in multiple lambda functions.
node_modules
is added to .gitignore
, since we are storing a helper function, in the node_modules
directory and not a 3rd party package, make sure to exclude the file from your .gitignore
, e.g. by adding the following line to your .gitignore
- !layers/calc/**/node_modules
.Now let's take care of the layer that imports a 3rd party package. Open your
terminal in the layers/date-fns/nodejs
directory and run the following
commands:
# in the layers/date-fns/nodejs directory npm init -y npm install date-fns@2.24.0
Your folder structure should look like:
At this point we are ready to zip
the code for the layers, create them and add
them to the lambda function.
Let's zip the code for the calc
layer first, open your terminal in the
layers/calc
directory and run the zip
command:
# in the layers/calc directory zip -r9 calc-layer.zip .
To create the calc
layer use the publish-layer-version
command from the
/layers/calc
directory:
aws lambda publish-layer-version --layer-name calc-layer --description "added double fn" --zip-file fileb://calc-layer.zip --compatible-runtimes nodejs10.x nodejs12.x nodejs14.x
LayerVersionArn
property in a notepad because we will need it when attaching the layer to the lambda function. The LayerVersionArn
will look something like: "arn:aws:lambda:YOUR_REGION:YOUR_ACCOUNT_ID:layer:calc-layer:1"
Let's also zip and publish the date-fns
layer. Open your terminal in the
layers/date-fns
directory and run the zip
command:
# in the layers/date-fns directory zip -r9 date-fns-layer.zip .
To create the date-fns
layer, open your terminal in the layers/date-fns
directory and run the publish-layer-version
command:
# in the layers/date-fns directory aws lambda publish-layer-version --layer-name date-fns-layer --description "add date-fns library" --zip-file fileb://date-fns-layer.zip --compatible-runtimes nodejs10.x nodejs12.x nodejs14.x
LayerVersionArn
property in a notepad because we will need it when attaching the layer to the lambda function. The LayerVersionArn
will look something like: "arn:aws:lambda:YOUR_REGION:YOUR_ACCOUNT_ID:layer:date-fns-layer:1"
At this point, we've created the layers and all we have to do is attach the layers to the lambda function.
We'll need the LayerVerionArn
s for both of the layers. In case you didn't copy
the LayerVersionArn
s, run the following commands to retrieve them:
aws lambda list-layer-versions --layer-name calc-layer --query "LayerVersions[*].LayerVersionArn" aws lambda list-layer-versions --layer-name date-fns-layer --query "LayerVersions[*].LayerVersionArn"
The command returns a list of all the LayerVersionArn
s of a layer, just pick
the latest version if you have multiple.
Finally, let's add the layers to the lambda function and test if everything works as expected.
Run the update-function-configuration
command, setting the --layers
parameter as our space-separated LayerVersionArn
s.
aws lambda update-function-configuration --function-name layers-function --layers "CALC_LAYER_VERSION_ARN" "DATE_FNS_LAYER_VERSION_ARN"
Let's test if everything works as expected, invoke the lambda function, storing
the response in a response.json
file:
aws lambda invoke --function-name layers-function response.json
The lambda function's response shows that the layers work as expected.
update-function-configuration
command, which we used to attach the layers to the function simply replaces existing function's layers (if any), with the new layers we specified.To be on the safe side, we can list the existing function's layers and include
the ARNs in the update-function-configuration
command.
To list the function's layers, run the get-function-configuration
command:
aws lambda get-function-configuration --function-name layers-function --query "{layers: Layers, revisionId: RevisionId}"
We used the --query
parameter to limit the output to relevant to us
properties:
the ARNs of the layers
the revisionId
, which can be included in the update-function-configuration
command and is only used when multiple people work on the same lambda
function.
It allows us to be sure that no one of our colleagues updated the function in the time window we listed the function's layers and updated them. In other words it helps us avoid race conditions.
In the case we wanted to add layers to the lambda function and not replace the
existing layers, we would copy the existing function's layer ARNs and include it
in the update-function-configuration
command.