Working with layers for Ruby Lambda functions - Amazon Lambda
Services or capabilities described in Amazon Web Services documentation might vary by Region. To see the differences applicable to the China Regions, see Getting Started with Amazon Web Services in China (PDF).

Working with layers for Ruby Lambda functions

A Lambda layer is a .zip file archive that contains supplementary code or data. Layers usually contain library dependencies, a custom runtime, or configuration files. Creating a layer involves three general steps:

  1. Package your layer content. This means creating a .zip file archive that contains the dependencies you want to use in your functions.

  2. Create the layer in Lambda.

  3. Add the layer to your functions.

This topic contains steps and guidance on how to properly package and create a Ruby Lambda layer with external library dependencies.

Prerequisites

To follow the steps in this section, you must have the following:

Throughout this topic, we reference the layer-ruby sample application on the awsdocs GitHub repository. This application contains scripts that download the dependencies and generate the layers. The application also contains corresponding functions that use dependencies from the layers. After creating a layer, you can deploy and invoke the corresponding function to verify that everything works properly. Because you use the Ruby 3.3 runtime for the functions, the layers must also be compatible with Ruby 3.3.

In the layer-ruby sample application, you package the tzinfo library into a Lambda layer. The layer/ directory contains the scripts to generate the layer. The function/ directory contains a sample function to help test that the layer works. The majority of this tutorial walks through how to create and package this layer.

Ruby layer compatibility with the Lambda runtime environment

When you package code in a Ruby layer, you specify the Lambda runtime environments that the code is compatible with. To assess code compatibility with a runtime, consider what versions of Ruby, what operating systems, and what instruction set architectures the code is designed for.

Lambda Ruby runtimes specify their Ruby version and operating system. In this document, you use the Ruby 3.3 runtime, which is based on AL2023. For more information about runtime versions, see Supported runtimes. When you create a Lambda function, you specify the instruction set architecture. In this document, you use the x86_64 architecture. For more information about architectures in Lambda, see Selecting and configuring an instruction set architecture for your Lambda function.

When you use code provided in a package, each package maintainer independently defines their compatibility. Most gems are written completely in Ruby, and are compatible with any runtime using a compatible Ruby language version.

Sometimes, gems use a Ruby feature called extensions to compile code or include precompiled code as part of their install process. If you depend on a gem with a native extension, you must assess operating system and instruction set architecture compatibility. To assess the compatibility between your gems and your Ruby runtime, you need to inspect your gems and their documentation. You can identify if your gem uses extensions by checking whether extensions is defined in its Gem specification. Ruby identifies the platform it is running on through the RUBY_PLATFORM global constant. The Lambda Ruby runtime defines the platform as aarch64-linux when running on the arm64 architecture, or x86_64-linux when running on the x86_64 architecture. There is no guaranteed way to check if a gem is compatible with these platforms, but some gems declare their supported platforms through the platform Gem specification attribute.

Layer paths for Ruby runtimes

When you add a layer to a function, Lambda loads the layer content into the /opt directory of that execution environment. For each Lambda runtime, the PATH variable already includes specific folder paths within the /opt directory. To ensure that Lambda picks up your layer content, your layer .zip file should have its dependencies in the following folder paths:

  • ruby/gems/x, where x is the Ruby version on your runtime, such as 3.3.0.

  • ruby/lib/

In this document, use the ruby/gems/x path. Lambda expects the contents of this directory to correspond to the structure of a Bundler install directory. Store your gem dependencies in the /gems subdirectory of the layer path, alongside other metadata subdirectories. For example, the resulting layer .zip file that you create in this tutorial has the following directory structure:

layer_content.zip └ ruby └ gems └ 3.3.0 └ gems └ tzinfo-2.0.6 └ <other_dependencies> (i.e. dependencies of the tzinfo package) └ ... └ <metadata generated by bundle>

The tzinfo library is correctly located in the ruby/gems/3.3.0/ directory. This ensure that Lambda can locate the library during function invocations.

Packaging the layer content

In this example, you package the Ruby tzinfo library in a layer .zip file. Complete the following steps to install and package the layer content.

