Skip to content

Improve CI builds - #700

Merged
jaydrogers merged 23 commits into
release/webserver-improvements-and-fixesfrom
ci-improvements
Sep 10, 2026
Merged

Improve CI builds#700
jaydrogers merged 23 commits into
release/webserver-improvements-and-fixesfrom
ci-improvements

Conversation

@jaydrogers

@jaydrogers jaydrogers commented Sep 9, 2026

Copy link
Copy Markdown
Member

Why we created this PR

Build and publish used to be one step. An image went public the moment it built, even on the weekly rebuilds. Nothing ever ran it.

While working on 4.6, s6-overlay 3.2.3 broke startup for every fpm-nginx and fpm-apache image. They all built fine. The old pipeline would have published all of them.

How to test

serversideup/php-dev:700-*

View the testing images →

How publishing works now

  1. Build. Depot builds every image for amd64 and arm64 and saves it to a private registry.
  2. Test. Every image is pulled on native amd64 and arm64 runners. It must start, run unprivileged, report the right PHP version, load the default extensions, pass its health check, and serve a PHP file through its web server.
  3. Publish. Only if everything passed, the tested image is copied to Docker Hub and GitHub Packages. The published digest is checked against the tested one.

If one image fails, nothing from that run is published. What you pull is what passed.

What this PR does

Testing

  • Added scripts/test-image.sh. Works on any image: bash scripts/test-image.sh serversideup/php-dev:700-8.4-fpm-nginx
  • Tests run on both architectures, grouped by PHP version and OS: 33 jobs instead of 137
  • Fork PRs are tested too. They can't save images, so the build job tests the amd64 image on the runner

Publishing

  • Split the old build-and-publish workflow into setup, build, test, publish, and report
  • Publish uses depot push. No image bytes touch a runner
  • Removed the unused dev-main workflow

Speed

  • Test and publish run on Depot runners (thanks, Depot), so nothing waits in a queue
  • A full run of 68 images is about 12 minutes (full run →)
  • A new push cancels the previous run for the same PR. Release and weekly rebuilds queue instead of overlapping

When something fails

  • Transient failures are retried once
  • If that fails too, an issue is opened and assigned to a maintainer with the failed jobs, the error, and a link to re-run
  • Every run ends with one table of every image and its size per architecture

Linting

  • actionlint, hadolint, and ShellCheck run before any image builds. Same commands work locally

Build hardening

  • Added docker-php-serversideup-download, a curl wrapper with retries, and used it for every download during a build
  • apt-get retries on Debian
  • get-php-versions.sh checks that every base image we need exists on Docker Hub before adding a version to the matrix
  • Fixed web images failing to start with s6-overlay 3.2.3

Security

  • Workflows start with no permissions and each job asks for what it needs
  • Dependabot keeps the GitHub Actions versions current

Docs

- Update Docker workflows to improve build and publish processes for production, beta, and PR images.
- Introduce a new setup matrix workflow for better PHP version management.
- Implement auto-retry for failed image builds to handle transient errors.
- Add support for additional environment variables in the Docker build process.
- Refactor PHP version validation to ensure all necessary base images are available on DockerHub.
- Update documentation to reflect changes in CI/CD processes and workflows.
@jaydrogers
jaydrogers changed the base branch from main to release/webserver-improvements-and-fixes September 9, 2026 19:05
@jaydrogers
jaydrogers marked this pull request as ready for review September 9, 2026 19:06
@jaydrogers
jaydrogers marked this pull request as draft September 9, 2026 19:06
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 9, 2026

Copy link
Copy Markdown

Deploying serversideup-php with  Cloudflare Pages  Cloudflare Pages

Latest commit: a826b0d
Status: ✅  Deploy successful!
Preview URL: https://35c67a80.serversideup-php.pages.dev
Branch Preview URL: https://ci-improvements.serversideup-php.pages.dev

View logs

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

Images for PR #700

Build Test Publish
✅ 68 of 68 images built ✅ Every image passed on amd64 and arm64 ✅ Published to serversideup/php-dev

Try it:

docker run --rm -v "$PWD:/var/www/html" -p 8080:8080 serversideup/php-dev:700-8.5-fpm-nginx

Every image is on Docker Hub as serversideup/php-dev:700-<php>-<variation>-<os>. Browse all tags or view the run.

All images with sizes

Sizes are compressed, per architecture.

Variation PHP Base OS amd64 arm64 Image
cli 8.5.10 alpine3.23 50.1 MB 50.0 MB serversideup/php-dev:700-8.5.10-cli-alpine3.23
cli 8.5.10 alpine3.24 50.1 MB 50.1 MB serversideup/php-dev:700-8.5.10-cli-alpine3.24
cli 8.5.10 bookworm 192.9 MB 185.8 MB serversideup/php-dev:700-8.5.10-cli-bookworm
cli 8.5.10 trixie 195.1 MB 187.4 MB serversideup/php-dev:700-8.5.10-cli-trixie
cli 8.4.25 alpine3.23 47.0 MB 47.1 MB serversideup/php-dev:700-8.4.25-cli-alpine3.23
cli 8.4.25 alpine3.24 47.1 MB 47.2 MB serversideup/php-dev:700-8.4.25-cli-alpine3.24
cli 8.4.25 bookworm 189.0 MB 182.1 MB serversideup/php-dev:700-8.4.25-cli-bookworm
cli 8.4.25 trixie 191.1 MB 183.7 MB serversideup/php-dev:700-8.4.25-cli-trixie
cli 8.3.33 alpine3.23 43.6 MB 44.0 MB serversideup/php-dev:700-8.3.33-cli-alpine3.23
cli 8.3.33 alpine3.24 43.6 MB 44.1 MB serversideup/php-dev:700-8.3.33-cli-alpine3.24
cli 8.3.33 bookworm 184.2 MB 177.7 MB serversideup/php-dev:700-8.3.33-cli-bookworm
cli 8.3.33 trixie 186.9 MB 179.8 MB serversideup/php-dev:700-8.3.33-cli-trixie
cli 8.2.33 alpine3.23 42.8 MB 43.2 MB serversideup/php-dev:700-8.2.33-cli-alpine3.23
cli 8.2.33 alpine3.24 42.8 MB 43.3 MB serversideup/php-dev:700-8.2.33-cli-alpine3.24
cli 8.2.33 bookworm 183.3 MB 176.9 MB serversideup/php-dev:700-8.2.33-cli-bookworm
cli 8.2.33 trixie 186.0 MB 178.9 MB serversideup/php-dev:700-8.2.33-cli-trixie
fpm 8.5.10 alpine3.23 44.2 MB 44.3 MB serversideup/php-dev:700-8.5.10-fpm-alpine3.23
fpm 8.5.10 alpine3.24 44.2 MB 44.4 MB serversideup/php-dev:700-8.5.10-fpm-alpine3.24
fpm 8.5.10 bookworm 181.2 MB 174.4 MB serversideup/php-dev:700-8.5.10-fpm-bookworm
fpm 8.5.10 trixie 183.3 MB 176.0 MB serversideup/php-dev:700-8.5.10-fpm-trixie
fpm 8.4.25 alpine3.23 42.0 MB 42.2 MB serversideup/php-dev:700-8.4.25-fpm-alpine3.23
fpm 8.4.25 alpine3.24 42.1 MB 42.3 MB serversideup/php-dev:700-8.4.25-fpm-alpine3.24
fpm 8.4.25 bookworm 179.0 MB 172.4 MB serversideup/php-dev:700-8.4.25-fpm-bookworm
fpm 8.4.25 trixie 181.2 MB 173.9 MB serversideup/php-dev:700-8.4.25-fpm-trixie
fpm 8.3.33 alpine3.23 39.4 MB 40.0 MB serversideup/php-dev:700-8.3.33-fpm-alpine3.23
fpm 8.3.33 alpine3.24 39.5 MB 40.1 MB serversideup/php-dev:700-8.3.33-fpm-alpine3.24
fpm 8.3.33 bookworm 176.0 MB 169.7 MB serversideup/php-dev:700-8.3.33-fpm-bookworm
fpm 8.3.33 trixie 178.7 MB 171.7 MB serversideup/php-dev:700-8.3.33-fpm-trixie
fpm 8.2.33 alpine3.23 38.7 MB 39.3 MB serversideup/php-dev:700-8.2.33-fpm-alpine3.23
fpm 8.2.33 alpine3.24 38.8 MB 39.4 MB serversideup/php-dev:700-8.2.33-fpm-alpine3.24
fpm 8.2.33 bookworm 175.3 MB 169.0 MB serversideup/php-dev:700-8.2.33-fpm-bookworm
fpm 8.2.33 trixie 178.0 MB 171.0 MB serversideup/php-dev:700-8.2.33-fpm-trixie
fpm-apache 8.5.10 bookworm 187.5 MB 181.2 MB serversideup/php-dev:700-8.5.10-fpm-apache-bookworm
fpm-apache 8.5.10 trixie 189.7 MB 182.9 MB serversideup/php-dev:700-8.5.10-fpm-apache-trixie
fpm-apache 8.4.25 bookworm 185.4 MB 179.2 MB serversideup/php-dev:700-8.4.25-fpm-apache-bookworm
fpm-apache 8.4.25 trixie 187.6 MB 180.8 MB serversideup/php-dev:700-8.4.25-fpm-apache-trixie
fpm-apache 8.3.33 bookworm 182.3 MB 176.5 MB serversideup/php-dev:700-8.3.33-fpm-apache-bookworm
fpm-apache 8.3.33 trixie 185.1 MB 178.6 MB serversideup/php-dev:700-8.3.33-fpm-apache-trixie
fpm-apache 8.2.33 bookworm 181.6 MB 175.8 MB serversideup/php-dev:700-8.2.33-fpm-apache-bookworm
fpm-apache 8.2.33 trixie 184.4 MB 177.9 MB serversideup/php-dev:700-8.2.33-fpm-apache-trixie
fpm-nginx 8.5.10 alpine3.23 50.2 MB 50.9 MB serversideup/php-dev:700-8.5.10-fpm-nginx-alpine3.23
fpm-nginx 8.5.10 alpine3.24 51.7 MB 52.3 MB serversideup/php-dev:700-8.5.10-fpm-nginx-alpine3.24
fpm-nginx 8.5.10 bookworm 189.0 MB 182.6 MB serversideup/php-dev:700-8.5.10-fpm-nginx-bookworm
fpm-nginx 8.5.10 trixie 198.1 MB 190.9 MB serversideup/php-dev:700-8.5.10-fpm-nginx-trixie
fpm-nginx 8.4.25 alpine3.23 48.1 MB 48.8 MB serversideup/php-dev:700-8.4.25-fpm-nginx-alpine3.23
fpm-nginx 8.4.25 alpine3.24 49.5 MB 50.2 MB serversideup/php-dev:700-8.4.25-fpm-nginx-alpine3.24
fpm-nginx 8.4.25 bookworm 186.8 MB 180.6 MB serversideup/php-dev:700-8.4.25-fpm-nginx-bookworm
fpm-nginx 8.4.25 trixie 195.9 MB 188.8 MB serversideup/php-dev:700-8.4.25-fpm-nginx-trixie
fpm-nginx 8.3.33 alpine3.23 45.5 MB 46.6 MB serversideup/php-dev:700-8.3.33-fpm-nginx-alpine3.23
fpm-nginx 8.3.33 alpine3.24 46.9 MB 48.0 MB serversideup/php-dev:700-8.3.33-fpm-nginx-alpine3.24
fpm-nginx 8.3.33 bookworm 183.7 MB 177.8 MB serversideup/php-dev:700-8.3.33-fpm-nginx-bookworm
fpm-nginx 8.3.33 trixie 193.4 MB 186.7 MB serversideup/php-dev:700-8.3.33-fpm-nginx-trixie
fpm-nginx 8.2.33 alpine3.23 44.8 MB 45.9 MB serversideup/php-dev:700-8.2.33-fpm-nginx-alpine3.23
fpm-nginx 8.2.33 alpine3.24 46.2 MB 47.3 MB serversideup/php-dev:700-8.2.33-fpm-nginx-alpine3.24
fpm-nginx 8.2.33 bookworm 183.0 MB 177.2 MB serversideup/php-dev:700-8.2.33-fpm-nginx-bookworm
fpm-nginx 8.2.33 trixie 192.7 MB 186.0 MB serversideup/php-dev:700-8.2.33-fpm-nginx-trixie
frankenphp 8.5.10 alpine3.23 78.2 MB 76.0 MB serversideup/php-dev:700-8.5.10-frankenphp-alpine3.23
frankenphp 8.5.10 alpine3.24 78.2 MB 76.1 MB serversideup/php-dev:700-8.5.10-frankenphp-alpine3.24
frankenphp 8.5.10 bookworm 214.0 MB 205.1 MB serversideup/php-dev:700-8.5.10-frankenphp-bookworm
frankenphp 8.5.10 trixie 216.2 MB 206.7 MB serversideup/php-dev:700-8.5.10-frankenphp-trixie
frankenphp 8.4.25 alpine3.23 74.2 MB 72.3 MB serversideup/php-dev:700-8.4.25-frankenphp-alpine3.23
frankenphp 8.4.25 alpine3.24 74.3 MB 72.3 MB serversideup/php-dev:700-8.4.25-frankenphp-alpine3.24
frankenphp 8.4.25 bookworm 210.1 MB 201.4 MB serversideup/php-dev:700-8.4.25-frankenphp-bookworm
frankenphp 8.4.25 trixie 212.2 MB 202.9 MB serversideup/php-dev:700-8.4.25-frankenphp-trixie
frankenphp 8.3.33 alpine3.23 69.9 MB 68.4 MB serversideup/php-dev:700-8.3.33-frankenphp-alpine3.23
frankenphp 8.3.33 alpine3.24 69.9 MB 68.4 MB serversideup/php-dev:700-8.3.33-frankenphp-alpine3.24
frankenphp 8.3.33 bookworm 205.3 MB 197.0 MB serversideup/php-dev:700-8.3.33-frankenphp-bookworm
frankenphp 8.3.33 trixie 208.0 MB 199.1 MB serversideup/php-dev:700-8.3.33-frankenphp-trixie

