View Sidebar
LambdaWrap, a Ruby GEM for AWS Lambda

LambdaWrap, a Ruby GEM for AWS Lambda

February 21, 2016 12:48 PM0 comments

LambdaWrap

Author: Markus Thurner
Reblogged from: http://lifeinvistaprint.com/techblog/lambdawrap-ruby-gem-aws-lambda/

We’ve released LambdaWrap, a Ruby gem to simplify deployment to a serverless application based on AWS Lambda. This blog post talks about the motivation behind this Ruby gem, and technical details of LambdaWrap.

Where did we start?

There was a lot of talk among my team regarding the benefits of AWS Lambda, an offering from Amazon Web Services to run code without provisioning or managing servers. So, while we were skeptical of how that would work out, we gave it a try for a simple RESTful service.

Since our service was very simple, we didn’t want to start with a framework like serverless. Instead, we simply had some basic unit tests, uploaded our scripts manually and tested everything online.

As our thoughts evolved on how to support this service in a production environment, we weren’t satisfied with our manual approach. We turned to AWS CloudFormation, but quickly realized that it didn’t support versioning of Lambda functions nor setup of API Gateway. So we decided to create a rakefile and leverage the AWS SDK for Ruby. We started simple by just supporting uploading of the Lamba functions, but then added a wrapper for aws-apigateway-importer, and since we were using AWS DynamoDB, also included a simple wrapper for DynamoDB table creation.

What does LambdaWrap do?

LambdaWrap allows one to create a build pipeline for an AWS Lambda-based RESTful service within less than an hour, so that you can immediately start focusing on creating value, namely, writing your service code. LambdaWrap is easy to get into, since it focuses on the deployment pipeline only.

Let’s look at a basic example: a RESTful service that exposes a PUT and a GET method on a resource, and uses AWS DynamoDB to store data. With a documentation-first approach, go to editor.swagger.io, document the two endpoints, and save the swagger.json locally. Then, create your rakefile and have a deploy task like the following:

task :deploy, :environment do |t, args|

  env = args[:environment] # An environment can be prod, test, or also something like pullrequest541 or myticket45.
  api_name = 'SimpleService'

  # publish dynamoDB database
  attributes = [{ attribute_name: "Key", attribute_type: "S" }]
  keyschema = [{ attribute_name: "Key", key_type: "HASH" }]
  LambdaWrap::DynamoDbManager.new().publish_database('myservice-' + env, attributes, keyschema, 1, 1)

  # package, publish and deploy lambda functions
  LambdaWrap::LambdaManager.new().package('package', 'package.zip', ['putfunc.js', 'getfunc.js'], [])
  s3_version_id = LambdaWrap::LambdaManager.new().publish_lambda_to_s3('package.zip', 'artifacts', 'lambda/service.zip')
  func_version = deploy_lambda(s3_version_id, 'func1', 'func1.handler')
  promote_lambda('func1', func_version, env)

  # configure API Gateway
  ag_mgr = LambdaWrap::ApiGatewayManager.new()
  ag_mgr.download_apigateway_importer('artifacts', 'tools/aws-apigateway-importer-1.0.3-SNAPSHOT-jar-with-dependencies.jar')
  uri = ag_mgr.setup_apigateway(api_name, env, 'swagger_doc.json')

end

That’s it. A few lines of ruby code and your deployment is fully automated, including supporting short-lived environments such as those for developers or pull request builds. (Yes, we recommend creating a full environment during a pull request to ensure the deployment pipeline works, and also to run some service level tests against it.) Once you start doing that, you probably also want to be able to destroy all those short-lived environments to avoid unnecessary expenses caused by unused resources.

 

task :shutdown, :environment do |t, args|

  env = args[:environment]

  # remove the stage form API Gateway
  LambdaWrap::ApiGatewayManager.new.shutdown_apigateway(DEFAULT_API_NAME, env)

  # remove lambda aliases
  LambdaWrap::LambdaManager.new().remove_alias('func1', env)

  # delete DynamoDB table
  LambdaWrap::DynamoDbManager.new().delete_database('myservice-' + env)

end

How did this help Cimpress?

We’re still in the early stages of our service’s lifecycle. But so far, deploying new versions of a service has been a smooth experience. Unifying this into a Ruby gem already benefited our small team by not duplicating the same deployment script over and over again, or worse – diverging over time. So while it took a little effort to bundle everything into a reusable library, the return on investment was almost immediate. So we believe the creation of LambdaWrap is a good story in moving a small team forward while showing what can be achieved with simple, generic script and by sharing our AWS Lamba experience in order to lower the entry hurdle for other teams.

What’s next?

We believe LambdaWrap allows others to learn from our experience of creating a deployment pipeline for services based on AWS Lambda. It’s so simple (in terms of just a few Ruby files) that it can easily be copied for more specific use cases, extended with additional, generic features, or both. Yes, we would appreciate your feedback and contributions. With that, we do not have a long-term roadmap for LambdaWrap, although we’ll continuously extend it. We will certainly continue to focus on deployment, not local execution or other alternatives. Other larger frameworks such as serverless already do that job particularly well.

Leave a reply


Simple Share Buttons