To install and package your layer content
  1. Clone the aws-lambda-developer-guide GitHub repo, which contains the sample code that you need in the sample-apps/layer-ruby directory.

    git clone https://github.com/awsdocs/aws-lambda-developer-guide.git
  2. Navigate to the layer directory of the layer-ruby sample app. This directory contains the scripts that you use to create and package the layer properly.

    cd aws-lambda-developer-guide/sample-apps/layer-ruby/layer
  3. Examine the Gemfile. This file defines the dependencies that you want to include in the layer, namely the tzinfo library. You can update this file to include any dependencies that you want to include in your own layer.

    Example Gemfile
    source "https://rubygems.org" gem "tzinfo"
  4. Ensure that you have permissions to run both scripts.

    chmod 744 1-install.sh && chmod 744 2-package.sh
  5. Run the 1-install.sh script using the following command:

    ./1-install.sh

    This script configures bundler to install dependencies in your project directory. It then installs all required dependencies in the vendor/bundle/ directory.

    Example 1-install.sh
    bundle config set --local path 'vendor/bundle' bundle install
  6. Run the 2-package.sh script using the following command:

    ./2-package.sh

    This script copies the contents from the vendor/bundle directory into a new directory named ruby. It then zips the contents of the ruby directory into a file named layer_content.zip. This is the .zip file for your layer. You can unzip the file and verify that it contains the correct file structure, as shown in the Layer paths for Ruby runtimes section.

    Example 2-package.sh
    mkdir -p ruby/gems/3.3.0 cp -r vendor/bundle/ruby/3.3.0/* ruby/gems/3.3.0/ zip -r layer_content.zip ruby

Creating the layer

In this section, you take the layer_content.zip file that you generated in the previous section and upload it as a Lambda layer. You can upload a layer using the Amazon Web Services Management Console or the Lambda API via the Amazon Command Line Interface (Amazon CLI). When you upload your layer .zip file, in the following PublishLayerVersion Amazon CLI command, specify ruby3.3 as the compatible runtime and arm64 as the compatible architecture.

aws lambda publish-layer-version --layer-name ruby-requests-layer \ --zip-file fileb://layer_content.zip \ --compatible-runtimes ruby3.3 \ --compatible-architectures "arm64"

From the response, note the LayerVersionArn, which looks like arn:aws:lambda:us-east-1:123456789012:layer:ruby-requests-layer:1. You'll need this Amazon Resource Name (ARN) in the next step of this tutorial, when you add the layer to your function.

Adding the layer to your function

In this section, you deploy a sample Lambda function that uses the tzinfo library in its function code, then you attach the layer. To deploy the function, you need a Defining Lambda function permissions with an execution role. If you don't have an existing execution role, follow the steps in the collapsible section.

To create an execution role
  1. Open the roles page in the IAM console.

  2. Choose Create role.

  3. Create a role with the following properties.

    • Trusted entityLambda.

    • PermissionsAWSLambdaBasicExecutionRole.

    • Role namelambda-role.

    The AWSLambdaBasicExecutionRole policy has the permissions that the function needs to write logs to CloudWatch Logs.

The Lambda function code imports the tzinfo library, then returns the status code and a localized date string.

require 'json' require 'tzinfo' def lambda_handler(event:, context:) tz = TZInfo::Timezone.get('America/New_York') { statusCode: 200, body: tz.to_local(Time.utc(2018, 2, 1, 12, 30, 0)) } end
To deploy the Lambda function
  1. Navigate to the function/ directory. If you're currently in the layer/ directory, then run the following command:

    cd ../function
  2. Create a .zip file deployment package using the following command:

    zip my_deployment_package.zip lambda_function.rb
  3. Deploy the function. In the following Amazon CLI command, replace the --role parameter with your execution role ARN:

    aws lambda create-function --function-name ruby_function_with_layer \ --runtime ruby3.3 \ --architectures "arm64" \ --handler lambda_function.lambda_handler \ --role arn:aws:iam::123456789012:role/lambda-role \ --zip-file fileb://my_deployment_package.zip
  4. Next, attach the layer to your function. In the following Amazon CLI command, replace the --layers parameter with the layer version ARN that you noted earlier:

    aws lambda update-function-configuration --function-name ruby_function_with_layer \ --cli-binary-format raw-in-base64-out \ --layers "arn:aws:lambda:us-east-1:123456789012:layer:ruby-requests-layer:1"
  5. Finally, try to invoke your function using the following Amazon CLI command:

    aws lambda invoke --function-name ruby_function_with_layer \ --cli-binary-format raw-in-base64-out \ --payload '{ "key": "value" }' response.json

    You should see output that looks like this:

    { "StatusCode": 200, "ExecutedVersion": "$LATEST" }

    The output response.json file contains details about the response.

You can now delete the resources that you created for this tutorial, unless you want to retain them. By deleting Amazon resources that you're no longer using, you prevent unnecessary charges to your Amazon Web Services account.

To delete the Lambda layer
  1. Open the Layers page of the Lambda console.

  2. Select the layer that you created.

  3. Choose Delete, then choose Delete again.

To delete the Lambda function
  1. Open the Functions page of the Lambda console.

  2. Select the function that you created.

  3. Choose Actions, Delete.

  4. Type confirm in the text input field and choose Delete.