Skip to content

Add serversideup/php-base: PHP compiled from source, a drop-in for the official images - #726

Draft
tomschlick wants to merge 3 commits into
serversideup:mainfrom
tomschlick:php-base-from-source
Draft

tomschlick wants to merge 3 commits into
serversideup:mainfrom
tomschlick:php-base-from-source

Conversation

@tomschlick

Copy link
Copy Markdown
Contributor

Adds serversideup/php-base: PHP compiled from the php.net tarball into an image meant to be interchangeable with the official php:<version>-<cli|fpm|zts>-<os> image. Nothing builds or publishes it yet, and every variation still builds on the official image by default, so this PR does not change any published image.

Why

A PHP security release can't ship until Docker Hub publishes the matching official image. scripts/get-php-versions.sh checks that each new patch exists on Docker Hub and falls back to the previous patch until it does. Building the base ourselves from php.net takes Docker Hub out of that path. When php.net publishes a release, we can build it.

How it stays a drop-in

src/base/Dockerfile is a port of docker-library/php's Dockerfile-linux.template, pinned to the upstream commit in src/base/bin/UPSTREAM. It keeps the same paths, ENV, configure flags, docker-php-ext-* scripts (copied unchanged from upstream), /usr/src/php.tar.xz, and /usr/local/etc contents. One Dockerfile covers every supported minor, SAPI, and OS. The per-minor differences are worked out from PHP_VERSION inside the build steps. Those include pear/pecl, the legacy 8.1 FPM layout, ZTS flags, and the Alpine patches.

scripts/test-base-image.sh checks a base image against the official one: image config, ENV, php -m, configure flags, checksums of /usr/local/etc, the www-data user, docker-php-ext-install, install-php-extensions with our default extensions, and PHP-FPM answering over FastCGI. Any difference other than PHP_BUILD_PROVIDER is a bug.

Changes

  • src/base/: the Dockerfile, upstream's helper scripts and MIT license, and bin/UPSTREAM with steps for pulling in upstream changes. Downloads go through docker-php-serversideup-download, bind-mounted for the build so it does not end up in the image.
  • scripts/get-php-source.sh: resolves a minor (8.4), a pinned minor (8.1 resolves to 8.1.34), or an exact release (8.4.26) to its php.net tarball URL, sha256, and signing keys. It reads only php.net.
  • scripts/conf/php-versions-base-config.yml: gpg_keys per minor (release managers from https://www.php.net/gpg-keys.php) and base_image per OS. get-php-versions.sh carries gpg_keys into the generated file. The generated CI matrix is identical to main's.
  • scripts/dev.sh --variation base --sapi <cli|fpm|zts> builds serversideup/php-base:<version>-<sapi>-<os> locally.
  • cli, fpm, and fpm-nginx's NGINX signing key stage now take BASE_IMAGE, as fpm-apache and frankenphp already do. The default is still the official image.
  • hadolint covers src/base/Dockerfile. AGENTS.md documents the base image.
  • Helper scripts use set -e instead of set -oe. set -oe still turns on exit-on-error, but it prints the shell's option table to stdout first. That put a page of noise in every build log, and it corrupted docker-php-serversideup-download output when writing to stdout. The download helper fix and the other four scripts are separate commits, so either can be reverted on its own.

Tested locally (arm64)

  • 8.4-fpm-bookworm and 8.4-cli-alpine3.24 pass scripts/test-base-image.sh against php:8.4.27-fpm-bookworm and php:8.4.27-cli-alpine3.24.
  • fpm-nginx built on the local 8.4-fpm-bookworm base passes scripts/test-image.sh: it reaches healthy and serves PHP through NGINX.
  • cli on bookworm and Alpine 3.24 with the set -e scripts passes scripts/test-image.sh. A missing package, a bad installer version, or a missing extension still fails with the same exit code as before.
  • shellcheck, hadolint, actionlint, and scripts/tests/run.sh pass.

Not in this PR

  • A workflow phase that builds and publishes php-base for the matrix.
  • Switching the default BASE_IMAGE to php-base.

How to test

  1. scripts/dev.sh --variation base --version 8.4 --os bookworm --sapi fpm
  2. scripts/test-base-image.sh serversideup/php-base:8.4-fpm-bookworm 8.4.27 php:8.4.27-fpm-bookworm
  3. scripts/dev.sh --variation fpm-nginx --version 8.4 --os bookworm --build-arg BASE_IMAGE=serversideup/php-base:8.4-fpm-bookworm, then scripts/test-image.sh serversideup/php:8.4-fpm-nginx-bookworm 8.4.27

"set -oe" makes the shell print its option table to stdout before it
enables errexit. Downloads to a file were unaffected, but stdout
downloads got the option table prepended to the body. The two existing
callers happened to filter it out.
src/base/Dockerfile ports docker-library/php's Dockerfile-linux.template
(pinned in src/base/bin/UPSTREAM) into one Dockerfile that builds any
supported minor, SAPI (cli, fpm, zts), and OS. The result is meant to be
interchangeable with the official php:<ver>-<sapi>-<os> image.

- scripts/get-php-source.sh resolves a version to its php.net tarball,
  sha256, and release manager GPG keys (new gpg_keys per minor in the
  base config; base_image per OS says what to build on).
- scripts/dev.sh --variation base --sapi <sapi> builds one locally.
- scripts/test-base-image.sh checks a base image against the official
  one: ENV, modules, configure flags, /usr/local/etc, www-data, and FPM.
- cli, fpm, and fpm-nginx now take BASE_IMAGE like fpm-apache and
  frankenphp already do. The default is still the official image, so CI
  builds are unchanged.
- hadolint covers src/base/Dockerfile.
"set -oe" still enables errexit, but it first prints the shell's option
table to stdout, which adds a page of noise to every image build log
and to the builds of anyone who calls these helpers in their own
Dockerfile. Failure behavior is unchanged: a failed package, extension,
or installer download already exited non-zero.
@jaydrogers

Copy link
Copy Markdown
Member

Thanks a ton for opening this! I took some time to reflect on what needs to be improved and I opened this discussion:

It seems like you've got a great start, but there might be some things that we need to add to this PR yet. Not sure if I will just hijack this PR or start a new one.

But if you could share your thoughts on the discussion above and let me know if you like that direction, that would be great!!

I am very grateful for your continued contributions 馃憤

@tomschlick

Copy link
Copy Markdown
Contributor Author

Absolutely!

This is a result of me brain dumping how this might work and letting opus 5.5 take the wheel on implementation so nothing here is sacred.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants