The Serverless PHP Application

A presentation at PHPUGFFM, September 2021 in September 2021 in 8700 Monrovia, Lenexa, KS 66215, USA by Rob Allen

Slide 1

Slide 1

The Serverless PHP Application Rob Allen PHPUGFFM, September 2021

Slide 2

Slide 2

Serverless? Rob Allen ~ @akrabat

Slide 3

Slide 3

Platform options Rob Allen ~ @akrabat

Slide 4

Slide 4

Platform options Rob Allen ~ @akrabat

Slide 5

Slide 5

Platform options Rob Allen ~ @akrabat

Slide 6

Slide 6

Platform options Rob Allen ~ @akrabat

Slide 7

Slide 7

Platform options Rob Allen ~ @akrabat

Slide 8

Slide 8

Platform options Rob Allen ~ @akrabat

Slide 9

Slide 9

Platform options Rob Allen ~ @akrabat

Slide 10

Slide 10

Serverless Serverless is all about composing software systems from a collection of cloud services. With serverless, you can lean on off-the-shelf cloud services resources for your application architecture, focus on business logic and application needs. Nate Taggart, CEO Stackery Rob Allen ~ @akrabat

Slide 11

Slide 11

FaaS Your code Rob Allen ~ @akrabat

Slide 12

Slide 12

FaaS Deployed to the cloud Rob Allen ~ @akrabat

Slide 13

Slide 13

FaaS Runs when needed Rob Allen ~ @akrabat

Slide 14

Slide 14

FaaS Scaled automatically Rob Allen ~ @akrabat

Slide 15

Slide 15

FaaS Pay only for execution Rob Allen ~ @akrabat

Slide 16

Slide 16

Where are the servers? Rob Allen ~ @akrabat

Slide 17

Slide 17

Rob Allen ~ @akrabat

Slide 18

Slide 18

Rob Allen ~ @akrabat

Slide 19

Slide 19

Use-cases Rob Allen ~ @akrabat

Slide 20

Slide 20

Use-cases Synchronous Service is invoked and provides immediate response (HTTP requests: APIs, chat bots) Rob Allen ~ @akrabat

Slide 21

Slide 21

Use-cases Synchronous Service is invoked and provides immediate response (HTTP requests: APIs, chat bots) Asynchronous Push a message which drives an action later (web hooks, timed events, database changes) Rob Allen ~ @akrabat

Slide 22

Slide 22

Benefits Rob Allen ~ @akrabat

Slide 23

Slide 23

Benefits • No need to maintain infrastructure Rob Allen ~ @akrabat

Slide 24

Slide 24

Benefits • No need to maintain infrastructure • Concentrate on application code Rob Allen ~ @akrabat

Slide 25

Slide 25

Benefits • No need to maintain infrastructure • Concentrate on application code • Pay only for what you use, when you use it Rob Allen ~ @akrabat

Slide 26

Slide 26

Benefits • • • • No need to maintain infrastructure Concentrate on application code Pay only for what you use, when you use it Language agnostic Rob Allen ~ @akrabat

Slide 27

Slide 27

Challenges Rob Allen ~ @akrabat

Slide 28

Slide 28

Challenges • Start up latency Rob Allen ~ @akrabat

Slide 29

Slide 29

Challenges • Start up latency • Time limit Rob Allen ~ @akrabat

Slide 30

Slide 30

Challenges • Start up latency • Time limit • State is external Rob Allen ~ @akrabat

Slide 31

Slide 31

Challenges • • • • Start up latency Time limit State is external Different way of thinking Rob Allen ~ @akrabat

Slide 32

Slide 32

When should you use serverless? Rob Allen ~ @akrabat

Slide 33

Slide 33

When should you use serverless? • Responding to web hooks Rob Allen ~ @akrabat

Slide 34

Slide 34

When should you use serverless? • Responding to web hooks • Additional features without extending current platform Rob Allen ~ @akrabat

Slide 35

Slide 35

When should you use serverless? • Responding to web hooks • Additional features without extending current platform • PWA/Static site contact form, et al. Rob Allen ~ @akrabat

Slide 36

Slide 36

When should you use serverless? • • • • Responding to web hooks Additional features without extending current platform PWA/Static site contact form, et al. Variable traffic levels Rob Allen ~ @akrabat

Slide 37

Slide 37

When should you use serverless? • • • • • Responding to web hooks Additional features without extending current platform PWA/Static site contact form, et al. Variable traffic levels When you want your costs to scale with traffic Rob Allen ~ @akrabat

Slide 38

Slide 38

It’s about value Rob Allen ~ @akrabat

Slide 39

Slide 39

Serverless platforms Rob Allen ~ @akrabat

Slide 40

Slide 40

Serverless languages Rob Allen ~ @akrabat

Slide 41

Slide 41

Serverless platforms with PHP support Rob Allen ~ @akrabat

Slide 42

Slide 42

Hello World AWS Lambda (Bref): <?php return function ($event) { $name = $event[‘name’] ?? ‘world’; return ‘Hello ’ . $name; }; Rob Allen ~ @akrabat

Slide 43

Slide 43

Hello World Apache OpenWhisk: <?php function main(array $args): array { $name = $args[‘name’] ?? ‘world’; return [“greeting” => ‘Hello ’ . $name]; } Rob Allen ~ @akrabat

Slide 44

Slide 44

Hello World OpenFAAS <?php class Handler { public function handle(string $data): void { $decoded = json_decode($data, true); $name = $decoded[‘name’] ?? ‘world’; return ‘Hello ’ . $name; } } Rob Allen ~ @akrabat

Slide 45

Slide 45

Hello World Google Cloud Functions (alpha) <?php use Psr\Http\Message\ServerRequestInterface as Request; function helloHttp(Request $request) { $name = $request->getQueryParams(‘name’) ?? ‘world’; return ‘Hello ’ . $name; } Rob Allen ~ @akrabat

Slide 46

Slide 46

Rob Allen ~ @akrabat

Slide 47

Slide 47

The anatomy of an action function main(array $args): array { // Marshall inputs from event parameters $name = $args[‘name’] ?? ‘world’; // Do the work $message = ‘Hello ’ . $name // Return result return [“body” => $message]; } Rob Allen ~ @akrabat

Slide 48

Slide 48

Hello World function main(array $args): array { // Marshall inputs from event parameters $name = $args[‘name’] ?? ‘world’; // Do the work $message = ‘Hello ’ . $name // Return result return [“body” => $message]; } Rob Allen ~ @akrabat

Slide 49

Slide 49

Hello World function main(array $args): array { // Marshall inputs from event parameters $name = $args[‘name’] ?? ‘world’; // Do the work $message = ‘Hello ’ . $name // Return result return [“body” => $message]; } Rob Allen ~ @akrabat

Slide 50

Slide 50

Hello World function main(array $args): array { // Marshall inputs from event parameters $name = $args[‘name’] ?? ‘world’; // Do the work $message = ‘Hello ’ . $name // Return result return [“body” => $message]; } Rob Allen ~ @akrabat

Slide 51

Slide 51

Hello World function main(array $args): array { // Marshall inputs from event parameters $name = $args[‘name’] ?? ‘world’; // Do the work $message = ‘Hello ’ . $name // Return result return [“body” => $message]; } Rob Allen ~ @akrabat

Slide 52

Slide 52

Deploy to OpenWhisk $ zip -q hello.zip hello.php Rob Allen ~ @akrabat

Slide 53

Slide 53

Deploy to OpenWhisk $ zip -q hello.zip hello.php $ wsk action update —kind php:7.4 hello hello.zip ok: updated action hello Rob Allen ~ @akrabat

Slide 54

Slide 54

Run it $ wsk action invoke hello —result —param name Rob Rob Allen ~ @akrabat

Slide 55

Slide 55

Run it $ wsk action invoke hello —result —param name Rob { “body”: “Hello Rob!” } Rob Allen ~ @akrabat

Slide 56

Slide 56

Under the hood Rob Allen ~ @akrabat

Slide 57

Slide 57

OpenWhisk’s architecture Rob Allen ~ @akrabat

Slide 58

Slide 58

Create an action Rob Allen ~ @akrabat

Slide 59

Slide 59

Invoke an action Rob Allen ~ @akrabat

Slide 60

Slide 60

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

Slide 61

Slide 61

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

Slide 62

Slide 62

Architecture Rob Allen ~ @akrabat

Slide 63

Slide 63

Monolith architecture Rob Allen ~ @akrabat

Slide 64

Slide 64

Serverless architecture Rob Allen ~ @akrabat

Slide 65

Slide 65

Serverless architecture pattern Rob Allen ~ @akrabat

Slide 66

Slide 66

Functions are key Rob Allen ~ @akrabat

Slide 67

Slide 67

Functions are the Unit of Deployment Rob Allen ~ @akrabat

Slide 68

Slide 68

Functions are the Unit of Scale Rob Allen ~ @akrabat

Slide 69

Slide 69

Functions are Stateless Rob Allen ~ @akrabat

Slide 70

Slide 70

Functions have Structure Rob Allen ~ @akrabat

Slide 71

Slide 71

Structure If it’s non-trivial, software engineering principles apply! • Use multiple methods Rob Allen ~ @akrabat

Slide 72

Slide 72

Structure If it’s non-trivial, software engineering principles apply! • Use multiple methods • Use multiple files Rob Allen ~ @akrabat

Slide 73

Slide 73

Structure If it’s non-trivial, software engineering principles apply! • Use multiple methods • Use multiple files • Integrate reusable dependencies Rob Allen ~ @akrabat

Slide 74

Slide 74

Rob Allen ~ @akrabat

Slide 75

Slide 75

AWS Lambda with PHP Relies on Lambda’s layers system Process: 1. Create a layer containing: 1. the PHP executable 2. a bootstrap script 2. Write the PHP function! Rob Allen ~ @akrabat

Slide 76

Slide 76

.

Slide 77

Slide 77

Bref PHP function index.php: <?php declare(strict_types=1); require DIR . ‘/vendor/autoload.php’; return function($event) { return ‘Hello ’ . ($event[‘name’] ?? ‘world’); } Rob Allen ~ @akrabat

Slide 78

Slide 78

serverless.yml service: helloapp provider: name: aws runtime: provided.al2 functions: hello: handler: index.php layers: - ${bref:layer.php-80} Rob Allen ~ @akrabat

Slide 79

Slide 79

serverless.yml service: helloapp provider: name: aws runtime: provided.al2 functions: hello: handler: index.php layers: - ${bref:layer.php-80} Rob Allen ~ @akrabat

Slide 80

Slide 80

serverless.yml service: helloapp provider: name: aws runtime: provided.al2 functions: hello: handler: index.php layers: - ${bref:layer.php-80} Rob Allen ~ @akrabat

Slide 81

Slide 81

Deploy $ serverless deploy Serverless: Packaging service… … Serverless: Stack update finished… Service Information service: helloapp stage: dev region: eu-west-2 stack: helloapp-dev functions: hello: helloapp-dev-hello Rob Allen ~ @akrabat

Slide 82

Slide 82

Run $ serverless invoke -f hello “Hello world” Rob Allen ~ @akrabat

Slide 83

Slide 83

Run $ serverless invoke -f hello “Hello world” $ serverless invoke -f hello -d ‘{“name”: “Rob”}’ “Hello Rob” Rob Allen ~ @akrabat

Slide 84

Slide 84

Run locally in Docker $ serverless invoke local —docker -f hello Serverless: Building Docker image… … REPORT RequestId: 6a653a94-ee51-1f3e-65c7-1f1954842f29 Init Duration: 265.93 ms Duration: 145.37 ms Billed Duration: 200 ms Memory Size: 1024 MB Max Memory Used: 27 MB “Hello world” Xdebug also works! Rob Allen ~ @akrabat

Slide 85

Slide 85

Add AWS API Gateway serverless.yml: functions: hello: handler: index.php … events: - http: “GET /hello” - http: “GET /hi/{name}” Rob Allen ~ @akrabat

Slide 86

Slide 86

Return a PSR-15 RequestHandler class HelloHandler implements RequestHandlerInterface { public function handle(ServerRequest $request): Response { $name = ($request->getQueryParams()[‘name’] ?? ‘world’); $body = ‘Hello ’ . $name; return new Response(200, [‘Content-Type’ => ‘text/plain’], $body); } } Rob Allen ~ @akrabat

Slide 87

Slide 87

Deploy $ serverless deploy Serverless: Packaging service… … Service Information service: helloapp stage: dev stack: helloapp-dev endpoints: GET - https://l1v6cz13zb.execute-api.eu-west-2 .amazonaws.com/dev/hello Rob Allen ~ @akrabat

Slide 88

Slide 88

Test $ curl -i https://l1v6cz…naws.com/dev/hello?name=Rob HTTP/2 200 content-type: text/plain content-length: 9 Hello Rob Rob Allen ~ @akrabat

Slide 89

Slide 89

Case study Project 365 photo website Rob Allen ~ @akrabat

Slide 90

Slide 90

Project 365 Static website to display my photo-a-day picture for each day of the year. • Hosted on S3 • CloudFront CDN • Lambda/PHP function Rob Allen ~ @akrabat

Slide 91

Slide 91

Lambda/PHP function Rob Allen ~ @akrabat

Slide 92

Slide 92

Infrastructure as code serverless.yml: functions: update: handler: update.php layers: - ${bref:layer.php-80} events: - schedule: rate: cron(0 */2 * * ? *) Rob Allen ~ @akrabat

Slide 93

Slide 93

Infrastructure as code functions: update: handler: update.php layers: - ${bref:layer.php-80} events: - schedule: rate: cron(0 */2 * * ? *) Rob Allen ~ @akrabat

Slide 94

Slide 94

Infrastructure as code functions: update: handler: update.php layers: - ${bref:layer.php-80} events: - schedule: rate: cron(0 */2 * * ? *) Rob Allen ~ @akrabat

Slide 95

Slide 95

Infrastructure as code functions: update: handler: update.php layers: - ${bref:layer.php-80} events: - schedule: rate: cron(0 */2 * * ? *) Rob Allen ~ @akrabat

Slide 96

Slide 96

Process 1. 2. 3. 4. 5. Gather credentials from environment Download photos from Flickr API Create HTML page Upload to S3 Invalidate CloudFront cache Rob Allen ~ @akrabat

Slide 97

Slide 97

main() return function ($event) { $year = $event[‘year’] ?? date(‘Y’); $photos = (new PhotoFetcher())->fetchForYear($year); $html = (new PageCreator())->create($year, $photos); $filename = “$year.html”; $uploader = new Uploader(); $uploader->uploadOne($filename, $html, $s3Bucket); $uploader->invalidateCache($filename); } Rob Allen ~ @akrabat

Slide 98

Slide 98

main() return function ($event) { $year = $event[‘year’] ?? date(‘Y’); $photos = (new PhotoFetcher())->fetchForYear($year); $html = (new PageCreator())->create($year, $photos); $filename = “$year.html”; $uploader = new Uploader(); $uploader->uploadOne($filename, $html, $s3Bucket); $uploader->invalidateCache($filename); } Rob Allen ~ @akrabat

Slide 99

Slide 99

main() return function ($event) { $year = $event[‘year’] ?? date(‘Y’); $photos = (new PhotoFetcher())->fetchForYear($year); $html = (new PageCreator())->create($year, $photos); $filename = “$year.html”; $uploader = new Uploader(); $uploader->uploadOne($filename, $html, $s3Bucket); $uploader->invalidateCache($filename); } Rob Allen ~ @akrabat

Slide 100

Slide 100

main() return function ($event) { $year = $event[‘year’] ?? date(‘Y’); $photos = (new PhotoFetcher())->fetchForYear($year); $html = (new PageCreator())->create($year, $photos); $filename = “$year.html”; $uploader = new Uploader(); $uploader->uploadOne($filename, $html, $s3Bucket); $uploader->invalidateCache($filename); } Rob Allen ~ @akrabat

Slide 101

Slide 101

main() return function ($event) { $year = $event[‘year’] ?? date(‘Y’); $photos = (new PhotoFetcher())->fetchForYear($year); $html = (new PageCreator())->create($year, $photos); $filename = “$year.html”; $uploader = new Uploader(); $uploader->uploadOne($filename, $html, $s3Bucket); $uploader->invalidateCache($filename); } Rob Allen ~ @akrabat

Slide 102

Slide 102

The finished website Rob Allen ~ @akrabat

Slide 103

Slide 103

To sum up Rob Allen ~ @akrabat

Slide 104

Slide 104

Thank you! Rob Allen ~ @akrabat

Slide 105

Slide 105

Photo credits - Assembly line: https://www.flickr.com/photos/adiram/3886212918 - Under the hood: https://www.flickr.com/photos/atomichotlinks/7736849388 - Pantheon: https://www.flickr.com/photos/shawnstilwell/4335732627 - Watch mechanism: https://www.flickr.com/photos/shinythings/2168994732 - Holiday snaps: https://www.flickr.com/photos/kjgarbutt/5358075923 - Rocket launch: https://www.flickr.com/photos/gsfc/16495356966 - Stars: https://www.flickr.com/photos/gsfc/19125041621 Rob Allen ~ @akrabat