Release pipeline
Builds run in GitHub Actions from .github/workflows/docker-build.yml. They are triggered by a push to main, a manual dispatch, and a weekly schedule.
Jobs
php-matrix ──┐
├──▶ build-php (one job per PHP minor, in parallel)
build-base ──┘ php ──▶ php-nginx ──▶ php-nginx-dev
- php-matrix reads
alpine/php-versions.txtand turns it into the build matrix, so adding a PHP version is a one-line change. - build-base builds, scans and promotes
adamrollogi/base:latest. - build-php runs once per minor and builds
php, thenphp-nginxfrom the promotedphptag, thenphp-nginx-devfrom the promotedphp-nginxtag. Each goes through the same candidate, scan, attest, promote sequence.
Multi-architecture builds
Images are built for linux/amd64 and linux/arm64 with buildx using the docker-container driver. The arm64 half is built under QEMU on the amd64 runner. Layers are cached in the GitHub Actions cache, one scope per image, so unchanged layers are reused between runs. A full uncached run takes a few minutes per PHP minor.
Candidate, scan, promote
Every image is first pushed under candidate-<git sha> (base) or candidate-<git sha>-<minor> (PHP images). Trivy scans that candidate for CRITICAL and HIGH findings with fixes available; a finding fails the job before anything reaches a public tag. The VEX attestation is attached, then docker buildx imagetools create retags the candidate as the real tags, copying the whole manifest list including the SBOM, provenance and VEX. Finally the candidate tag is deleted through the Docker Hub API.
What is pinned
- Actions are pinned to commit SHAs and kept current by Dependabot.
- buildx is pinned to a release via
BUILDX_VERSION. - The Alpine base is pinned to a digest and kept current by Dependabot.
- PHP is pinned per minor in
php-versions.txtand kept current by the bump job.
Weekly rebuild
The schedule rebuilds everything every Monday even when nothing in the repository changed. Because the base Dockerfile runs apk upgrade, this is how Alpine's fixes for musl, OpenSSL, Nginx and other system packages reach the published images without a code change.
Secrets and permissions
The workflow needs a DOCKER_USER variable and a DOCKER_PAT secret. The token is passed only to the login step and the candidate cleanup step, never exposed at workflow scope, and the workflow runs with read-only repository permissions.