There are many definitions and interpretation of the "Serverless" term, but if I have to say it in a few words, it would be: a software architecture, which allow the (Dev)Ops team not to care about the backend infrastructure (there are still servers, they just don't care about them). Depending on the use case, there are different components that comprise a Serverless architecture:
- Cloud data stores
- API gateways
- Functions as a Service
In this blog post we examine in more detail how Functions as a Service (FaaS) can be implement on by leveraging the vCloud Director (vCD) platform.
First, lets define some basic requirements for a FaaS solution.
- As a FaaS developer I would like to be able to create a function with the following properties
- Name - the name of the function
- Code - the function executable code, complying with the FaaS API
- Trigger - the criteria which if met will tell the platform the run the function code. In the vCD world we can define this as two events:
- External API call to an endpoint defined by the trigger
- A notification event triggered as a result of an operation like creation of a VM.
- As a FaaS developer I would like my functions to not be limited in terms of scale, or how many events they can handle.
- As a FaaS developer I would like my function to be run in a sandbox, i.e. other tenants, should not have access to my functions.
- As a Service Provider I would like individual function calls to be limited in amount of resources they are going to use.
- As a FaaS developer I would like to be able to update a function.
- As a FaaS developer I would like to be able to remove a function.
There are probably many architectures that would satisfy these requirements, but I would touch on two in this blog post and will discuss their pros and cons.The first part of both solution architectures is the same: when an event or an external API call is triggered, send a message to a queue. This is the OOTB vCD extensibility mechanism.
Gateway Based Alternative
This alternative relies on a FaaS gateway to handle the request for a function call by:
- Starting a previously created container
- Running the function with the request payload
- Stoping the container
This architecture has an obvious drawback: the time it takes to start the container is added the time a request can be handled, but on the other hand is:
- Relatively simple
- Scalable by nature
Queues Based Alternative
The second alternative replaces the FaaS gateway with a very simple router, which can route the massages to e function specific queues. Modern messaging queue system can handle message routing, however, it is described in the architecture to clearly communicate the need of message routing as the first queue is not tenant aware.
The function containers would need be "fatter" as the code running inside would need to handle messages from a message queue and translate them into a request to the function.
This approach would deliver much faster response time, but it would require a monitoring/scaling mechanism of the containers, which is part of container orchestration solutions like Kubernetes.
Solution Implementation (PoC)
For the current PoC, I've decided to go with the simpler architecture and use vRO as a FaaS Gateway. We will cover only the external API endpoints type of trigger.
To cerate a function we would need to provide the Programming Language, endpoint URI and the function code itself.
When we hit create, it will:
- Store the function in a persistent store.
- Create a container
- Register the endpoint using the vCD API extensibility
There are few things to notice here:
- The status is initializing, because creating the container takes a minute or so. This is why we've made the process async.
- The route is tenant-specific. In the request form we provided "hello", but the solution generated "/api/org/pscoe/hello".
Our container is relatively simple. It has:
- Dockerfile, which describes the container
- handler.js which contains the function code
- package.json, which is used by the NodeJS package installer (NPM)
- server.js, which is a very simple express web server, used to redirect request to the function code
Finally, we use docker to build our image and create a container from it.
Once the function is in ready state, we can test it using the "Test Function" button, which makes a simple GET HTTP request using the function's route.
- Starts the container.
- Makes an HTTP POST request to the container port with the body of the original request.
- Stops the container.