mirror of
https://github.com/dunglas/frankenphp.git
synced 2025-12-24 13:38:11 +08:00
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>
This commit is contained in:
@@ -34,19 +34,18 @@ you need to create a worker script and to be sure that the app is not leaking me
|
||||
|
||||
## Don't Use musl
|
||||
|
||||
The static binaries we provide and the Alpine Linux variant of the official Docker images
|
||||
are using [the musl libc](https://musl.libc.org).
|
||||
The Alpine Linux variant of the official Docker images and the default binaries we provide are using [the musl libc](https://musl.libc.org).
|
||||
|
||||
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,
|
||||
especially when compiled in ZTS mode (thread-safe), which is required for FrankenPHP.
|
||||
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,
|
||||
especially when compiled in ZTS mode (thread-safe), which is required for FrankenPHP. The difference can be significant in a heavily threaded environment.
|
||||
|
||||
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).
|
||||
|
||||
In production environments, we strongly recommend to use the glibc.
|
||||
In production environments, we recommend using FrankenPHP linked against glibc.
|
||||
|
||||
This can be achieved by using the Debian Docker images (the default) and [by compiling FrankenPHP from sources](compile.md).
|
||||
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).
|
||||
|
||||
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).
|
||||
Alternatively, we provide static musl binaries compiled with [the mimalloc allocator](https://github.com/microsoft/mimalloc), which alleviates the problems in threaded scenarios.
|
||||
|
||||
## Go Runtime Configuration
|
||||
|
||||
|
||||
@@ -1,46 +1,74 @@
|
||||
# Create a Static Build
|
||||
|
||||
Instead of using a local installation of the PHP library,
|
||||
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).
|
||||
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).
|
||||
|
||||
With this method, a single, portable, binary will contain the PHP interpreter, the Caddy web server and FrankenPHP!
|
||||
With this method, a single, portable, binary will contain the PHP interpreter, the Caddy web server, and FrankenPHP!
|
||||
|
||||
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).
|
||||
However, they can't load dynamic PHP extensions (such as Xdebug) and have some limitations because they are using the musl libc.
|
||||
|
||||
Mostly static binaries only require `glibc` and can load dynamic extensions.
|
||||
|
||||
When possible, we recommend using glibc-based, mostly static builds.
|
||||
|
||||
FrankenPHP also supports [embedding the PHP app in the static binary](embed.md).
|
||||
|
||||
## Linux
|
||||
|
||||
We provide a Docker image to build a Linux static binary:
|
||||
We provide Docker images to build static Linux binaries:
|
||||
|
||||
### musl-Based, Fully Static Build
|
||||
|
||||
For a fully-static binary that runs on any Linux distribution without dependencies but doesn't support dynamic loading of extensions:
|
||||
|
||||
```console
|
||||
docker buildx bake --load static-builder
|
||||
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
|
||||
docker buildx bake --load static-builder-musl
|
||||
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
|
||||
```
|
||||
|
||||
The resulting static binary is named `frankenphp` and is available in the current directory.
|
||||
For better performance in heavily concurrent scenarios, consider using the [mimalloc](https://github.com/microsoft/mimalloc) allocator.
|
||||
|
||||
If you want to build the static binary without Docker, take a look at the macOS instructions, which also works for Linux.
|
||||
```console
|
||||
docker buildx bake --load --set static-builder-musl.args.MIMALLOC=1 static-builder-musl
|
||||
```
|
||||
|
||||
### glibc-Based, Mostly Static Build (With Dynamic Extension Support)
|
||||
|
||||
For a binary that supports loading PHP extensions dynamically while still having the selected extensions compiled statically:
|
||||
|
||||
```console
|
||||
docker buildx bake --load static-builder-gnu
|
||||
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
|
||||
```
|
||||
|
||||
This binary supports all glibc versions 2.17 and superior but does not run on musl-based systems (like Alpine Linux).
|
||||
|
||||
The resulting mostly static (except `glibc`) binary is named `frankenphp` and is available in the current directory.
|
||||
|
||||
If you want to build the static binary without Docker, take a look at the macOS instructions, which also work for Linux.
|
||||
|
||||
### Custom Extensions
|
||||
|
||||
By default, most popular PHP extensions are compiled.
|
||||
By default, the most popular PHP extensions are compiled.
|
||||
|
||||
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.
|
||||
|
||||
For instance, run the following command to only build the `opcache` extension:
|
||||
|
||||
```console
|
||||
docker buildx bake --load --set static-builder.args.PHP_EXTENSIONS=opcache,pdo_sqlite static-builder
|
||||
docker buildx bake --load --set static-builder-musl.args.PHP_EXTENSIONS=opcache,pdo_sqlite static-builder-musl
|
||||
# ...
|
||||
```
|
||||
|
||||
To add libraries enabling additional functionality to the extensions you've enabled, you can pass use the `PHP_EXTENSION_LIBS` Docker ARG:
|
||||
To add libraries enabling additional functionality to the extensions you've enabled, you can pass the `PHP_EXTENSION_LIBS` Docker ARG:
|
||||
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--set static-builder.args.PHP_EXTENSIONS=gd \
|
||||
--set static-builder.args.PHP_EXTENSION_LIBS=libjpeg,libwebp \
|
||||
static-builder
|
||||
--set static-builder-musl.args.PHP_EXTENSIONS=gd \
|
||||
--set static-builder-musl.args.PHP_EXTENSION_LIBS=libjpeg,libwebp \
|
||||
static-builder-musl
|
||||
```
|
||||
|
||||
### Extra Caddy Modules
|
||||
@@ -50,15 +78,15 @@ To add extra Caddy modules or pass other arguments to [xcaddy](https://github.co
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--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" \
|
||||
static-builder
|
||||
--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" \
|
||||
static-builder-musl
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> The cbrotli, Mercure and Vulcain modules are included by default if `XCADDY_ARGS` is empty or not set.
|
||||
> The cbrotli, Mercure, and Vulcain modules are included by default if `XCADDY_ARGS` is empty or not set.
|
||||
> If you customize the value of `XCADDY_ARGS`, you must include them explicitly if you want them to be included.
|
||||
|
||||
See also how to [customize the build](#customizing-the-build)
|
||||
@@ -68,7 +96,7 @@ See also how to [customize the build](#customizing-the-build)
|
||||
If you hit the GitHub API rate limit, set a GitHub Personal Access Token in an environment variable named `GITHUB_TOKEN`:
|
||||
|
||||
```console
|
||||
GITHUB_TOKEN="xxx" docker --load buildx bake static-builder
|
||||
GITHUB_TOKEN="xxx" docker --load buildx bake static-builder-musl
|
||||
# ...
|
||||
```
|
||||
|
||||
@@ -82,7 +110,7 @@ cd frankenphp
|
||||
./build-static.sh
|
||||
```
|
||||
|
||||
Note: this script also works on Linux (and probably on other Unixes), and is used internally by the Docker based static builder we provide.
|
||||
Note: this script also works on Linux (and probably on other Unixes), and is used internally by the Docker images we provide.
|
||||
|
||||
## Customizing The Build
|
||||
|
||||
@@ -97,6 +125,37 @@ script to customize the static build:
|
||||
* `EMBED`: path of the PHP application to embed in the binary
|
||||
* `CLEAN`: when set, libphp and all its dependencies are built from scratch (no cache)
|
||||
* `NO_COMPRESS`: don't compress the resulting binary using UPX
|
||||
* `DEBUG_SYMBOLS`: when set, debug-symbols will not be stripped and will be added within the binary
|
||||
* `MIMALLOC`: (experimental, Linux-only) replace musl's mallocng by [mimalloc](https://github.com/microsoft/mimalloc) for improved performance
|
||||
* `DEBUG_SYMBOLS`: when set, debug-symbols will not be stripped and will be added to the binary
|
||||
* `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.
|
||||
* `RELEASE`: (maintainers only) when set, the resulting binary will be uploaded on GitHub
|
||||
|
||||
## Extensions
|
||||
|
||||
With the glibc or macOS-based binaries, you can load PHP extensions dynamically. However, these extensions will have to be compiled with ZTS support.
|
||||
Since most package managers do not currently offer ZTS versions of their extensions, you will have to compile them yourself.
|
||||
|
||||
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`.
|
||||
|
||||
Example steps for [the Xdebug extension](https://xdebug.org):
|
||||
|
||||
```console
|
||||
docker build -t gnu-ext -f static-builder-gnu.Dockerfile --build-arg FRANKENPHP_VERSION=1.0 .
|
||||
docker create --name static-builder-gnu -it gnu-ext /bin/sh
|
||||
docker start static-builder-gnu
|
||||
docker exec -it static-builder-gnu /bin/sh
|
||||
cd /go/src/app/dist/static-php-cli/buildroot/bin
|
||||
git clone https://github.com/xdebug/xdebug.git && cd xdebug
|
||||
source scl_source enable devtoolset-10
|
||||
../phpize
|
||||
./configure --with-php-config=/go/src/app/dist/static-php-cli/buildroot/bin/php-config
|
||||
make
|
||||
exit
|
||||
docker cp static-builder-gnu:/go/src/app/dist/static-php-cli/buildroot/bin/xdebug/modules/xdebug.so xdebug-zts.so
|
||||
docker cp static-builder-gnu:/go/src/app/dist/frankenphp-linux-$(uname -m) ./frankenphp
|
||||
docker stop static-builder-gnu
|
||||
docker rm static-builder-gnu
|
||||
docker rmi gnu-ext
|
||||
```
|
||||
|
||||
This will have created `frankenphp` and `xdebug-zts.so` in the current directory.
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user