Skip to main content

Introduction to Serverless (FaaS)

7 min read

Older Article

This article was published 7 years ago. Some information may be outdated or no longer applicable.

Serverless computing, serverless functions, FaaS. These buzzwords have been floating around for a while. Let’s look at what they actually mean and build something with them.

Definition

The biggest “quirk” you need to remember: “serverless” still involves servers. There’s no magic that eliminates servers entirely. It’s a model where we, the developers, don’t worry about managing those servers.

Lingo

Let’s run through the basic terms around Serverless computing. Here’s a screenshot from a slide I presented at Download Event in Bergamo, Italy earlier this year.

IaaS

Infrastructure As A Service. Think Amazon’s Elastic Cloud Computing (AWS EC2) or Virtual Private Cloud (VPC). The key point: you manage everything. Amazon provides the infrastructure, but you set up and run the server.

SaaS

Software As A Service. A service that gives you specific functionality, free or paid. Stripe and PayPal for payments, Slack for communication. You integrate them, but you know very little about what’s happening under the hood.

PaaS

Platform As A Service. You get an entire platform to deploy and run an application, without worrying about the underlying infrastructure. Heroku is a solid example. Deploy to a Dyno (Heroku’s term), scale up or down as needed.

BaaS

Backend As A Service. A highly available backend for specific tasks, typically accessed through dedicated SDKs and APIs. DynamoDB from Amazon and Firebase from Google are good examples.

BaaS counts as Serverless. Why? From our perspective, there’s no server management involved.

FaaS

Function As A Service. You invoke a function. That’s it. Useful for things like implementing custom logic or orchestrating web services. Cost is a big factor here too (more on that shortly).

FaaS is the other service category considered Serverless.

So now we’ve got a handle on the various components in the Serverless space.

Pros and Cons

Serverless computing has clear benefits, but it also comes with trade-offs.

Pros:

  • No “always-on” pricing (“Pay As You Go” instead)
  • Computational power scales with load and usage
  • Framework, language, and environment agnostic
  • Horizontal scalability via ephemeral containers
  • Lightweight virtualisation, no heavy configuration needed

“Ephemeral” here means short-lived containers. A container starts up, executes, returns data (or does some computation), then shuts down and gets destroyed.

In short, FaaS lets you focus on writing the function, not on DevOps. And you only pay for the computational time you actually use. Compare that to an EC2 instance running (and billing) around the clock.

Cons:

  • Application state is hard to maintain
  • No variable or data sharing between invocations
  • Long-running functions get cut short
  • Potential startup latency

Since functions run in ephemeral containers, sharing variables between invocations is nearly impossible. Containers have execution time limits, so long-running functions won’t work. And if a function goes idle for a while, its container can go stale (the infrastructure decides when), meaning you might hit longer startup times.

Serverless Framework

The Serverless Framework is an open source project from Serverless, Inc. It lets you create serverless functions without getting in the way, and it’s provider agnostic. You can target AWS, Microsoft Azure, or IBM OpenWhisk.

Example

We’ll use the Serverless Framework to create a function running on AWS (via AWS Lambda). The function will talk to Unsplash and Cloudinary. I picked the Serverless Framework for two reasons: I’d been wanting to try it, and it makes deploying to AWS (and other providers like Azure, Bluemix, and Oracle Cloud) easy.

Here’s the scenario. You need a sample image of something (a cat, a house, a business person, you name it, but probably a cat). You want to grab one and store it somewhere.

We’ll build a Serverless Function that takes an argument like “cat”, fetches a random image from Unsplash, and uploads it to Cloudinary’s Media Library. We’ll cover setting up the Serverless Framework, configuring it, and wiring the pieces together.

Getting started

Install the Serverless Framework: npm i -g serverless

Start a new serverless project: serverless login

You’ll need to set up your AWS credentials. This article doesn’t cover that, but check the AWS Credential Setup Guide from Serverless, Inc.

Once logged in, create a new service using the Node.js template: serverless create -t aws-nodejs

This generates two files:

* handler.js
* serverless.yml

handler.js holds the function we’ll invoke. serverless.yml contains the service configuration.

Open the yml file and add these lines:

service: aws-nodejs
app: XXX
tenant: XXX

Replace XXX with your app and tenant values.

Deploy the service: serverless deploy

Verify it’s working by invoking the function (called hello by default): serverless invoke -f hello -l

If everything’s set up correctly, you’ll see a message body come back.

Updating the handler

Time to update the handler function. We’ll rename it and write the actual code:

'use strict';

function _getImage(term) {
  const url = `https://api.unsplash.com/photos/random?query=${term}&client_id=${process.env.UNSPLASH_API_KEY}`;
  return new Promise((resolve, reject) => {
    const https = require('https');
    const request = https.get(url, (response) => {
      if (response.statusCode < 200 || response.statusCode > 299) {
        reject(
          new Error('Failed to load page, status code: ' + response.statusCode)
        );
      }
      const body = [];
      response.on('data', (chunk) => body.push(chunk));
      response.on('end', () => resolve(body.join('')));
    });
    request.on('error', (err) => reject(err));
  });
}

module.exports.image = async (event, context, callback) => {
  const cloudinary = require('cloudinary');
  cloudinary.config({
    cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
    api_key: process.env.CLOUDINARY_API_KEY,
    api_secret: process.env.CLOUDINARY_API_SECRET,
  });
  if (event.queryStringParameters && event.queryStringParameters.term) {
    const term = event.queryStringParameters.term;
    return _getImage(term).then((response) => {
      const r = JSON.parse(response);
      return cloudinary.v2.uploader.upload(r.urls.full, (error, result) => {
        return callback(null, {
          statusCode: 200,
          body: JSON.stringify({
            message: `Access image at ${result.secure_url}`,
          }),
        });
      });
    });
  }
};

That’s a chunk of code. Let’s break it down.

All the process.env.* values are explained later in this article.

_getImage() hits Unsplash and returns a random image based on the term argument.

You’ll need a valid API key for this to work. Register for one.

The second part, starting with module.exports.image, is the FaaS code that runs on AWS. It sets up Cloudinary credentials.

Sign up for Cloudinary to get your API key.

With credentials in place, we check for query parameters. If they exist, we call _getImage().

That function returns a random image. We take the full URL from Unsplash, pass it to the Cloudinary Node.js Uploader, and if the upload succeeds, we return the Cloudinary URL.

Managing dependencies

The code depends on the Cloudinary Node.js API. How does the Serverless platform know about this dependency and install it on AWS?

Simple. You need a package.json in the same location as your other files, with the dependency listed:

{
  "name": "serverless",
  "version": "1.0.0",
  "description": "",
  "main": "handler.js",
  "dependencies": {
    "cloudinary": "^1.11.0"
  },
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Managing secrets

We’ve got several secrets in the code, and they shouldn’t be exposed. The serverless.yml config file lets you set environment variables, accessible via process.env:

Extend serverless.yml with the following (swap in your real values):

provider:
  name: aws
  runtime: nodejs8.10
  environment:
    CLOUDINARY_API_KEY: 'cloudinary-api-key'
    CLOUDINARY_API_SECRET: 'cloudinary-api-secret'
    CLOUDINARY_CLOUD_NAME: 'cloudinary-cloud-name'
    UNSPLASH_API_KEY: 'unsplash-api-key'

API Gateway

We’ve created a service, but there’s no way to call it via REST yet. To invoke the function, we need an API Gateway.

Since we’re using the Serverless Framework, this is painless. Just update serverless.yml with the gateway details:

functions:
  image:
    handler: handler.image
    events:
    - http:
        path: image
        method: get

We define that an HTTP GET to /image should resolve to handler.image, which is module.exports.image in our code.

Deploy

After all these changes, deploy (or redeploy): serverless deploy

Executing

During deploy, you’ll get Service Information that looks something like this:

See the endpoints? That’s what we use to invoke our FaaS. Let’s try it.

The service URLs and responses will be different for your setup.

You should see a URL come back. And if you log into your Cloudinary Media Library, the image should be sitting there:

Conclusion

We’ve covered the basics of Serverless computing and built a fun example: a FaaS solution that loads a random image from a royalty-free provider into Cloudinary.