The Serverless PHP Application Rob Allen
The Online PHP Conference, January 2021
Slide 2
Serverless?
Rob Allen ~ @akrabat
Slide 3
Platform options
Rob Allen ~ @akrabat
Slide 4
Platform options
Rob Allen ~ @akrabat
Slide 5
Platform options
Rob Allen ~ @akrabat
Slide 6
Platform options
Rob Allen ~ @akrabat
Slide 7
Platform options
Rob Allen ~ @akrabat
Slide 8
Platform options
Rob Allen ~ @akrabat
Slide 9
Platform options
Rob Allen ~ @akrabat
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
FaaS
Your code
Rob Allen ~ @akrabat
Slide 12
FaaS
Deployed to the cloud
Rob Allen ~ @akrabat
Slide 13
FaaS
Runs when needed
Rob Allen ~ @akrabat
Slide 14
FaaS
Scaled automatically
Rob Allen ~ @akrabat
Slide 15
FaaS
Pay only for execution
Rob Allen ~ @akrabat
Slide 16
Where are the servers?
Rob Allen ~ @akrabat
Slide 17
Rob Allen ~ @akrabat
Slide 18
Rob Allen ~ @akrabat
Slide 19
Use-cases
Rob Allen ~ @akrabat
Slide 20
Use-cases Synchronous Service is invoked and provides immediate response (HTTP requests: APIs, chat bots)
Rob Allen ~ @akrabat
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
Benefits
Rob Allen ~ @akrabat
Slide 23
Benefits • No need to maintain infrastructure
Rob Allen ~ @akrabat
Slide 24
Benefits • No need to maintain infrastructure • Concentrate on application code
Rob Allen ~ @akrabat
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
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
Challenges
Rob Allen ~ @akrabat
Slide 28
Challenges • Start up latency
Rob Allen ~ @akrabat
Slide 29
Challenges • Start up latency • Time limit
Rob Allen ~ @akrabat
Slide 30
Challenges • Start up latency • Time limit • State is external
Rob Allen ~ @akrabat
Slide 31
Challenges • Start up latency • Time limit • State is external • Different way of thinking
Rob Allen ~ @akrabat
Slide 32
When should you use serverless?
Rob Allen ~ @akrabat
Slide 33
When should you use serverless? • Responding to web hooks
Rob Allen ~ @akrabat
Slide 34
When should you use serverless? • Responding to web hooks • Additional features without extending current platform
Rob Allen ~ @akrabat
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
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
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
It’s about value
Rob Allen ~ @akrabat
Slide 39
Serverless platforms
Rob Allen ~ @akrabat
Slide 40
Serverless languages
Rob Allen ~ @akrabat
Slide 41
Serverless platforms with PHP support
Rob Allen ~ @akrabat
Slide 42
Hello World AWS Lambda (Bref): <?php return function ($event) { $name = $event[‘name’] ?? ‘world’; return ‘Hello ’ . $name; };
Rob Allen ~ @akrabat
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
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
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
Rob Allen ~ @akrabat
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
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
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
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
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
Deploy to OpenWhisk $ zip -q hello.zip hello.php
Rob Allen ~ @akrabat
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
Run it $ wsk action invoke hello —result —param name Rob
Rob Allen ~ @akrabat
Slide 55
Run it $ wsk action invoke hello —result —param name Rob { “body”: “Hello Rob!” }
Rob Allen ~ @akrabat
Slide 56
Under the hood
Rob Allen ~ @akrabat
Slide 57
OpenWhisk’s architecture
Rob Allen ~ @akrabat
Slide 58
Create an action
Rob Allen ~ @akrabat
Slide 59
Invoke an action
Rob Allen ~ @akrabat
Slide 60
Action container lifecycle • Hosts the user-written code • Controlled via two end points: /init & /run
Rob Allen ~ @akrabat
Slide 61
Action container lifecycle • Hosts the user-written code • Controlled via two end points: /init & /run
Rob Allen ~ @akrabat
Slide 62
Architecture
Rob Allen ~ @akrabat
Slide 63
Monolith architecture
Rob Allen ~ @akrabat
Slide 64
Serverless architecture
Rob Allen ~ @akrabat
Slide 65
Serverless architecture pattern
Rob Allen ~ @akrabat
Slide 66
Functions are key
Rob Allen ~ @akrabat
Slide 67
Functions are the Unit of Deployment
Rob Allen ~ @akrabat
Slide 68
Functions are the Unit of Scale
Rob Allen ~ @akrabat
Slide 69
Functions are Stateless
Rob Allen ~ @akrabat
Slide 70
Functions have Structure
Rob Allen ~ @akrabat
Slide 71
Structure If it’s non-trivial, software engineering principles apply! • Use multiple methods
Rob Allen ~ @akrabat
Slide 72
Structure If it’s non-trivial, software engineering principles apply! • Use multiple methods • Use multiple files
Rob Allen ~ @akrabat
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
Serverless state machines
Rob Allen ~ @akrabat
Slide 75
Serverless state machines
Rob Allen ~ @akrabat
Slide 76
Rob Allen ~ @akrabat
Slide 77
Rob Allen ~ @akrabat
Slide 78
Case study Project 365 photo website
Rob Allen ~ @akrabat
Slide 79
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 80
Lambda/PHP function
Rob Allen ~ @akrabat
Slide 81
Infrastructure as code serverless.yml: functions: update: handler: update.php events: - schedule: name: project365-build rate: cron(0 */2 * * ? *)
Rob Allen ~ @akrabat
Slide 82
Infrastructure as code functions: update: handler: update.php events: - schedule: name: project365-build rate: cron(0 */2 * * ? *)
Rob Allen ~ @akrabat
Slide 83
Infrastructure as code functions: update: handler: update.php events: - schedule: name: project365-build rate: cron(0 */2 * * ? *)
Rob Allen ~ @akrabat
Slide 84
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 85
main() return function ($event) { $year = $event[‘year’] ?? date(‘Y’); $photos = (new PhotoFetcher())->fetchForYear($year); $html = (new PageCreator())->create($year, $photos); $uploader = new Uploader(); $uploader->uploadOne($year, $html, $s3Bucket); $uploader->invalidateCache([‘/’.$year]); } Rob Allen ~ @akrabat
Slide 86
main() return function ($event) { $year = $event[‘year’] ?? date(‘Y’); $photos = (new PhotoFetcher())->fetchForYear($year); $html = (new PageCreator())->create($year, $photos); $uploader = new Uploader(); $uploader->uploadOne($year, $html, $s3Bucket); $uploader->invalidateCache([‘/’.$year]); } Rob Allen ~ @akrabat
Slide 87
main() return function ($event) { $year = $event[‘year’] ?? date(‘Y’); $photos = (new PhotoFetcher())->fetchForYear($year); $html = (new PageCreator())->create($year, $photos); $uploader = new Uploader(); $uploader->uploadOne($year, $html, $s3Bucket); $uploader->invalidateCache([‘/’.$year]); } Rob Allen ~ @akrabat
Slide 88
main() return function ($event) { $year = $event[‘year’] ?? date(‘Y’); $photos = (new PhotoFetcher())->fetchForYear($year); $html = (new PageCreator())->create($year, $photos); $uploader = new Uploader(); $uploader->uploadOne($year, $html, $s3Bucket); $uploader->invalidateCache([‘/’.$year]); } Rob Allen ~ @akrabat
Slide 89
main() return function ($event) { $year = $event[‘year’] ?? date(‘Y’); $photos = (new PhotoFetcher())->fetchForYear($year); $html = (new PageCreator())->create($year, $photos); $uploader = new Uploader(); $uploader->uploadOne($year, $html, $s3Bucket); $uploader->invalidateCache([‘/’.$year]); } Rob Allen ~ @akrabat
Slide 90
The finished website
Rob Allen ~ @akrabat
Slide 91
To sum up
Rob Allen ~ @akrabat
Slide 92
Thank you!
Rob Allen ~ @akrabat
Slide 93
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