The Serverless Application Rob Allen November 2019

Serverless? Rob Allen ~ @akrabat

Platform options Rob Allen ~ @akrabat

Platform options Rob Allen ~ @akrabat

Platform options Rob Allen ~ @akrabat

Platform options Rob Allen ~ @akrabat

Platform options Rob Allen ~ @akrabat

Platform options Rob Allen ~ @akrabat

Platform options Rob Allen ~ @akrabat

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

FaaS Your code Rob Allen ~ @akrabat

FaaS Deployed to the cloud Rob Allen ~ @akrabat

FaaS Runs when needed Rob Allen ~ @akrabat

FaaS Scaled automatically Rob Allen ~ @akrabat

FaaS Pay only for execution Rob Allen ~ @akrabat

Where are the servers? Rob Allen ~ @akrabat

Rob Allen ~ @akrabat

Rob Allen ~ @akrabat

Use-cases Rob Allen ~ @akrabat

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

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

Benefits Rob Allen ~ @akrabat

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

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

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

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

Challenges Rob Allen ~ @akrabat

Challenges • Start up latency Rob Allen ~ @akrabat

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

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

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

When should you use serverless? Rob Allen ~ @akrabat

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

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

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

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

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

Serverless platforms Rob Allen ~ @akrabat

Hello World AWS Lambda: def my_handler(event, context): name = event.get(“name”, “World”) message = ‘Hello {}!’.format(name) return {‘message’: message} Rob Allen ~ @akrabat

Hello World Apache OpenWhisk: def main(args): name = args.get(“name”, “World”) message = ‘Hello {}!’.format(name) return {‘message’: message} Rob Allen ~ @akrabat

Hello World Google Cloud Functions def hello_http(request): name = request.json.get(“name”, “World”) message = ‘Hello {}!’.format(name) return message Rob Allen ~ @akrabat

Hello World Azure Cloud Functions import azure.functions as func def main(req: func.HttpRequest, msg: func.Out[func.QueueMessage]) -> str: name = req.params.json.get(“name”, “World”) message = ‘Hello {}!’.format(name) msg.set(message) return message Rob Allen ~ @akrabat

Rob Allen ~ @akrabat

Rob Allen ~ @akrabat

The anatomy of an action def main(args): # Marshall inputs from event parameters name = args.get(“name”, “World”) # Do the work message = ‘Hello {}!’.format(name) # return result return {‘body’: message} Rob Allen ~ @akrabat

Hello World def main(args): # Marshall inputs from event parameters name = args.get(“name”, “World”) # Do the work message = ‘Hello {}!’.format(name) # return result return {‘body’: message} Rob Allen ~ @akrabat

Hello World def main(args): # Marshall inputs from event parameters name = args.get(“name”, “World”) # Do the work message = ‘Hello {}!’.format(name) # return result return {‘body’: message} Rob Allen ~ @akrabat

Hello World def main(args): # Marshall inputs from event parameters name = args.get(“name”, “World”) # Do the work message = ‘Hello {}!’.format(name) # return result return {‘body’: message} Rob Allen ~ @akrabat

Hello World def main(args): # Marshall inputs from event parameters name = args.get(“name”, “World”) # Do the work message = ‘Hello {}!’.format(name) # return result return {‘body’: message} Rob Allen ~ @akrabat

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

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

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

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

Under the hood Rob Allen ~ @akrabat

OpenWhisk’s architecture 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 lifecycle • Hosts the user-written code • Controlled via two end points: /init & /run Rob Allen ~ @akrabat

Architecture Rob Allen ~ @akrabat

Monolith architecture Rob Allen ~ @akrabat

Serverless architecture Rob Allen ~ @akrabat

Serverless architecture pattern Rob Allen ~ @akrabat

Functions are key Rob Allen ~ @akrabat

Functions are the Unit of Deployment Rob Allen ~ @akrabat

Functions are the Unit of Scale Rob Allen ~ @akrabat

Functions are Stateless Rob Allen ~ @akrabat

Functions have Structure Rob Allen ~ @akrabat

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

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

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

Serverless state machines Rob Allen ~ @akrabat

Serverless state machines Rob Allen ~ @akrabat

Rob Allen ~ @akrabat

Rob Allen ~ @akrabat

Case study Project 365 photo website Rob Allen ~ @akrabat

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

Lambda/PHP function Rob Allen ~ @akrabat

Infrastructure as code functions: update: handler: src/actions/update.main layers: - {Ref: PhpLambdaLayer} environment: FLICKR_API_KEY: ${self:custom.FLICKR_API_KEY} FLICKR_USER_ID: ${self:custom.FLICKR_USER_ID} events: - schedule: name: project365-build rate: cron(0 */2 * * ? *) Rob Allen ~ @akrabat

Infrastructure as code functions: update: handler: src/actions/update.main environment: FLICKR_API_KEY: ${self:custom.FLICKR_API_KEY} FLICKR_USER_ID: ${self:custom.FLICKR_USER_ID} events: - schedule: name: project365-build rate: cron(0 */2 * * ? *) Rob Allen ~ @akrabat

Infrastructure as code functions: update: handler: src/actions/update.main environment: FLICKR_API_KEY: ${self:custom.FLICKR_API_KEY} FLICKR_USER_ID: ${self:custom.FLICKR_USER_ID} events: - schedule: name: project365-build rate: cron(0 */2 * * ? *) Rob Allen ~ @akrabat

Infrastructure as code functions: update: handler: src/actions/update.main environment: FLICKR_API_KEY: ${self:custom.FLICKR_API_KEY} FLICKR_USER_ID: ${self:custom.FLICKR_USER_ID} events: - schedule: name: project365-build rate: cron(0 */2 * * ? *) Rob Allen ~ @akrabat

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

main() function main(array $eventData) : array { $apiKey = getEnvVar(‘P365_FLICKR_API_KEY’); $userId = getEnvVar(‘P365_FLICKR_USER_ID’); $year = $eventData[‘year’] ?? date(‘Y’); $pageCreator = new PhotoPageCreator($apiKey); $html = $pageCreator->update($year, $userId); $uploader = new Uploader($cloudFrontId); $uploader->uploadOne($filename, $html, $s3Bucket); $uploader->invalidate([‘/’.$filename]); } Rob Allen ~ @akrabat

main() function main(array $eventData) : array { $apiKey = getEnvVar(‘P365_FLICKR_API_KEY’); $userId = getEnvVar(‘P365_FLICKR_USER_ID’); $year = $eventData[‘year’] ?? date(‘Y’); $pageCreator = new PhotoPageCreator($apiKey); $html = $pageCreator->update($year, $userId); $uploader = new Uploader($cloudFrontId); $uploader->uploadOne($filename, $html, $s3Bucket); $uploader->invalidate([‘/’.$filename]); } Rob Allen ~ @akrabat

main() function main(array $eventData) : array { $apiKey = getEnvVar(‘P365_FLICKR_API_KEY’); $userId = getEnvVar(‘P365_FLICKR_USER_ID’); $year = $eventData[‘year’] ?? date(‘Y’); $pageCreator = new PhotoPageCreator($apiKey); $html = $pageCreator->update($year, $userId); $uploader = new Uploader($cloudFrontId); $uploader->uploadOne($filename, $html, $s3Bucket); $uploader->invalidate([‘/’.$filename]); } Rob Allen ~ @akrabat

main() function main(array $eventData) : array { $apiKey = getEnvVar(‘P365_FLICKR_API_KEY’); $userId = getEnvVar(‘P365_FLICKR_USER_ID’); $year = $eventData[‘year’] ?? date(‘Y’); $pageCreator = new PhotoPageCreator($apiKey); $html = $pageCreator->update($year, $userId); $uploader = new Uploader($cloudFrontId); $uploader->uploadOne($filename, $html, $s3Bucket); $uploader->invalidate([‘/’.$filename]); } Rob Allen ~ @akrabat

The finished website Rob Allen ~ @akrabat

Demo Rob Allen ~ @akrabat

To sum up Rob Allen ~ @akrabat

Resources • https://akrabat.com • https://www.martinfowler.com/articles/serverless.html • https://github.com/akrabat/ow-php-todo-backend • https://github.com/akrabat/project365-photos-website • http://www.openwhisk.org • https://aws.amazon.com/lambda/ • https://bref.sh Rob Allen ~ @akrabat

Thank you! Rob Allen ~ @akrabat

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 - Computer code: https://www.flickr.com/photos/n3wjack/3856456237 - Rocket launch: https://www.flickr.com/photos/gsfc/16495356966 - Stars: https://www.flickr.com/photos/gsfc/19125041621 Rob Allen ~ @akrabat