0% found this document useful (0 votes)
38 views35 pages

Implementing Serverless PHP: Under The Hood of Openwhisk

This document discusses implementing serverless PHP using Apache OpenWhisk. It begins by explaining serverless computing and Functions as a Service (FaaS). It then demonstrates how to write a simple "Hello World" application in PHP and deploy it to OpenWhisk. The document notes that initial attempts had slow execution times due to container startup latency. It then proposes writing a PHP action runner to address this issue by handling PHP execution in a separate process. This allows PHP actions on OpenWhisk to execute much faster, in around 500 milliseconds.

Uploaded by

LotfiBennour
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
38 views35 pages

Implementing Serverless PHP: Under The Hood of Openwhisk

This document discusses implementing serverless PHP using Apache OpenWhisk. It begins by explaining serverless computing and Functions as a Service (FaaS). It then demonstrates how to write a simple "Hello World" application in PHP and deploy it to OpenWhisk. The document notes that initial attempts had slow execution times due to container startup latency. It then proposes writing a PHP action runner to address this issue by handling PHP execution in a separate process. This allows PHP actions on OpenWhisk to execute much faster, in around 500 milliseconds.

Uploaded by

LotfiBennour
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 35

Implementing Serverless PHP

Under the hood of OpenWhisk


 
Rob Allen
Serverless?
 
The first thing to know about serverless computing is that
"serverless" is a pretty bad name to call it.
- Brandon Butler, Network World

Rob Allen ~ @akrabat


AKA: Functions as a Service
• A runtime to execute your functions
• No capacity planning or load balancing; just tasks being executed.
• Pay for execution, not when idle

Rob Allen ~ @akrabat


Common tasks
• Microservices / API backends
• Volatile workloads (that break down in pieces)
• Data processing
• Event processing (message queues)
• Scheduled tasks
• Chat bots

Rob Allen ~ @akrabat


Challenges
• Start up latency
• Time limit
• State is external
• DevOps is still a thing

Rob Allen ~ @akrabat


It's about value

Rob Allen ~ @akrabat


Serverless implementations
Apache OpenWhisk (IBM, Adobe, RedHat)
AWS Lambda
Google Cloud Functions
Microsoft Azure Cloud Functions
Iron.io

Rob Allen ~ @akrabat


OpenWhisk is Open Source

Rob Allen ~ @akrabat


JavaScript

Rob Allen ~ @akrabat


Hello world in JS
hello.js:
1 function main(params)
2 {
3 name = params.name || "World"
4 return {msg: 'Hello ' + name}
5 }

Create action:
$ wsk action create helloJS hello.js --web true --kind nodejs:6
ok: updated action helloJS

Rob Allen ~ @akrabat


Hello world in JS
Execute:
$ wsk action invoke -r helloJS -p name Rob
{
"msg": "Hello Rob"
}

or:
$ curl -k https://192.168.33.13/api/v1/web/guest/default/helloJS.json
{
"msg": "Hello World"
}

Rob Allen ~ @akrabat


PHP

Rob Allen ~ @akrabat


Hello world in PHP
hello.php:
1 <?php
2 function main(array $args) : array
3 {
4 $name = $args["name"] ?? "World";
5 return [ "msg" => "Hello $name" ];
6 }

Rob Allen ~ @akrabat


Dockerise
exec:
1 #!/bin/bash
2
3 # Install PHP
4 if [ ! -f /usr/bin/php ]; then
5 echo "http://dl-cdn.alpinelinux.org/alpine/edge/community" \
6 >> /etc/apk/repositories
7 apk add --update php7 php7-json
8 fi
9
10 # Run PHP action
11 /usr/bin/php -r 'require "/action/hello.php";
12 echo json_encode(main(json_decode($argv[1], true)));' -- "$@"

Rob Allen ~ @akrabat


Create & Execute action
1 $ zip -r hello.zip hello.php exec
2
3 $ wsk action create helloPHP hello.zip --web true --docker
4 ok: updated action helloPHP
5
6 $ wsk action invoke -r helloPHP -p name Rob
7 {
8 "msg": "Hello Rob"
9 }

Rob Allen ~ @akrabat


