Skip to content

Instantly share code, notes, and snippets.

@joshuap
Last active February 21, 2022 09:00
Show Gist options
  • Save joshuap/4ab915f6b94366f570fcb63f38660262 to your computer and use it in GitHub Desktop.
Save joshuap/4ab915f6b94366f570fcb63f38660262 to your computer and use it in GitHub Desktop.
Deploy a new Rails app to AWS Lambda using Lamby

Rails => Lambda

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.

Questions/comments: https://twitter.com/heyjoshwood

Notes

  • 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'
  • Edit app/controllers/application_controller.rb:

    class ApplicationController < ActionController::Base
    +  def index
    +    render html: "<h1>Hello Lamby</h1>".html_safe
    +  end
    end

    Edit config/routes.rb:

    Rails.application.routes.draw do
    +  root to: "application#index"
    end
  • Save progress:

    git add -p
    git commit -m 'hello lamby'
  • Install lamby gems:

    bundle add lamby aws-sdk-ssm
  • Edit Gemfile:

    - gem "lamby", "~> 2.0"
    + gem "lamby", "~> 2.0", require: false
  • Finish installing lamby:

    ./bin/rake -r lamby lamby:install
    
    git add -p
    git status
    git add .
    git commit -m 'install lamby'
  • I set up my AWS credentials here:

    # ~/.aws/credentials
    [lamby_rails]
    aws_access_key_id = VALUE
    aws_secret_access_key = SECRET_VALUE
    
  • And the region config here:

    # ~/.aws/config
    [lamby_rails]
    output = json
    region = us-west-1
    
  • I set my AWS_PROFILE using direnv. Edit .envrc:

    export AWS_PROFILE=lamby_rails
    

    then run:

    direnv allow
  • 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)
  • 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')
  • 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 attached):

    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/*
    
  • Save progress:

    git add -p
    git commit -m 'configure lamby'
  • Edit .envrc (change the bucket name):

    export CLOUDFORMATION_BUCKET=lamby-rails-josh
    export AWS_DEFAULT_REGION=us-west-1
    

    don't forget:

    direnv allow
  • Now run:

    aws s3 mb "s3://$CLOUDFORMATION_BUCKET"
    
    ./bin/deploy
  • 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

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

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: LambyRails Lambda (HTTP API)
Parameters:
RailsEnv:
Type: String
Default: production
AllowedValues:
- staging
- production
Resources:
RailsFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: .
Handler: app.handler
Runtime: ruby2.7
MemorySize: 512
Timeout: 30
Environment:
Variables:
RAILS_ENV: !Ref RailsEnv
FunctionName: !Join [ '', [ 'LambyRails-', !Ref RailsEnv, '-', !Ref 'AWS::Region' ] ]
Events:
RailsApiProxy:
Type: HttpApi
Properties:
ApiId: !Ref RailsApi
AutoPublishAlias: live
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/*
RailsApi:
Type: AWS::Serverless::HttpApi
Properties:
StageName: !Ref RailsEnv
Outputs:
RailsApiUrl:
Description: API Gateway Endpoint
Value: !Sub "https://${RailsApi}.execute-api.${AWS::Region}.amazonaws.com/${RailsEnv}/"
RailsFunctionArn:
Description: Lambda ARN
Value: !GetAtt RailsFunction.Arn
@joshuap
Copy link
Author

joshuap commented Jan 18, 2021

@alfredorico I think it was just a personal preference; you should be able to add back whatever features you want.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment