PHP ON LAMBDA
WITH CUSTOM RUNTIMES
MergePHP January 2024
Ian Littman / @ian@phpc.social / @iansltx
Follow along at https://ian.im/lambmerge24
Questions We'll Answer
- Why you'd use Lambda, and what caveats come with using it
- How Lambda works with Custom Runtimes (including PHP)
- How to build an email reply bot with Lambda, SES, S3, and PHP
- How to build a Lambda-powered API via
- API Gateway
- Function URLs
- Bonus: How to build API Gateway endpoints with Bref
Topics We won't cover
- A deep dive into Bref or Serverless Framework
- Building Lambda applications via AWS's CLI
- AWS SAM
- Laravel Vapor
WHY LAMBDA?
- No servers to manage
- No worrying about concurrency within an app instance
- Quick automatic scaling + high levels of concurrency
- Millisecond-level billing + fair-sized free tier
- Stateless per-request, shared-nothing-ish
thanks to Firecracker microVMs - Integrates with other AWS components
What kinds of integrations?
- Trigger events from S3, SNS, SQS...and a lot more
- Application Load Balancer (billed for capacity + time)
- API Gateway (billed per request)
- Directly via AWS's APIs (sync or async)
- Directly via HTTP with Function URLs (more info)
Shared-nothing-ish?
-
AWS keeps Lambda containers around for a bit
to avoid "cold start" penalties- Cold start penalties are proportional to bundle size
- Sometimes AWS will proactively init
- weathermap
- /tmp storage available per-instance; can use as a cache
- 512 MB by default
- Up to 10 GiB if you pay for it
- Instances
- != invocations
- == concurrency
A note on performance
- CPU time allocation (speed) scales with RAM allotment
- Minimum: 128 MB
- Maximum:
3008 MB10240 MB - Increment size: 64 MB
- At 1792 MB you have one full core (stop there)
- Up to 6 cores
- Using Serverless Framework (e.g. via Bref)? Default is 1024 MB
- There are a few other limits to keep in mind
A note on Billing
- Billed per GB/s, rounded to the nearest ms
- Includes init (for custom runtimes) and execution,
including I/O wait - Init phase gets you more CPU + RAM
- arm64 is cheaper than x86 and performs well enough
Virtual Private Caveats
- No internet connectivity by default
- NAT Gateway is $$$ (4.5¢/hr + 4.5¢/GB in main US regions)
- Workaround: split functionality between functions
- Internet-connected, outside VPC (external APIs)
- Internet-disconnected, inside VPC (internal resources)
- Pass info between via queues, S3, etc.
- Public IPv4s cost money as of February 1
- IPv6 IPs are free, and now you can use them outbound
- Cold start times No longer an issue as of late 2019
So, what about PHP on Lambda?
- Custom runtime support has been available since 2018
- Build the file system needed to run your function code
- Store the file system as one or more (up to 5) Layers
- Worker-based, long-polling-esque model
- NOT HTTP request based without additional abstractions
- Built on top of Amazon Linux 2023
- Can also specify AL2 or original Amazon Linux
- Extracted to /opt (function code is in /var/task)
- Versioned
- Can include library dependencies (e.g. /vendor)
- Zipped + submitted to AWS API (like functions)
- Function specifies inclusion order
Custom runtime lifecycle
- Bootstrap (cold start)
- Task execution (warm start)
- Lambda decides when to kill the instance
- Inactivity timeout
- Task deadline (configurable, up to 15 minutes)
- Explicitly exiting the bootstrap process
(due to error or otherwise)
- Initialize runtime
- Prep function for execution
- Pass env vars including file/method for handler function
- If there's an error init-ing, make an API call
- Pro tip: do heavy work impacting shared state here
Task execution (warm start) Phase
- Call APIs to process work
-
Next invocation (GET)
- Request ID and more in headers
- Task data in response body, JSON-encoded
-
Invocation response (POST)
- Request ID in URL
- Response in body
- Consuming services may require specific format
- Can perform (billed) cleanup between calling response
endpoint and requesting the next invocation
Logging & Errors
- Invocation error (POST)
- STDOUT -> CloudWatch Logs
- Metrics available via CloudWatch (or in function UI)
- Lambda Telemetry API for more advanced metrics
- Slower to start
- Images can be up 10 GB total
-
Still need to interact with the Lambda runtime API
- AWS base images include the Lambda Runtime Interface Client
- AWS provides Runtime Interface Clients for some languages
- ...but not PHP...
- ...so just use the bootstrap files we already have
- You can test with the Runtime Interface Emulator
- No function URL support
What might this look like from AWS's Side?
- Are any workers for target function waiting on work?
- If so, skip to step 3; if not...
- Build a new instance (container or layers + function code)
- Run /opt/bootstrap (or /var/task/bootstrap,
or container entrypoint) - Wait for it to do one of the following
- Return nonzero from the bootstrap (init failure)
- Call the init error API endpoint
- Call the task request API endpoint
- Respond to the next invocation endpoint with event
- Wait for API calls to invocation success/failure or timeout,
whichever comes first
- SES rule pushes email to S3
- S3 triggers Lambda
- Lambda function executes...
- Grabs email from S3
- Parses using MIME parser
- RaNdOMlY CaPiTaLiZeS LEtTerS
- Sends email reply via SES
- HTTP request hits API Gateway
- Lambda function executes...
- Grabs query string parameter if there is one
- RaNdOMlY CaPiTaLiZeS LEtTerS
- Sends a JSON response
- API Gateway turns the Lambda payload into an HTTP response
- HTTP request hits function URL
- Lambda function executes...
- Grabs query string parameter if there is one
- RaNdOMlY CaPiTaLiZeS LEtTerS
- Sends a JSON response
...but you should probably use Bref in prod
...or Vapor, if you're using Laravel
Thanks! Questions?
- https://ian.im/lambmerge24 - this presentation
- https://github.com/iansltx/spongebot - sample code
- https://phpc.social/@ian - me
- https://twitter.com/iansltx - also me
- https://github.com/iansltx - my code
PHP on Lambda with Custom Runtimes - MergePHP January 2024
By Ian Littman
PHP on Lambda with Custom Runtimes - MergePHP January 2024
It's 2024 and, while AWS still doesn't have an official PHP runtime for Lambda, it doesn't need one thanks to both custom runtime and container support in Lambda. This talk will show you how Lambda custom runtimes work, how to build one that speaks PHP, and how to set up Lambda to either handle web requests or hook into other AWS services to process jobs in a highly elastic manner. As a bonus, you'll see how things work with Lambda's Docker container support, as well as with Bref, the tooling you'll likely want to use if you choose to deploy PHP Lambdas in production without restoring to e.g. Laravel Vapor.
- 268