When developing serverless functions, you often need additional dependencies or libraries for the function to work. For Lambda functions in java, you need amazon dependencies of the services used in the function. Then you zip the function and its dependencies into a fat jar and upload it to the Lambda function. If you are not familiar with creating lambda function in java then refer to this post for a quick start.
The fat jar approach works fine but if you have multiple functions that use the same dependencies then creating a fat jar of each function is not a good approach and maintenance of such code is also difficult. A change in the version of a jar requires a change in each of the individual lambda functions.
A more elegant solution is to use Lambda layers.
What is Lambda Layers?
A layer is a ZIP archive that contains libraries, a custom runtime, or other dependencies. With layers, you can use libraries in your function without needing to include them in your deployment package. Layers let you keep your deployment package small, which makes development easier.
Layers are extracted to the /opt directory in the function execution environment. Each runtime looks for libraries in a different location under /opt, depending on the language.
You can specify up to 5 layers in your function's configuration, during or after function creation. You choose a specific version of a layer to use. If you want to use a different version later, update your function's configuration.
Let's see it in action
We will write a basic Lambda function that would just print lambda environment variables and event details. We will create 2 maven projects. In the first project, we include amazon and other essential dependencies. This project will serve as our Lambda Layer. In the second project, we include our first project as a dependency and will write the Lambda handler.
Create the first maven project called Lambda-Layer-Base and update pom as below:
This project contains all common dependencies required by the functions. In our case, we added lamdba-core
and gson
dependency. We also added maven-shade-plugin
to create fat jar.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.rajanpanchal</groupId>
<artifactId>lambda-layer-base</artifactId>
<version>1</version>
<name>Lambda-Layer-Base</name>
<description>Lambda base</description>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<aws.java.sdk.version>2.14.11</aws.java.sdk.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bom</artifactId>
<version>${aws.java.sdk.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
This project will only contain dependencies. Now execute maven clean install
and it should generate a jar (lambda-layer-base-1.jar
) in the target folder.
Create another maven project and update pom with the below contents. We included our first project as a dependency (lambda-layer-base
). Also note, we no longer use maven shade plugin since we don't want dependencies to be included in the jar.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.rajanpanchal</groupId>
<artifactId>lambda-java-demo</artifactId>
<version>1</version>
<packaging>jar</packaging>
<name>Lambda-Layers-Demo</name>
<description>HelloWorld Lambda Layers Demo</description>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<aws.java.sdk.version>2.14.11</aws.java.sdk.version>
</properties>
<dependencies>
<dependency>
<groupId>net.rajanpanchal</groupId>
<artifactId>lambda-layer-base</artifactId>
<version>1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Add a class file in src/main/java that will contain Lambda logic. Here we are just logging some stuff.
package net.rajanpanchal.handlers;
import java.util.Map;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class HelloWorldHandler implements RequestHandler<Map<String,String>, String>{
public String handleRequest(Map<String,String> event, Context context)
{
LambdaLogger logger = context.getLogger();
String response = new String("200 OK");
logger.log("ENVIRONMENT:"+System.getenv());
// log execution details
Gson gson = new GsonBuilder().setPrettyPrinting().create();
logger.log("ENVIRONMENT VARIABLES: " + gson.toJson(System.getenv()));
logger.log("CONTEXT: " + gson.toJson(context));
// process event
logger.log("EVENT: " + gson.toJson(event));
logger.log("EVENT TYPE: " + event.getClass().toString());
return response;
}
}
Execute maven package
command to create the jar for the project. A jar (lambda-java-demo-1.jar
) should get created in target folder.
Creating Lamdba Layer
Before we head to the console to create the layer, let's complete one important step. Remember that layers gets extracted to a folder in /opt directory. You need to package the layer in folder structure as per your runtime. For java, you need to package jar in java/lib
folder. The final folder structure, in the lambda runtime, would be /opt/java/lib/<your jar>
. So now create folders java/lib and copy jar from the first project and zip the folder. Now we are ready to upload the jar as lambda layer.
Creating Lambda function
Now create the lambda function and specify the layer that we just created. Also, upload the jar from the second project as our function code.
Add Layers to the function
Upload function code jar and update runtime settings
Create a test event and execute the test.
Source Code:
Conclusion
Lambda layer makes your development easy and error-free. It reduces the size of the function deployment package. You can use the same layer in multiple functions.
If you like the post, feel free to share and follow me on Twitter for updates!