Serverless use cases for Web projects

Oleksii Vasyliev, Railsware

Serverless use cases for Web projects

Brought to you by Alexey Vasiliev, Railsware

Oleksii Vasyliev

Serverless

Serverless

Serverless computing is a cloud-computing execution model in which the cloud provider runs the server, and dynamically manages the allocation of machine resources

serverless

Serverless Solutions

  • AWS Lambda
  • Azure serverless
  • Google Cloud Functions
  • Apache OpenWhisk
  • Kubeless
  • etc...
aws-lambda

Ruby on Serverless

aws-lambda-ruby
  • AWS Lambda - supported
  • Azure serverless - nope :(
  • Google Cloud Functions - nope :(
  • Apache OpenWhisk - supported

Use cases

Resize Images on S3 bucket

aws-lambda-ruby
  • AWS S3 events
  • AWS API Gateway
  • AWS Lambda@Edge

AWS S3 events

  # Gemfile
  source 'https://rubygems.org'

  gem 'aws-sdk-s3'
  gem 'mini_magick'
# handler.rb
require 'resizer'

class ImageHandler

  def self.process(event:, context:)
    event = event["Records"].first
    bucket_name = event["s3"]["bucket"]["name"]
    object_name = event["s3"]["object"]["key"]

    file = Resizer.from_s3(bucket_name, object_name)
    file.resize "100x100"
    file.upload_file("resized-your-images", "resized_" + event["s3"]["object"]["key"] )
  end
end
require "aws-sdk-s3"
require "mini_magick"

class Resizer
    def resize(params)
        image = MiniMagick::Image.open(@tmp_file)
        ...
        image.write @resized_tmp_file
    end

    def upload_file(target_bucket, target_object)
        s3 = Aws::S3::Resource.new()
        object = s3.bucket(target_bucket).object(target_object).upload_file(@resized_tmp_file)
    end
end

AWS API Gateway

AWS API Gateway


http://YOUR_CLOUDFRONT_WEBSITE_HOSTNAME_HERE/300×300/your_image.jpg

http://YOUR_CLOUDFRONT_WEBSITE_HOSTNAME_HERE/25×25/your_image.jpg

http://YOUR_CLOUDFRONT_WEBSITE_HOSTNAME_HERE/500×500/your_image.jpg

AWS Lambda@Edge

Use case with static website

CloudFront does allow you to specify a default root object (index.html), but it only works on the root of the website (such as http://www.example.com > http://www.example.com/index.html). It does not work on any subdirectory (such as http://www.example.com/about/)

https://railsware.com/ - works on CloudFront

https://railsware.com/railswarians/ - not resolve to "index.html"

exports.handler = (event, context, callback) => {
  const request = event.Records[0].cf.request;

  if (request.uri.match('.+/$')) {
    request.uri += 'index.html';
    callback(null, request);
  } else if (request.uri.match('(.+)/index.html')) {
    ...
  }
}
  ...
  } else if (request.uri.match('(.+)/index.html')) {
    const prefixPath = request.uri.match('(.+)/index.html');
    const response = {
      status: '301',
      statusDescription: 'Found',
      headers: {
        location: [{
          key: 'Location', value: prefixPath[1] + '/',
        }],
      }
    };
    callback(null, response);
  } else if (request.uri.match('/[^/.]+$')) {
    ...
  }
}
  ...
  } else if (request.uri.match('/[^/.]+$')) {
    const response = {
      status: '301',
      statusDescription: 'Found',
      headers: {
        location: [{
          key: 'Location', value: request.uri + '/',
        }],
      }
    };
    callback(null, response);
  } else {
    callback(null, request);
  }
}

Lambda@Edge Use Cases

AWS Lambda + AWS Route53 + AWS S3 = Letsencrypt wildcard certificate

load_paths = Dir["./vendor/bundle/ruby/2.5.0/bundler/gems/**/lib"]
$LOAD_PATH.unshift(*load_paths)
require 'acme_aws_lambda'

AcmeAwsLambda.configure do |config|
  config.production_mode = true
  config.contact_email = 'admin@example.com'
  config.domains = ['example.com', '*.example.com']
  config.common_name = '*.example.com'
  config.s3_bucket = 'example.com-certificates'
  config.s3_certificates_key = 'certificates/example.com'
  config.route53_domain = 'example.com'
end

def handler(event:, context:)
  AcmeAwsLambda.create_or_renew_cert
end

Cron task to update certificates

 # crontab
0 3 * * * /opt/s3_fetch/s3_fetch_certs
-accessKeyId="access-key"
-secretAccessKey="secret-access-key"
-bucket="s3-bucket" -certsKey="path-on-s3"
-outDirectory="/etc/nginx/certs" -outName="production"
-runAfterChange="systemctl reload nginx"

Certonid is a Serverless SSH Certificate Authority: github.com/certonid/certonid

serverless
$ certonid -h

Usage:
  certonid [OPTIONS] COMMAND [ARG...]
  certonid [command]

Available Commands:
  completion  Generates bash completion scripts
  decrfile    Decrypt file
  decrstr     Decrypt text
  encrfile    Encrypt file
  encrstr     Encrypt text
  gencert     Generate user or host certificate
  help        Help about any command
  randstr     Generate random string (32 bytes)

Pros

Cons

Serverless Cost

Tips

<Thank You!> Questions?

Contact information

QuestionsSlide