Updated on every push to this PR.

s6-overlay 3.2.3 moved its user bundle to /etc/s6-overlay/user-bundles.d
and no longer ships s6-rc.d/user/type. With our services still registered
under the old s6-rc.d/user/contents.d path, rc.init tried to create that
type file at startup, failed as the unprivileged www-data user, and nginx
or apache never started, leaving the container unhealthy forever.

Register php-fpm, nginx, and apache2 in user-bundles.d/user/contents.d
instead. Verified with local fpm-nginx and fpm-apache builds on bookworm:
both services start and the HEALTHCHECK reports healthy.
Add a hadolint job to the lint group so Dockerfile mistakes are caught
before any image builds. Rules that conflict with deliberate project
decisions (unpinned apt/apk packages for weekly security rebuilds,
shell-form CMD, named USER, and so on) are ignored in .hadolint.yaml
with the reason recorded next to each one.

Fix the two findings it raised in the fpm-nginx Dockerfile: the Alpine
repository printf had five placeholders but four arguments, and egrep
is replaced with grep -E.
Replace the per-job summary cards (68 lists of pull commands) with a
single table for the whole run. Each build job now records its canonical
tag and compressed size per architecture, read from the registry
manifest, and uploads it as a small artifact. A new service_summary.yml
merges those files with scripts/build-summary.sh into one table grouped
by variation, listing images that failed to build as well.

