Skip to content

Commit f85ca1c

Browse files
henderkesdunglas
andauthored
docs: glibc-based mostly static builds and loading extensions (#1453)
* add glibc based static builder to documentation * english docs for gnu/extensions * remove source again * lint fixes * why is there no .editorconfig :( * apply suggestions * Update docs/static.md Co-authored-by: Kévin Dunglas <kevin@dunglas.fr> * remove list * Update performance.md * Update static.md * Update static.md --------- Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>
1 parent a30ed2e commit f85ca1c

File tree

2 files changed

+85
-27
lines changed

2 files changed

+85
-27
lines changed

docs/performance.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,18 @@ you need to create a worker script and to be sure that the app is not leaking me
3434

3535
## Don't Use musl
3636

37-
The static binaries we provide and the Alpine Linux variant of the official Docker images
38-
are using [the musl libc](https://musl.libc.org).
37+
The Alpine Linux variant of the official Docker images and the default binaries we provide are using [the musl libc](https://musl.libc.org).
3938

40-
PHP is known to be [significantly slower](https://gitlab.alpinelinux.org/alpine/aports/-/issues/14381) when using this alternative C library instead of the traditional GNU library,
41-
especially when compiled in ZTS mode (thread-safe), which is required for FrankenPHP.
39+
PHP is known to be [slower](https://gitlab.alpinelinux.org/alpine/aports/-/issues/14381) when using this alternative C library instead of the traditional GNU library,
40+
especially when compiled in ZTS mode (thread-safe), which is required for FrankenPHP. The difference can be significant in a heavily threaded environment.
4241

4342
Also, [some bugs only happen when using musl](https://github.com/php/php-src/issues?q=sort%3Aupdated-desc+is%3Aissue+is%3Aopen+label%3ABug+musl).
4443

45-
In production environments, we strongly recommend to use the glibc.
44+
In production environments, we recommend using FrankenPHP linked against glibc.
4645

47-
This can be achieved by using the Debian Docker images (the default) and [by compiling FrankenPHP from sources](compile.md).
46+
This can be achieved by using the Debian Docker images (the default), downloading the -gnu suffix binary from our [Releases](https://github.com/dunglas/frankenphp/releases), or by [compiling FrankenPHP from sources](compile.md).
4847

49-
Alternatively, we provide static binaries compiled with [the mimalloc allocator](https://github.com/microsoft/mimalloc), which makes FrankenPHP+musl faster (but still slower than FrankenPHP+glibc).
48+
Alternatively, we provide static musl binaries compiled with [the mimalloc allocator](https://github.com/microsoft/mimalloc), which alleviates the problems in threaded scenarios.
5049

5150
## Go Runtime Configuration
5251

docs/static.md

Lines changed: 79 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,74 @@
11
# Create a Static Build
22

33
Instead of using a local installation of the PHP library,
4-
it's possible to create a static build of FrankenPHP thanks to the great [static-php-cli project](https://github.com/crazywhalecc/static-php-cli) (despite its name, this project support all SAPIs, not only CLI).
4+
it's possible to create a static or mostly static build of FrankenPHP thanks to the great [static-php-cli project](https://github.com/crazywhalecc/static-php-cli) (despite its name, this project supports all SAPIs, not only CLI).
55

6-
With this method, a single, portable, binary will contain the PHP interpreter, the Caddy web server and FrankenPHP!
6+
With this method, a single, portable, binary will contain the PHP interpreter, the Caddy web server, and FrankenPHP!
7+
8+
Fully static native executables require no dependencies at all and can even be run on [`scratch` Docker image](https://docs.docker.com/build/building/base-images/#create-a-minimal-base-image-using-scratch).
9+
However, they can't load dynamic PHP extensions (such as Xdebug) and have some limitations because they are using the musl libc.
10+
11+
Mostly static binaries only require `glibc` and can load dynamic extensions.
12+
13+
When possible, we recommend using glibc-based, mostly static builds.
714

815
FrankenPHP also supports [embedding the PHP app in the static binary](embed.md).
916

1017
## Linux
1118

12-
We provide a Docker image to build a Linux static binary:
19+
We provide Docker images to build static Linux binaries:
20+
21+
### musl-Based, Fully Static Build
22+
23+
For a fully-static binary that runs on any Linux distribution without dependencies but doesn't support dynamic loading of extensions:
24+
25+
```console
26+
docker buildx bake --load static-builder-musl
27+
docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp ; docker rm static-builder-musl
28+
```
29+
30+
For better performance in heavily concurrent scenarios, consider using the [mimalloc](https://github.com/microsoft/mimalloc) allocator.
1331

1432
```console
15-
docker buildx bake --load static-builder
16-
docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp ; docker rm static-builder
33+
docker buildx bake --load --set static-builder-musl.args.MIMALLOC=1 static-builder-musl
1734
```
1835

19-
The resulting static binary is named `frankenphp` and is available in the current directory.
36+
### glibc-Based, Mostly Static Build (With Dynamic Extension Support)
2037

21-
If you want to build the static binary without Docker, take a look at the macOS instructions, which also works for Linux.
38+
For a binary that supports loading PHP extensions dynamically while still having the selected extensions compiled statically:
39+
40+
```console
41+
docker buildx bake --load static-builder-gnu
42+
docker cp $(docker create --name static-builder-gnu dunglas/frankenphp:static-builder-gnu):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp ; docker rm static-builder-gnu
43+
```
44+
45+
This binary supports all glibc versions 2.17 and superior but does not run on musl-based systems (like Alpine Linux).
46+
47+
The resulting mostly static (except `glibc`) binary is named `frankenphp` and is available in the current directory.
48+
49+
If you want to build the static binary without Docker, take a look at the macOS instructions, which also work for Linux.
2250

2351
### Custom Extensions
2452

25-
By default, most popular PHP extensions are compiled.
53+
By default, the most popular PHP extensions are compiled.
2654

2755
To reduce the size of the binary and to reduce the attack surface, you can choose the list of extensions to build using the `PHP_EXTENSIONS` Docker ARG.
2856

2957
For instance, run the following command to only build the `opcache` extension:
3058

3159
```console
32-
docker buildx bake --load --set static-builder.args.PHP_EXTENSIONS=opcache,pdo_sqlite static-builder
60+
docker buildx bake --load --set static-builder-musl.args.PHP_EXTENSIONS=opcache,pdo_sqlite static-builder-musl
3361
# ...
3462
```
3563

36-
To add libraries enabling additional functionality to the extensions you've enabled, you can pass use the `PHP_EXTENSION_LIBS` Docker ARG:
64+
To add libraries enabling additional functionality to the extensions you've enabled, you can pass the `PHP_EXTENSION_LIBS` Docker ARG:
3765

3866
```console
3967
docker buildx bake \
4068
--load \
41-
--set static-builder.args.PHP_EXTENSIONS=gd \
42-
--set static-builder.args.PHP_EXTENSION_LIBS=libjpeg,libwebp \
43-
static-builder
69+
--set static-builder-musl.args.PHP_EXTENSIONS=gd \
70+
--set static-builder-musl.args.PHP_EXTENSION_LIBS=libjpeg,libwebp \
71+
static-builder-musl
4472
```
4573

4674
### Extra Caddy Modules
@@ -50,15 +78,15 @@ To add extra Caddy modules or pass other arguments to [xcaddy](https://github.co
5078
```console
5179
docker buildx bake \
5280
--load \
53-
--set static-builder.args.XCADDY_ARGS="--with github.com/darkweak/souin/plugins/caddy --with github.com/dunglas/caddy-cbrotli --with github.com/dunglas/mercure/caddy --with github.com/dunglas/vulcain/caddy" \
54-
static-builder
81+
--set static-builder-musl.args.XCADDY_ARGS="--with github.com/darkweak/souin/plugins/caddy --with github.com/dunglas/caddy-cbrotli --with github.com/dunglas/mercure/caddy --with github.com/dunglas/vulcain/caddy" \
82+
static-builder-musl
5583
```
5684

5785
In this example, we add the [Souin](https://souin.io) HTTP cache module for Caddy as well as the [cbrotli](https://github.com/dunglas/caddy-cbrotli), [Mercure](https://mercure.rocks) and [Vulcain](https://vulcain.rocks) modules.
5886

5987
> [!TIP]
6088
>
61-
> The cbrotli, Mercure and Vulcain modules are included by default if `XCADDY_ARGS` is empty or not set.
89+
> The cbrotli, Mercure, and Vulcain modules are included by default if `XCADDY_ARGS` is empty or not set.
6290
> If you customize the value of `XCADDY_ARGS`, you must include them explicitly if you want them to be included.
6391
6492
See also how to [customize the build](#customizing-the-build)
@@ -68,7 +96,7 @@ See also how to [customize the build](#customizing-the-build)
6896
If you hit the GitHub API rate limit, set a GitHub Personal Access Token in an environment variable named `GITHUB_TOKEN`:
6997

7098
```console
71-
GITHUB_TOKEN="xxx" docker --load buildx bake static-builder
99+
GITHUB_TOKEN="xxx" docker --load buildx bake static-builder-musl
72100
# ...
73101
```
74102

@@ -82,7 +110,7 @@ cd frankenphp
82110
./build-static.sh
83111
```
84112

85-
Note: this script also works on Linux (and probably on other Unixes), and is used internally by the Docker based static builder we provide.
113+
Note: this script also works on Linux (and probably on other Unixes), and is used internally by the Docker images we provide.
86114

87115
## Customizing The Build
88116

@@ -97,6 +125,37 @@ script to customize the static build:
97125
* `EMBED`: path of the PHP application to embed in the binary
98126
* `CLEAN`: when set, libphp and all its dependencies are built from scratch (no cache)
99127
* `NO_COMPRESS`: don't compress the resulting binary using UPX
100-
* `DEBUG_SYMBOLS`: when set, debug-symbols will not be stripped and will be added within the binary
101-
* `MIMALLOC`: (experimental, Linux-only) replace musl's mallocng by [mimalloc](https://github.com/microsoft/mimalloc) for improved performance
128+
* `DEBUG_SYMBOLS`: when set, debug-symbols will not be stripped and will be added to the binary
129+
* `MIMALLOC`: (experimental, Linux-only) replace musl's mallocng by [mimalloc](https://github.com/microsoft/mimalloc) for improved performance. We only recommend using this for musl targeting builds, for glibc prefer disabling this option and using [`LD_PRELOAD`](https://microsoft.github.io/mimalloc/overrides.html) when you run your binary instead.
102130
* `RELEASE`: (maintainers only) when set, the resulting binary will be uploaded on GitHub
131+
132+
## Extensions
133+
134+
With the glibc or macOS-based binaries, you can load PHP extensions dynamically. However, these extensions will have to be compiled with ZTS support.
135+
Since most package managers do not currently offer ZTS versions of their extensions, you will have to compile them yourself.
136+
137+
For this, you can build and run the `static-builder-gnu` Docker container, remote into it, and compile the extensions with `./configure --with-php-config=/go/src/app/dist/static-php-cli/buildroot/bin/php-config`.
138+
139+
Example steps for [the Xdebug extension](https://xdebug.org):
140+
141+
```console
142+
docker build -t gnu-ext -f static-builder-gnu.Dockerfile --build-arg FRANKENPHP_VERSION=1.0 .
143+
docker create --name static-builder-gnu -it gnu-ext /bin/sh
144+
docker start static-builder-gnu
145+
docker exec -it static-builder-gnu /bin/sh
146+
cd /go/src/app/dist/static-php-cli/buildroot/bin
147+
git clone https://github.com/xdebug/xdebug.git && cd xdebug
148+
source scl_source enable devtoolset-10
149+
../phpize
150+
./configure --with-php-config=/go/src/app/dist/static-php-cli/buildroot/bin/php-config
151+
make
152+
exit
153+
docker cp static-builder-gnu:/go/src/app/dist/static-php-cli/buildroot/bin/xdebug/modules/xdebug.so xdebug-zts.so
154+
docker cp static-builder-gnu:/go/src/app/dist/frankenphp-linux-$(uname -m) ./frankenphp
155+
docker stop static-builder-gnu
156+
docker rm static-builder-gnu
157+
docker rmi gnu-ext
158+
```
159+
160+
This will have created `frankenphp` and `xdebug-zts.so` in the current directory.
161+
If you move the `xdebug-zts.so` into your extension directory, add `zend_extension=xdebug-zts.so` to your php.ini and run FrankenPHP, it will load Xdebug.

0 commit comments

Comments
 (0)