Time to execute: 7 seconds

Rob Allen ~ @akrabat


Solution:
Write a PHP action runner!

Rob Allen ~ @akrabat


OpenWhisk's Architecture

 
 
(Thanks Philippe Suter for the original architecture diagrams)

Rob Allen ~ @akrabat


OpenWhisk's Architecture

 
 
(Thanks Philippe Suter for the original architecture diagrams)

Rob Allen ~ @akrabat


Create an action

Rob Allen ~ @akrabat


Invoke an action

Rob Allen ~ @akrabat


Action container lifecycle
• Hosts the user-written code
• Controlled via two end points: /init & /run

Rob Allen ~ @akrabat


Action Container API
POST /init POST /run
input { {
"value": { "value": {
"name" : "helloPHP", "name" : "Rob",
"main" : "main", }
"binary": false, }
"code" : "<?php …",
}
}

output { "OK": true} `{"msg": "Hello Rob" }

Rob Allen ~ @akrabat


Writing a PHP action container
We need:
• A container
• Code to handle endpoints (router)
• Execute the user code (runner)

Rob Allen ~ @akrabat


Dockerfile
FROM php:7.1-alpine

# copy required files


ADD router.php /action
ADD runner.php /action

# Start webserver on port 8080


EXPOSE 8080
CMD [ "php", "-S", "0.0.0.0:8080", "/action/router.php" ]

Rob Allen ~ @akrabat


router.php
1 <?php
2 if ($_SERVER['REQUEST_URI'] == '/init') {
3 $result = init();
4 } elseif ($_SERVER['REQUEST_URI'] == '/run') {
5 $result = run();
6 }
7
8 /* send response */
9 header('Content-Type: application/json');
10 echo json_encode((object)$result);

Rob Allen ~ @akrabat


router.php: init()
1 function init()
2 {
3 $post = file_get_contents('php://input');
4 $data = json_decode($post, true)['value'];
5
6 file_put_contents('index.php', $data['code']);
7
8 $config = ['function' => $data['main'], 'file' => 'index.php'];
9 file_put_contents('config.json', json_encode($config));
10
11 return ["OK" => true];
12 }

Rob Allen ~ @akrabat


router.php: run()
1 function run()
2 {
3 $config = file_get_contents('config.json');
4 $args = json_decode(file_get_contents('php://input'), true)['value'];
5
6 list($code, $out, $err) = runPHP('runner.php', $config, $args);
7
8 $pos = strrpos($stdout, PHP_EOL) + 1;
9 $lastLine = trim(substr($stdout, $pos));
10
11 file_put_contents("php://stderr", $stderr);
12 file_put_contents("php://stdout", $stdout);
13
14 return $lastLine;
15 }

Rob Allen ~ @akrabat


runner.php
Runs the user's code in a separate process
1 <?php
2 $config = json_decode($argv[1], true);
3 $functionName = $config['function'] ?? 'main';
4
5 $args = json_decode(file_get_contents('php://stdin') ?? [], true);
6
7 require '/action/vendor/autoload.php';
8 require '/action/src/index.php';
9 $result = $_functionName($args);
10
11 echo json_encode((object)$result);

Rob Allen ~ @akrabat


Hello world in PHP
hello.php:
1 <?php
2 function main(array $args) : array {
3 $name = $args["name"] ?? "World";
4 return [ "msg" => "Hello $name" ];
5 }
$ wsk action create hello hello.php --web true --kind php:7.1
ok: updated action hello

$ wsk action invoke -r hello -p name Rob


{
"msg": "Hello Rob"
}

Rob Allen ~ @akrabat


Time to execute: 500 milliseconds

Rob Allen ~ @akrabat


Let's look at some code!

Rob Allen ~ @akrabat


Summary

Rob Allen ~ @akrabat


Resources
• https://www.martinfowler.com/articles/serverless.html
• http://www.openwhisk.org
• https://medium.com/openwhisk

• http://github.com/apache/incubator-openwhisk/pull/2415
• https://github.com/akrabat/ow-php-ftime

Rob Allen ~ @akrabat


Thank you!
 
 
 
 
 
Rob Allen ~ @akrabat

You might also like