Skip to content

Commit 8d9faae

Browse files
committed
bref: idiomatic layer layout + Lambda deploy example & docs
Align the Lambda artifacts with Bref's own convention (as used by brefphp/extra-php-extensions) so a release drops in like any other Bref extension and the same binary works for both layer and Docker deploys: - Layer zip now ships bref/extensions/quickjs.so (Bref's extension_dir) and bref/etc/php/conf.d/ext-quickjs.ini with a bare `extension=quickjs.so`, instead of an /opt/php-quickjs/*.so with an absolute path. - Add examples/lambda/ — a runnable skeleton: a Bref function handler that runs a TS guest, a Dockerfile (FROM bref/php-84:3, copies the .so into /opt/bref/extensions), and a serverless.yml covering both the container image and the layer route. - Expand docs/install.md's AWS Lambda section to document all three paths (Docker image, Lambda layer, vendored .so) and how Bref loads extensions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R3vgA3Q6PR9VQn8X5pLcMR
1 parent 09eb940 commit 8d9faae

6 files changed

Lines changed: 210 additions & 23 deletions

File tree

.github/workflows/release.yml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,14 @@ jobs:
125125
- name: Package Bref Lambda layer
126126
run: |
127127
ver="${{ inputs.version }}"; php="${{ matrix.php }}"; arch="${{ matrix.arch }}"
128-
# Layer is mounted at /opt on Lambda; Bref scans /opt/bref/etc/php/conf.d.
129-
mkdir -p layer/php-quickjs layer/bref/etc/php/conf.d
130-
cp dist/quickjs.so layer/php-quickjs/quickjs.so
131-
echo 'extension=/opt/php-quickjs/quickjs.so' > layer/bref/etc/php/conf.d/quickjs.ini
128+
# Idiomatic Bref layout (matches brefphp/extra-php-extensions): the
129+
# layer mounts at /opt, Bref's extension_dir is /opt/bref/extensions,
130+
# and it scans /opt/bref/etc/php/conf.d for *.ini. So the .so drops in
131+
# by bare name and the ini just says `extension=quickjs.so` — the same
132+
# binary + ini then work identically in a Docker `FROM bref/php-*`.
133+
mkdir -p layer/bref/extensions layer/bref/etc/php/conf.d
134+
cp dist/quickjs.so layer/bref/extensions/quickjs.so
135+
echo 'extension=quickjs.so' > layer/bref/etc/php/conf.d/ext-quickjs.ini
132136
( cd layer && zip -qr "../php-quickjs-v${ver}-php${php}-lambda-bref-${arch}.zip" . )
133137
cp dist/quickjs.so "php-quickjs-v${ver}-php${php}-lambda-bref-${arch}.so"
134138

docs/install.md

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,35 @@ RUN echo 'extension=/usr/local/lib/php/quickjs.so' > /usr/local/etc/php/conf.d/q
4343

4444
## AWS Lambda (Bref)
4545

46-
The `lambda-bref-*.zip` is a **Lambda layer**: it contains the extension plus a
47-
`conf.d` ini that enables it. Add it as a layer alongside the Bref runtime layer
48-
and the extension loads automatically.
46+
A Bref function is the runtime layer mounted at `/opt` plus your code at
47+
`/var/task`. PHP scans `*.ini` from `/opt/bref/etc/php/conf.d/` (layers) and your
48+
project's `php/conf.d/`; Bref's `extension_dir` is `/opt/bref/extensions`. The
49+
release artifacts follow that convention, so the **same `.so` + ini work whether
50+
you go via a layer or a Docker image**.
4951

50-
In `serverless.yml`:
52+
Match the **architecture** (`arm64` for Graviton, `x86_64` otherwise) and the
53+
**PHP version** to your Bref runtime. There's a runnable skeleton (handler +
54+
`Dockerfile` + `serverless.yml`) in [`examples/lambda/`](../examples/lambda).
5155

52-
```yaml
53-
functions:
54-
api:
55-
handler: index.php
56-
runtime: php-84 # Bref PHP 8.4 runtime
57-
layers:
58-
- arn:aws:lambda:<region>:<account>:layer:php-quickjs-php84-arm64:<n>
56+
### Docker image (recommended for custom binaries)
57+
58+
Bake the released `.so` into a `FROM bref/php-XX:3` image:
59+
60+
```dockerfile
61+
FROM bref/php-84:3
62+
COPY php-quickjs-vX-php8.4-lambda-bref-arm64.so /opt/bref/extensions/quickjs.so
63+
RUN echo 'extension=quickjs.so' > /opt/bref/etc/php/conf.d/ext-quickjs.ini
64+
COPY . /var/task
5965
```
6066

61-
To create the layer from the released zip:
67+
Deploy it as a container image (`provider.ecr.images` + `functions.*.image` in
68+
`serverless.yml` — see the example).
69+
70+
### Lambda layer (the `lambda-bref-*.zip`)
71+
72+
The zip is a ready layer: it contains `bref/extensions/quickjs.so` and
73+
`bref/etc/php/conf.d/ext-quickjs.ini` (which simply says `extension=quickjs.so`).
74+
Publish it, then reference its ARN alongside the Bref runtime:
6275

6376
```sh
6477
aws lambda publish-layer-version \
@@ -67,14 +80,22 @@ aws lambda publish-layer-version \
6780
--zip-file fileb://php-quickjs-vX-php8.4-lambda-bref-arm64.zip
6881
```
6982

70-
Match the **architecture** (`arm64` for Graviton functions, `x86_64` otherwise)
71-
and the **PHP version** to your Bref runtime. The layer's internal layout
72-
(`/opt/php-quickjs/quickjs.so` + `/opt/bref/etc/php/conf.d/quickjs.ini`) follows
73-
Bref's ini scan path; if a future Bref changes that path, prefer the raw `.so`
74-
with your own `php/conf.d` entry in the project.
83+
```yaml
84+
functions:
85+
api:
86+
handler: index.php
87+
runtime: php-84 # Bref PHP 8.4 runtime
88+
architecture: arm64
89+
layers:
90+
- arn:aws:lambda:<region>:<account>:layer:php-quickjs-php84-arm64:<n>
91+
```
92+
93+
AWS allows at most **5 layers** per function.
94+
95+
### Vendor the raw `.so`
7596

76-
Alternatively, skip the layer and vendor the raw `.so` in your project, enabling
77-
it via Bref's per-project config (`php/conf.d/php.ini`):
97+
Skip layers entirely — drop the `.so` in your project and enable it via Bref's
98+
per-project config:
7899

79100
```ini
80101
; php/conf.d/php.ini

examples/lambda/Dockerfile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Deploy php-quickjs on AWS Lambda as a container image (Bref's recommended path
2+
# for custom binaries). Build for the architecture you deploy to: linux/arm64
3+
# (Graviton) or linux/amd64.
4+
#
5+
# docker build --platform linux/arm64 \
6+
# --build-arg EXT=php-quickjs-v0.0.1-php8.4-lambda-bref-arm64.so -t my-app .
7+
#
8+
# Always pin the Bref image MAJOR version. Match the PHP minor (8.4/8.5) and the
9+
# architecture to the .so you copy in.
10+
FROM bref/php-84:3
11+
12+
# The prebuilt extension, downloaded from a php-quickjs release. Pass the file
13+
# name matching your PHP version + arch via --build-arg EXT=...
14+
ARG EXT
15+
16+
# /opt/bref/extensions is Bref's extension_dir, and /opt/bref/etc/php/conf.d is
17+
# scanned for *.ini — so a bare `extension=quickjs.so` is enough.
18+
COPY ${EXT} /opt/bref/extensions/quickjs.so
19+
RUN echo 'extension=quickjs.so' > /opt/bref/etc/php/conf.d/ext-quickjs.ini
20+
21+
# Your application code (and `composer install`ed vendor/).
22+
COPY . /var/task

examples/lambda/README.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# php-quickjs on AWS Lambda (Bref)
2+
3+
Three ways to ship the extension to Lambda, all using the artifacts attached to a
4+
[php-quickjs release](https://github.com/eddmann/php-quickjs/releases). Pick the
5+
`.so` / `.zip` that matches your **PHP minor** (8.4 / 8.5) and **architecture**
6+
(`arm64` for Graviton, `x86_64` otherwise). All builds are NTS, built inside the
7+
Bref Amazon Linux 2023 image so they load on Lambda (glibc 2.34).
8+
9+
This folder contains a runnable skeleton: [`index.php`](index.php) (a Bref function
10+
handler that runs a TS guest), a [`Dockerfile`](Dockerfile), and a
11+
[`serverless.yml`](serverless.yml).
12+
13+
## How Bref loads it
14+
15+
A Bref function is the runtime layer mounted at `/opt` plus your code at
16+
`/var/task`. PHP scans `*.ini` from `/opt/bref/etc/php/conf.d/` (layers) and your
17+
project's `php/conf.d/`. Bref's `extension_dir` is `/opt/bref/extensions`. The
18+
release artifacts follow that convention exactly, so the same `.so` + ini work
19+
whether you go the layer or the Docker route.
20+
21+
## 1. Docker image (recommended for custom binaries)
22+
23+
Bake the `.so` into a `FROM bref/php-XX:3` image (see [`Dockerfile`](Dockerfile)):
24+
25+
```dockerfile
26+
FROM bref/php-84:3
27+
ARG EXT
28+
COPY ${EXT} /opt/bref/extensions/quickjs.so
29+
RUN echo 'extension=quickjs.so' > /opt/bref/etc/php/conf.d/ext-quickjs.ini
30+
COPY . /var/task
31+
```
32+
33+
```sh
34+
composer require bref/bref
35+
serverless deploy # builds the image (buildArg EXT=...), pushes to ECR, deploys
36+
```
37+
38+
## 2. Lambda layer (the released `.zip`)
39+
40+
Publish the layer once, then reference its ARN alongside the Bref runtime:
41+
42+
```sh
43+
aws lambda publish-layer-version \
44+
--layer-name php-quickjs-php84-arm64 \
45+
--compatible-architectures arm64 \
46+
--zip-file fileb://php-quickjs-v0.0.1-php8.4-lambda-bref-arm64.zip
47+
```
48+
49+
```yaml
50+
functions:
51+
demo:
52+
handler: index.php
53+
runtime: php-84
54+
architecture: arm64
55+
layers:
56+
- arn:aws:lambda:<region>:<account>:layer:php-quickjs-php84-arm64:1
57+
```
58+
59+
(AWS allows at most **5 layers** per function.) See the commented block at the
60+
bottom of [`serverless.yml`](serverless.yml).
61+
62+
## 3. Vendor the raw `.so`
63+
64+
Skip layers entirely: drop the `.so` in your project and enable it via Bref's
65+
per-project config.
66+
67+
```ini
68+
; php/conf.d/quickjs.ini
69+
extension=/var/task/quickjs.so
70+
```
71+
72+
---
73+
74+
See [`../../docs/install.md`](../../docs/install.md) for the full platform matrix
75+
and how the Lambda binaries are built.

examples/lambda/index.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
// A minimal Bref function handler that runs a JS/TS guest inside Lambda.
6+
//
7+
// composer require bref/bref
8+
//
9+
// The `QuickJS` class comes from the php-quickjs extension, enabled by the
10+
// Lambda layer or baked into the Docker image (see this folder's README).
11+
12+
require __DIR__ . '/vendor/autoload.php';
13+
14+
return function (array $event): array {
15+
$js = new QuickJS(memoryLimit: 32 * 1024 * 1024, timeoutMs: 1000);
16+
17+
// Expose a tiny, controlled capability to the guest.
18+
$js->register('event.name', fn(): string => (string) ($event['name'] ?? 'world'));
19+
20+
// The guest is TypeScript; types are erased in-process before it runs.
21+
$message = $js->eval(<<<'TS'
22+
const name: string = php.event.name();
23+
`Hello, ${name}! 2 ** 10 = ${2 ** 10}`;
24+
TS);
25+
26+
return ['message' => $message];
27+
};

examples/lambda/serverless.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
service: php-quickjs-demo
2+
3+
provider:
4+
name: aws
5+
region: eu-west-1
6+
architecture: arm64 # match the .so you ship (arm64 = Graviton, cheaper)
7+
8+
# ── Container-image deployment (this example's Dockerfile) ──────────────
9+
# Bref builds the image from ./Dockerfile and pushes it to ECR.
10+
ecr:
11+
images:
12+
app:
13+
path: ./
14+
file: Dockerfile
15+
platform: linux/arm64
16+
buildArgs:
17+
EXT: php-quickjs-v0.0.1-php8.4-lambda-bref-arm64.so
18+
19+
functions:
20+
demo:
21+
image:
22+
name: app
23+
command: index.php # the handler returned by index.php
24+
25+
# ── Alternative: Lambda layer (the released .zip) instead of Docker ────────
26+
# Publish the layer once:
27+
# aws lambda publish-layer-version \
28+
# --layer-name php-quickjs-php84-arm64 --compatible-architectures arm64 \
29+
# --zip-file fileb://php-quickjs-v0.0.1-php8.4-lambda-bref-arm64.zip
30+
# then drop the `ecr`/`image` blocks above and use the classic runtime + layers:
31+
#
32+
# functions:
33+
# demo:
34+
# handler: index.php
35+
# runtime: php-84
36+
# architecture: arm64
37+
# layers:
38+
# - arn:aws:lambda:<region>:<account>:layer:php-quickjs-php84-arm64:1

0 commit comments

Comments
 (0)