@@ -23,10 +23,16 @@ embedded PHP language module on Debian **trixie** (amd64). The whole
2323php-version / suite / FreeUnit-release matrix is covered by build args — there
2424is no code generation and no committed per-variant directories.
2525
26- FreeUnit ships ** prebuilt ` .deb ` packages** (core ` unit ` + per-version
27- ` unit -phpX.Y` modules) on its GitHub releases page, so the build installs them
26+ FreeUnit ships ** prebuilt ` .deb ` packages** (core ` freeunit ` + per-version
27+ ` freeunit -phpX.Y` modules) on its GitHub releases page, so the build installs them
2828directly — it does ** not** compile Unit or the PHP module from source.
2929
30+ Upstream rebranded its packages and on-disk identity from ` unit* ` to ` freeunit* `
31+ (daemon ` freeunitd ` , ` /var/lib/freeunit ` , ` control.freeunit.sock ` , the
32+ ` freeunit:freeunit ` user/group). Because this image only * installs* the prebuilt
33+ ` .deb ` s, that identity is fixed by the artifact, not chosen here — see the brand
34+ ARGs and the build-time guard below.
35+
3036## Build matrix
3137
3238The ` Makefile ` drives the matrix; each target is one ` docker build ` with
@@ -41,15 +47,25 @@ docker build --build-arg PHP_VER=8.3 -t x . # one-off without make
4147```
4248
4349Key build args (defaults in the ` Dockerfile ` ): ` PHP_VER ` (8.4), ` SUITE ` (trixie),
44- ` IMAGE_SUFFIX ` (-slim), ` FREEUNIT_VERSION ` (deb version base, e.g. ` 1.35.5 -1 ` ),
45- ` FREEUNIT_RELEASE ` (GitHub release tag, e.g. ` 1.35.5-build4 ` ), and the
50+ ` IMAGE_SUFFIX ` (-slim), ` FREEUNIT_VERSION ` (deb version base, e.g. ` 1.35.6 -1 ` ),
51+ ` FREEUNIT_RELEASE ` (GitHub release tag, e.g. ` 1.35.6-build2 ` ), and the
4652` DEBIAN_MIRROR ` / ` DEBIAN_SECURITY_MIRROR ` / ` SURY_MIRROR ` mirror args (neutral
4753CDN defaults; sury is fetched over https because its signing key travels that
4854channel). The ` Makefile ` reads ` SUITE ` / ` PHP_VER ` / ` FREEUNIT_VERSION ` /
4955` FREEUNIT_RELEASE ` defaults out of the ` Dockerfile ` ARGs via ` sed ` , so they are
5056** single-sourced** : bumping a FreeUnit release = edit ` FREEUNIT_VERSION ` +
5157` FREEUNIT_RELEASE ` in the ` Dockerfile ` only (or pass on the command line).
5258
59+ A second ARG group single-sources the ** brand identity** , mirroring the upstream
60+ packaging vocabulary (` freeunit/pkg/deb/Makefile ` ): ` BRAND ` (dpkg/apt asset and
61+ package names we download), ` RUNTIME ` (the on-disk identity compiled into the
62+ package — binary ` ${RUNTIME}d ` , ` /var/lib/${RUNTIME} ` , ` control.${RUNTIME}.sock ` ,
63+ ` /var/log/${RUNTIME}.log ` , the ` ${RUNTIME}:${RUNTIME} ` user/group), ` RUNDIR ` (the
64+ socket + pid dir), plus ` BRAND_TITLE ` / ` HOMEPAGE ` / ` DOCS_URL ` for the OCI labels.
65+ All default to ` freeunit ` / ` /var/run ` . These are ** not** free knobs (the prebuilt
66+ ` .deb ` s carry one fixed identity); they document intent and are asserted against
67+ the installed binary at build time (see below).
68+
5369The Makefile's immutable image tag is ` $(SUITE)-$(FREEUNIT_RELEASE)-php$* ` (the
5470release is the unique build id), plus the floating ` $(SUITE)-php$* ` .
5571
@@ -65,25 +81,34 @@ release is the unique build id), plus the floating `$(SUITE)-php$*`.
65813 . ** php_image** also installs the fragile extensions (` imagick ` ,
6682 ` uploadprogress ` ) in a ** best-effort** loop (`apt-get install … || echo
6783 WARNING`), so a missing extension on a newer PHP line does not fail the build.
68- 4 . ** final_image** — downloads ` unit_ *` and ` unit -php${PHP_VER}_*` ` .deb ` s from the
69- FreeUnit GitHub release, verifies ` SHA256SUMS ` itself against the pinned
84+ 4 . ** final_image** — downloads ` ${BRAND}_ *` and ` ${BRAND} -php${PHP_VER}_*` ` .deb ` s
85+ from the FreeUnit GitHub release, verifies ` SHA256SUMS ` itself against the pinned
7086 ` FREEUNIT_SHA256SUMS_SHA256 ` trust anchor (see below), then verifies the ` .deb ` s
7187 against it (asserting both expected entries are present with ` grep -qF ` , so
7288 ` --ignore-missing ` cannot pass vacuously), and ` apt-get install ` s the two local
7389 files (apt pulls
74- ` libphp${PHP_VER}-embed ` already present and the virtual ` unit-rX.Y.Z ` provided
75- by the core package). Then it prepares ` /var/lib/unit ` + ` /docker-entrypoint.d ` ,
76- symlinks ` unit.log ` to stdout, ` COPY rootfs/ / ` , sets OCI ` LABEL ` s, and sets the
77- ` tini ` entrypoint + ` unitd --no-daemon ` .
90+ ` libphp${PHP_VER}-embed ` already present and the virtual ` ${RUNTIME}-rX.Y.Z `
91+ provided by the core package). Then it prepares ` /var/lib/${RUNTIME} ` +
92+ ` /docker-entrypoint.d ` , symlinks ` /var/log/${RUNTIME}.log ` to stdout, ** asserts
93+ the installed ` ${RUNTIME}d ` 's compiled paths (` --statedir ` /` --control ` /` --pid ` /
94+ ` --log ` /` --user ` /` --group ` from its ` --version ` configure line) match
95+ ` RUNTIME ` /` RUNDIR ` ** — so a future upstream identity change fails the build
96+ instead of shipping an image whose entrypoint manages the wrong paths — then
97+ ` COPY rootfs/ / ` and sets OCI ` LABEL ` s. There is ** no ` CMD ` ** : the default launch
98+ (` ${RUNTIME}d --no-daemon --control … ` ) lives in the entrypoint and the
99+ ` HEALTHCHECK ` is a script (` /docker-healthcheck.sh ` ), so the binary name and
100+ socket path stay single-sourced from ` docker-entrypoint-common.sh ` rather than
101+ duplicated in an exec-form instruction (which cannot expand a build ARG/ENV).
102+ ` tini ` is the entrypoint wrapper.
78103
79104` SUITE ` and ` IMAGE_SUFFIX ` are declared ** before the first ` FROM ` ** so they reach
80105the ` FROM ` line; they are re-declared inside stages that use them in ` RUN ` .
81106
82107### Critical packaging detail (asset name vs deb version)
83108
84109GitHub renames the ` ~ ` in deb version strings to ` . ` in asset file names, so the
85- ** same** package is downloaded as ` unit_1 .35.5 -1.trixie_amd64.deb` but its real
86- version (and its ` SHA256SUMS ` entry) is ` 1.35.5 -1~trixie ` . The Dockerfile downloads
110+ ** same** package is downloaded as ` freeunit_1 .35.6 -1.trixie_amd64.deb` but its real
111+ version (and its ` SHA256SUMS ` entry) is ` 1.35.6 -1~trixie ` . The Dockerfile downloads
87112with ` curl -o ` into the ** ` ~ ` name** so ` sha256sum -c --ignore-missing ` actually
88113matches the file. Saving under the ` . ` name would make the checksum check pass
89114** vacuously** (no matching filename → entry skipped) — a silent integrity hole.
@@ -96,8 +121,8 @@ trusted `SHA256SUMS` **in version control**, and the build aborts unless the
96121fetched file hashes to it. Bumping FreeUnit therefore means recomputing this
97122digest too — which is exactly what ` check-upstream.yml ` automates.
98123
99- The core ` unit ` package's ` postinst ` creates the ` unit:unit ` system user/group,
100- so the Dockerfile does not create it manually.
124+ The core ` freeunit ` package's ` postinst ` creates the ` freeunit:freeunit ` system
125+ user/group, so the Dockerfile does not create it manually.
101126
102127## rootfs overlay
103128
@@ -110,12 +135,15 @@ lives there at its target path:
110135 library): if a sourced file defined a shell function ` handle_<cmd> ` matching
111136 ` $1 ` , that handler owns the launch (it must ` exec ` , and a return or a non-zero
112137 exit is a fatal contract violation);
113- otherwise, for ` unitd ` /` unitd-debug ` it runs the standard first-run routine
114- (` unit_initial_configuration ` ) and ` exec ` s the command. The first-run routine
115- only fires when ` /var/lib/unit ` is empty: it launches unitd against the control
116- socket and applies everything in ` /docker-entrypoint.d/ ` (` *.sh ` executed,
138+ otherwise, for ` freeunitd ` /` freeunitd-debug ` it runs the standard first-run
139+ routine (` unit_initial_configuration ` ) and ` exec ` s the command. (When invoked
140+ with no command at all, the dispatcher first supplies the default launch —
141+ ` ${UNIT_BINARY} --no-daemon --control … ` — from the ` UNIT_* ` constants, so the
142+ image needs no ` CMD ` .) The first-run routine
143+ only fires when ` /var/lib/freeunit ` is empty: it launches freeunitd against the
144+ control socket and applies everything in ` /docker-entrypoint.d/ ` (` *.sh ` executed,
117145 ` *.pem ` uploaded as certificate bundles, ` *.json ` PUT to ` config ` ), then stops
118- unitd so the real start boots a populated state.
146+ freeunitd so the real start boots a populated state.
119147- ` rootfs/docker-entrypoint-common.sh ` — the reusable ** core library** sourced by
120148 the entrypoint (and available to child hooks). Every function takes its target
121149 as an argument, defaulting to the ` UNIT_* ` / ` ENTRYPOINT_* ` constants, so a
@@ -144,8 +172,14 @@ lives there at its target path:
144172 idempotent; a child hook calls it to create a * different* app user.
145173 - ` unit_initial_configuration <binary> ` is the full first-run routine composed
146174 from the above, guarded by its ` unit_config_failed ` EXIT trap.
147- On source it provisions the default app user from `APPLICATION_USER/UID/GROUP/
148- GID/DIR/CHOWN` by calling ` setup_user` with them.
175+ On source it provisions the default app user (default ` freeunit ` , which maps to
176+ the package's system ` freeunit:freeunit ` ) from `APPLICATION_USER/UID/GROUP/
177+ GID/DIR/CHOWN` by calling ` setup_user` — unless ` UNIT_LIB_NO_PROVISION=1` is set,
178+ which yields the constants/functions without the side effect (used by
179+ ` /docker-healthcheck.sh ` , which sources the lib only to read ` UNIT_CONTROL_SOCKET ` ).
180+ The path constants derive from ` UNIT_RUNTIME ` (` freeunit ` ) and ` UNIT_RUNDIR `
181+ (` /var/run ` ), readonly literals — deliberately not env-derived — so the state-dir
182+ wipe target and control paths cannot be redirected at runtime.
149183
150184` /docker-entrypoint.d ` itself is created by the ` RUN ` (empty dirs are not tracked
151185in git); users mount or add config snippets into it at runtime.
@@ -179,8 +213,9 @@ The two reusable routines above are the public surface handlers build on.
179213
180214## Verification
181215
182- - ** Build** — the ` final_image ` stage runs ` unitd --version ` and ` php -v ` , so a
183- successful build proves the daemon and module load.
216+ - ** Build** — the ` final_image ` stage runs ` freeunitd --version ` (also asserting
217+ its compiled paths match ` RUNTIME ` /` RUNDIR ` ) and ` php -v ` , so a successful build
218+ proves the daemon and module load and the image's paths match the binary.
184219- ** Smoke test** — ` test/smoke.sh <image-ref> ` runs the image with the
185220 ` test/fixtures/ ` PHP app mounted (config into ` /docker-entrypoint.d ` , code into
186221 ` /www ` ) and asserts a request is served by PHP — the entrypoint's happy path.
@@ -237,4 +272,4 @@ The two reusable routines above are the public surface handlers build on.
237272 the build context.
238273- The entrypoint uses bash globs (` shopt -s nullglob globstar ` ) over
239274 ` /docker-entrypoint.d ` , not ` for f in $(find …) ` ; it passes ` --pid ` explicitly
240- and wipes ` /var/lib/unit ` if first-run config fails (retry on next start).
275+ and wipes ` /var/lib/freeunit ` if first-run config fails (retry on next start).
0 commit comments