The quickest & easiest way to develop AWS Lambda functions that use Ruby gems

Although there are some nifty frameworks for building and managing AWS Lambda functions using Ruby, unless the project is quite complex I like a simple local-to-AWS development flow, without any framework magic obscuring what’s actually happening in my code.

This is probably the simplest way to get up and running developing locally for AWS Lamda functions that need to use common gems such as “rest-client”. It is modeled after: https://www.stevenringo.com/ruby-in-aws-lambda-with-postgresql-nokogiri/ but simplified.

You need an AWS account, and Docker, period. (Don’t even need the AWS CLI command line utility.)

In browser:

1. Create a default ‘hello world’ lambda function in your aws lambda console

It sets up intelligent default for roles etc.

I like to set concurrency to 1 while developing.

In the Mac terminal:

2. Create  a docker folder with a dockerfile that uses an aws lambda image

The folder is just to hold the docker file you use when you need to build or rebuilt the Docker image you use for local AWS Lambda development.
$ mkdir aws-lambda-docker
$ cd aws-lambda-docker

If using postgres (like the article above this was based on) it’ll need extra stuff, this example below is just the simplest  Dockerfile, to let you use ruby gems.

# be sure the ruby version is same as what aws lambda currently offers 
# Dockerfile 
FROM lambci/lambda:build-ruby2.7 
RUN gem update bundler 
CMD "/bin/bash"

3. Create tagged docker container, your own local “AWS Lambda in a Box” that you can re-use for all your Ruby-with-gems Lambda projects:

I’m building a container for aws lambda ruby v27 so I use that for the tag:

$ docker build -t awsruby27 .

4. Make a Project directory

$ mkdir awsstuff 
$ cd awsstuff

5. Create your lambda_function.rb code

We’ll use two gems, one that needs to be compiled with native extensions (nokogiri) and one that does not (rest-client).

# lambda_function.rb
require 'json'
require 'rest-client'
require 'nokogiri'

def lambda_handler(event:, context:)
    url = "https://api.myip.com"
    puts "use rest-client ruby gem"
    html = "<html><title>The Title</title><body>The Body</body></html>"
    parsed_data = Nokogiri::HTML.parse(html)
    puts parsed_data.title
    rr = RestClient::Request.execute :method =&gt; :get, 
        :url => url, 
        :ssl_version =&gt; 'SSLv23'
    result = "Title check: #{parsed_data.title} and remote api returned #{rr.body}"

    { statusCode: rr.code, body: result }
end

6. Create your Gemfile

# Gemfile
source "https://rubygems.org"
gem "rest-client"
gem "nokogiri"

7. Inside the project folder, run the Lambda ruby container:

$ docker run --rm -it -v $PWD:/var/task -w /var/task awsruby27

Inside the docker container:

8. Bundle your project

Only needed when you create or  modify the Gemfile:

bash-4.2# bundle install --path vendor/bundle --clean

9. Test your handler code

Via Ruby’s -e option to execute a string containing the ruby code to require & invoke a function:

bash-4.2# ruby -e "require 'lambda_function'; puts lambda_handler(event: nil, context: nil)"
# output:
use rest-client ruby gem 
The Title {:statusCode=>200, :body=>"Title check: The Title and remote api returned {\"ip\":\"xxx.xxx.xxx.xxx\",\"country\":\"United States\",\"cc\":\"US\"}"}

Or interactively, via irb:

bash-4.2# irb
> require 'lambda_function'
> lambda_handler(event: nil, context: nil)
# output: 
use rest client ruby gem 
The Title {:statusCode=>200, :body=>"Title check: The Title and remote api returned {\"ip\":\"xxx.xxx.xxx.xxx\",\"country\":\"United States\",\"cc\":\"US\"}"} 
> exit
bash-4.2# exit

10. Back in Terminal, package the zip file

$ rm -f deploy.zip ; zip -q -r deploy.zip .

In AWS console:

11. Upload your working zip file deployment to the lambda function

In aws console, on the existing lambda function, on CODE tab, use UPLOAD FROM button on right and upload zip fle

12. Test it on Lambda

Now you have an AWS Lambda function in Ruby, which can use arbitrary Ruby gems, even native-extensions gems like nokogiri (which works on AWS since you compiled your Ruby bundle inside a docker container based on the AWS ‘build’ image for Ruby).

A few notes about deployment size…

The bundle’s deployment size increases significantly if you add certain native-extension gems such as nokogiri, and if the deployment package exceeds some limit you will not be able to view the code on the AWS Lambda console and will see this message instead:

The deployment package of your Lambda function "test2" is too large to enable inline code editing. However, you can still invoke your function.

The code still runs on Lambda, only the code view/edit is disabled when the package is too large.

For your NEXT projects, simply start at step 4.

You’ve already created your Lambda-in-a-Box docker container so simply create a project folder, write your lambda_function.rb and Gemfile, then use your already-built docker container to run and text your code.

Leave a Reply

Your email address will not be published. Required fields are marked *