Before building, each job looks up the same tag on serversideup/php so
the table shows how much every image grew compared to what users pull
today. Growth over 10% is flagged.

The setup card shrinks to the PHP patch versions resolved from php.net,
which is the one thing only that job knows.
Nothing ran the images after they were built, so a broken entrypoint
would only be noticed by users. scripts/smoke-test.sh runs an image and
checks what a user would hit first: PHP reports the expected version,
the container runs as an unprivileged user, and images with a
HEALTHCHECK become healthy. On failure it prints the container logs.

service_smoke-test.yml selects the newest PHP version of every variation
on one Debian and one Alpine base from the run's image details and tests
each on native amd64 and arm64 GitHub runners. Images that were not
pushed (pull requests from forks) are skipped.

The script works against any image reference, so it doubles as a local
check before opening a PR that touches startup behavior. It caught the
s6-overlay user bundle regression fixed earlier in this branch.
Add smoke and summary jobs to the PR, production, and beta workflows.
Both run whenever the matrix was generated, even if some builds failed,
so a red run still shows which images are missing and whether the rest
work. The PR comment now reports the smoke test result and carries the
full image table, collapsed, next to the pull commands.
- Split the image build and publish processes into separate reusable workflows: `service_build-images.yml` and `service_publish-images.yml`.
- Enhance the smoke test workflow to pull images from the Depot Registry and validate them against expected behaviors.
- Introduce a new script `select-smoke-images.sh` to select representative images for smoke testing based on the latest PHP versions and variations.
- Update the summary generation script to reflect changes in image publishing and size reporting.
- Add tests for CI helper scripts to ensure consistent behavior across environments.
- Improve documentation to clarify the CI/CD process and the role of each workflow in the image publishing pipeline.
…ing reliability and clarity in the publishing process
…cy across image publishing and testing processes
- Updated service_build-images.yml to handle image loading and testing for pull requests from forks, ensuring that amd64 images are tested directly on the runner.
- Modified service_publish-images.yml to improve image promotion logic, including digest verification and enhanced error handling for failed image promotions.
- Improved service_test-images.yml to group saved images by PHP version and base OS, allowing for more efficient testing and clearer reporting of results.
- Enhanced trigger_auto-retry-failed-builds.yml to better manage transient failures, including automatic issue creation for persistent failures.
- Updated AGENTS.md and contributing documentation to reflect changes in the CI/CD process and image testing.
- Refined scripts/build-summary.sh to prioritize published image records and improve error visibility for failed builds.
- Enhanced scripts/test-image.sh to check for loaded PHP extensions and validate web server responses for images that include a web server.
- Adjusted scripts/tests/run.sh to reflect changes in image publishing status and ensure accurate testing of image details.
@jaydrogers
jaydrogers marked this pull request as ready for review September 10, 2026 15:07
@jaydrogers
jaydrogers merged commit 33352f9 into release/webserver-improvements-and-fixes Sep 10, 2026
114 checks passed
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.

1 participant