DEV Community

Josh Wood
Josh Wood

Posted on • Originally published at gist.github.com

Deploy a new Rails app to AWS Lambda using Lamby

These are my notes from deploying a boilerplate Rails app to AWS Lambda (yeah, you read that right) using Lamby. Basically this is me going through the Quick Start guide. (Here is my production endpoint--not sure how long this will be up.)

Related links:

Follow me on Twitter: https://twitter.com/heyjoshwood

A few unanswered questions I have:

  • What about Lambda's 250MB max function size? Will this work with a large Rails app?
  • What about cold starts? Even a boilerplate Rails app takes a long time to boot.
  • Why is Docker so slow on macOS 😭

Update: Ken Collins, the creator of the Lamby gem, responded to some of my questions on Reddit. Check out the thread.


  • Generate the initial Rails app:
  brew install awscli jq
  brew tap aws/tap
  brew install aws-sam-cli

  asdf shell ruby 2.7.1

  gem install rails -N

  rails new lamby_rails \
    --skip-action-mailer --skip-action-mailbox --skip-action-text \
    --skip-active-record --skip-active-storage --skip-puma \
    --skip-action-cable --skip-spring --skip-listen --skip-turbolinks \
    --skip-system-test --skip-bootsnap

  cd lamby_rails

  git add .
  git commit -m 'initial'
Enter fullscreen mode Exit fullscreen mode
  • Edit app/controllers/application_controller.rb:
  class ApplicationController < ActionController::Base
    def index
      render html: "<h1>Hello Lamby</h1>".html_safe
    end
  end
Enter fullscreen mode Exit fullscreen mode

Edit config/routes.rb:

  Rails.application.routes.draw do
    root to: "application#index"
  end
Enter fullscreen mode Exit fullscreen mode
  • Save progress:
  git add -p
  git commit -m 'hello lamby'
Enter fullscreen mode Exit fullscreen mode
  • Install lamby gems:
  bundle add lamby aws-sdk-ssm
Enter fullscreen mode Exit fullscreen mode
  • Edit Gemfile:
  - gem "lamby", "~> 2.0"
  + gem "lamby", "~> 2.0", require: false
Enter fullscreen mode Exit fullscreen mode
  • Finish installing lamby:
  ./bin/rake -r lamby lamby:install

  git add -p
  git status
  git add .
  git commit -m 'install lamby'
Enter fullscreen mode Exit fullscreen mode
  • I set up my AWS credentials here:
  # ~/.aws/credentials
  [lamby_rails]
  aws_access_key_id = VALUE
  aws_secret_access_key = SECRET_VALUE
Enter fullscreen mode Exit fullscreen mode
  • And the region config here:
  # ~/.aws/config
  [lamby_rails]
  output = json
  region = us-west-1
Enter fullscreen mode Exit fullscreen mode
  • I set my AWS_PROFILE using direnv. Edit .envrc:
  export AWS_PROFILE=lamby_rails
Enter fullscreen mode Exit fullscreen mode

then run:

  direnv allow
Enter fullscreen mode Exit fullscreen mode
  • Configure SSM w/ Rails master key:
  aws ssm put-parameter \
    --name "/config/lamby_rails/env/RAILS_MASTER_KEY" \
    --type "SecureString" \
    --value $(cat config/master.key)
Enter fullscreen mode Exit fullscreen mode
  • Edit app.rb and add this line right after require 'lamby':
  ENV['RAILS_MASTER_KEY'] =
    Lamby::SsmParameterStore.get!('/config/lamby_rails/env/RAILS_MASTER_KEY')
Enter fullscreen mode Exit fullscreen mode
  • Edit template.yaml CloudFormation/SAM file by adding this to the Properties section of your RailsFunction. This addition allows your Lambda's runtime policy to read configs from SSM Parameter store (see full template.yml):
  Policies:
    - Version: "2012-10-17"
      Statement:
        - Effect: Allow
          Action:
            - ssm:GetParameter
            - ssm:GetParameters
            - ssm:GetParametersByPath
            - ssm:GetParameterHistory
          Resource:
            - !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/config/lamby_rails/*
Enter fullscreen mode Exit fullscreen mode
  • Save progress:
  git add -p
  git commit -m 'configure lamby'
Enter fullscreen mode Exit fullscreen mode
  • Edit .envrc (change the bucket name):
  export CLOUDFORMATION_BUCKET=lamby-rails-josh
  export AWS_DEFAULT_REGION=us-west-1
Enter fullscreen mode Exit fullscreen mode

don't forget:

  direnv allow
Enter fullscreen mode Exit fullscreen mode
  • Now run:
  aws s3 mb "s3://$CLOUDFORMATION_BUCKET"

  ./bin/deploy
Enter fullscreen mode Exit fullscreen mode
  • This uses Docker to bake the Rails app Lambda function. That can take a long time on macOS. Go get some coffee or tea. :)
  $ time ./bin/deploy

  Successfully created/updated stack - lambyrails-production-us-west-1 in None
  ./bin/deploy  17.45s user 9.86s system 5% cpu 9:04.13 total
Enter fullscreen mode Exit fullscreen mode

(that's the build/deploy time on an 8-core MacBook Pro 🤔)

Discussion (1)

Collapse
liquid_chickens profile image
Chris Dodds • Edited

"Why is Docker on Mac so slow?" = There are several reasons, but the main one is that Docker on Mac requires an additional layer of virtualization vs. Docker on Linux.

github.com/EugenMayer/docker-sync can help, but yeah... it's a problem.

Regarding Lamby, It's interesting, but I'm struggling to think of a real-world use case. I'm seeing some references in the docs to a Lambda/Rails proxy, which doesn't make much sense to me. A preferable pattern for something async would be Lambda -> SQS -> Rails worker/sidekiq, I would think. A real-time API using this seems like it would be fragile/slow/difficult-to-troubleshoot. I may be missing something. Have you come across any examples where folks were using this for something concrete?