PHP and OpenFaaS

There's been a couple of things recently that have got me to this point 1) Hype around serverless functions 2) My growing interest in OpenFaaS So here I am, sat in a coffee shop in central London tinkering with OpenFaaS and PHP - here's how it went.

OpenFaaS describes itself as "Serverless Functions Made Simple for Docker & Kubernetes"

Within this post, I'm not saying any of this is perfect or the best way to do things. This is just documentation of what I did and my own personal notes of things I've found along the way to getting a PHP serverless function running locally in OpenFaaS. This is mostly a brain-dump for my own reference later on.

Setting up OpenFaaS

Get OpenFaaS setup and running as per the docs. I did mine locally just to tinker with it. I already had docker running so I ran docker swarm init and then ran:

> git clone https://github.com/openfaas/faas && \
  cd faas && \
  ./deploy_stack.sh

Which deployed it and gave me some admin credentials. I opened the UI at 127.0.0.1:8080 and used them to login.

Get OpenFaaS CLI up and running as per the docs. - I used brew install faas-cli as I was on my Macbook at the time.

Setting up our project

Make a new directory for your serverless function:

> mkdir ping-php && cd ping-php

Now pull the template we're going to use (thanks to itscaro for this!

> faas-cli template pull https://github.com/itscaro/openfaas-template-php

Now we'll create a new function and tell it what language to use:

> faas-cli new ping-php --lang php

Now open the directory within your editor of choice. Mine's PhpStorm.

The first thing of note that's odd to me is the nested folders of the same name. But hey, we'll roll with it.

Within ./ping-php there's a src directory that containers a Handler.php class. Open that and you'll see:

<?php

namespace App;

class Handler
{
    public function handle(string $data): void {
        echo $data;
    }
}

So, by default it'll just return the data you send to it.

Now we've got the project setup, we can build it!

Building our function

To build your function, we'll use the faas-cli once again:

> faas-cli build -f ./ping-php.yml

This will build the docker container that will run our function.

Once it's built, we can deploy it!

Deploying our function

> faas-cli deploy -f ./ping-php.yml

After running this function you should see:

Deploying: ping-php.

Deployed. 200 OK.
URL: http://127.0.0.1:8080/function/ping-php

This tells us that it's deployed okay, as well as the URL we can invoke the function with.

Running our function

Now, we can access our function by sending a POST request to the URL specified:

> curl -XPOST http://127.0.0.1:8080/function/ping-php

However, we'll not see anything as the function just returns what you submit to it, and we haven't sent anything to it!

Now, if we submit data to it, we should have the data returned. So running:

> curl -XPOST -d "hello blog\!" http://127.0.0.1:8080/function/ping-php

Will give us an output of:

hello blog!

Winner!

Now, let's update our function to respond with the current timestamp as it's a "ping" function.

Updating our function

Let's update our function to return some json, so back in ./ping-php/src/Handler.php we'll change it to:

<?php

namespace App;

class Handler
{
    public function handle(string $data): void {
        echo json_encode(['pong' => time()]);
    }
}

Note that we're not setting a Content-Type. From my playing around it seems that setting a Content-Type within the function that's responding doesn't do anything. The gateway that OpenFaaS uses though does seem to respect the Content-Type in the request and use that for the response. Digging through the docs there's more information there that suggests that's the case.

We can verify this by running:

> curl -XPOST -H "Content-Type: application/json" http://127.0.0.1:8080/function/ping-php --head

Which will show us that the response also gives back application/json:

HTTP/1.1 200 OK
Content-Length: 19
Content-Type: application/json
Date: Sat, 21 Jul 2018 12:35:58 GMT
X-Call-Id: 155bd285-8ea9-413d-a60b-d66adac0b676
X-Duration-Seconds: 0.018977
X-Start-Time: 1532176558927224600

Right back to it, let's re-build our function and re-deploy it as per the steps above:

Build:

> faas-cli build -f ./ping-php.yml

Deploy:

> faas-cli deploy -f ./ping-php.yml

Now if we run our function, we'll see that we get back the JSON we specified:

> curl -XPOST http://127.0.0.1:8080/function/ping-php

{"pong":1532176701}

Conclusion

First impressions: cool!

Interested to see how it works in production if I move anything to it. Like anything, I expect it to have a learning cliff - everything in dev is easy, prod is always another matter! But that's future Matts problem, present-Matt is just having fun with the easy stuff in dev