FaaS for the Rubyist

We'll be using OpenFaaS today and its ruby-http template that gives full control over the HTTP request/response for your functions. OpenFaaS is a next-generation PaaS called a FaaS which allows users to run microservices and functions on any machine.

My buddy Paulo Arruda shut down his faastRuby service this month, so I wrote up this tutorial to welcome Ruby developers to the OpenFaaS community.

Tutorial

We'll deploy OpenFaaS, then go on to build a series of functions using Ruby to generate text, JSON, and HTML. We'll also make use of Ruby Gems.

Want to see how OpenFaaS, Docker, and Kubernetes can all play well together? Checkout my new video from the Cloud Native London conference: Serverless 2.0: Get Started With The PLONK Stack

Install OpenFaaS

OpenFaaS provides a complete platform for FaaS and microserviecs out of the box by building upon industry-standard projects from the Cloud Native Computing Foundation such as Prometheus.io and Kubernetes

A new community member Josh Michielsen wrote up a concise tutorial for installing OpenFaaS and its CLI on any machine using k3d from Rancher.

If you run into any issues, please use the docs and feel free to join Slack and ask for help there.

Explore the template

Each OpenFaaS function can be built from a template, or by using a Dockerfile. I created the ruby-http template for users who needed native compilation of Gems (using Debian as a base) and sane defaults such as a non-root user and a light-weight runtime image.

Before you get started have a look at how the ruby-http template works by browsing the README.

Generate a new function named my-website:

faas-cli template store pull ruby-http

faas-cli new --lang ruby-http my-website

You'll get three files generated:

my-website.yml
my-website/handler.rb
my-website/Gemfile

Let's look at the YAML file (my-website.yml):

version: 1.0
provider:
  name: openfaas
  gateway: http://127.0.0.1:8080
functions:
  my-website:
    lang: ruby-http
    handler: ./my-website
    image: my-website:latest

In order to deploy the function, change the image from my-website:latest to include your Docker Hub username i.e. alexellis2/my-website:latest. Each time we deploy the code, a new image will be pushed to the registry and our cluster will pull it down and run it for us.

Look at my-website/handler.rb:

class Handler
  def run(body, headers)
    response_headers = {"content-type": "text/plain"}
    body = "Hello world from the Ruby template"

    return body, response_headers
  end
end

Here we see that we can return a body and a map of response_headers. The default advertises the response as text/plain mime type.

We also get a Gemfile where we can provide a list of gems:

source 'https://rubygems.org'

The good news is that you can include Gems here that require native compilation such as Nokogiri. They will be built and pushed up inside the image that we build.

Deploy the example

Now deploy the example with the following:

faas-cli up -f my-website.yml

The up command does three things:

  1. Builds your code into a Docker image and installs your Ruby Gems
  2. Pushes the resulting image to the Docker Hub or another registry specified in your YAML file
  3. Sends a REST call to the OpenFaaS gateway to deploy the function

The OpenFaaS back-end will then pull down your image and run it.

Open the OpenFaaS UI and invoke the function.

You can also invoke it via curl:

export OPENFAAS_URL=http://127.0.0.1:8080

curl $OPENFAAS_URL/function/my-website

You can also run faas-cli describe to view alternative URLs for the function and to read its metadata.

faas-cli describe -f my-website.yml my-website

Name:                my-website
Status:              Ready
Replicas:            1
Available replicas:  1
Invocations:         2
Image:               alexellis2/my-website:latest
Function process:    
URL:                 http://127.0.0.1:8080/function/my-website
Async URL:           http://127.0.0.1:8080/async-function/my-website

You can invoke any OpenFaaS function asynchronously without having to add additional software such as resque or Sidekiq.

Simply change the URL, that's it. If you want to get the result then pass an X-Callback-Url header with where you want the result to be sent.

Render a webpage (HTML)

Now update the example to render HTML.

Edit my-website/handler.rb:

class Handler
  def run(body, headers)
    response_headers = {"content-type": "text/html"}
    body = '<html><h2>OpenFaaS for Ruby programmers</h2><p><img src="https://cdn.iconscout.com/icon/free/png-256/ruby-44-1175099.png"/></p><p>Hello world from the Ruby template</p></html>'

    return body, response_headers
  end
end

Redeploy the function

faas-cli up -f my-website.yml

Now invoke the function and inspect the returned content type, you'll also see the HTML rendered in a browser.

curl -i $OPENFAAS_URL/function/my-website

Use your favourite gem

We'll now write a new function to print the title of an RSS feed.

faas-cli new --lang ruby-http get-rss-title

Edit get-rss-title/handler.rb:

require 'rubygems'
require 'simple-rss'
require 'open-uri'
require 'json'

class Handler
  def run(body, headers)
    response_headers = {"Content-Type": "application/json"}

    uri = ENV["URI"]
    rss = SimpleRSS.parse open(uri)
    body = {"title" => rss.channel.title}

    return JSON.dump(body), response_headers
  end
end

Now we need a couple of gems, so let's update our Gem file so that the Docker build knows what to do.

Edit get-rss-title/Gemfile:

source 'https://rubygems.org'

gem 'simple-rss'

I've set the URI of the feed to be configured at deployment time in an environment variable. We can set these via the YAML file.

Edit get-rss-title.yml:

version: 1.0
provider:
  name: openfaas
  gateway: http://127.0.0.1:8080
functions:
  get-rss-title:
    lang: ruby-http
    handler: ./get-rss-title
    image: get-rss-title:latest
    environment:
      URI: http://rss.slashdot.org/Slashdot/slashdot/to

Note: remember to update image: to include your own Docker Hub username

This is what it looks like:

curl http://127.0.0.1:8080/function/get-rss-title; echo
{"title":"Slashdot"}

What could you do with the RSS feed? How about building a pretty-printer that outputted HTML for each entry?

Wrapping up

We've now built and deployed an OpenFaaS function using Ruby to render plain-text, JSON, and HTML. We've also made use of Gems, so it's now over to you to continue learning and then to go on to build something awesome.

Go deeper with OpenFaaS

OpenFaaS is built in the open by a community volunteers, if you'd like to contribute, the best way to start is by joining Slack. We would love to have more Ruby programmers in the community and to improve the developer-experience.

Above: OpenFaaS has built-in auto-scaling and detailed metrics, meaning that you can build your own dashboard to monitor your Ruby functions and microservices

Above: Grafana Dashboard generated from built-in Prometheus metrics

You can find out about the OpenFaaS stack in the docs

I also put together short set of labs for the team at Civo.com using Ruby: Ruby workshop for Civo, you can use it to learn about secrets and authentication.

Get in touch

Get in touch via Slack or Twitter and show me what you've built. 👑