US08-02 — Build a Reproducible Application Image #88

Closed
opened 2026-08-17 21:11:35 +02:00 by domverse · 3 comments
Owner

Source specification: delivery_backlog/stories/US08-02-container-image.md

US08-02 — Build a Reproducible Application Image

Epic: E08

As an operator, I want one image that can run either application role, so deployment is
a pull instead of a Python environment I have to reproduce by hand.

Context

The application shells out to exiftool and immich-go, writes into the library as a
normal filesystem user, and serves a static frontend from frontend/. All three have to
be true inside the image, or the container starts and then fails on the first real
operation.

Acceptance criteria

  • A Dockerfile builds from a pinned Python base, installs the project and its runtime
    dependencies, and contains no test, playwright, or build-only tooling in the final
    layer.
  • exiftool and immich-go are present at pinned versions, and their versions are
    recorded in the image and reported by python -m photo_pipeline diagnostics.
  • The image runs as a non-root user whose UID/GID are build-time arguments, so files
    the application renames or writes keep the ownership the host library expects.
  • One entrypoint selects the role: serve or worker, passing through the existing
    CLI arguments; no supervisor runs two roles in one container.
  • serve containers declare a HEALTHCHECK against /api/v1/health/ready, so an
    unmigrated or misconfigured database is not reported healthy.
  • The image contains no secrets, no library data, no database, and no .git; the build
    context is constrained by .dockerignore.
  • Image build is reproducible from a clean checkout and documented in README.md.

Automated tests

  • A build-and-run test asserts the image starts, reports ready, serves the frontend
    index, and returns the pinned exiftool and immich-go versions.
  • A test asserts the container refuses to run as UID 0 and that a file created by the
    container is owned by the configured UID/GID.

Dependencies

  • US07-05
Source specification: [delivery_backlog/stories/US08-02-container-image.md](https://git.domverse-berlin.eu/domverse/photoanalyzer/src/branch/main/delivery_backlog/stories/US08-02-container-image.md) # US08-02 — Build a Reproducible Application Image Epic: [E08](https://git.domverse-berlin.eu/domverse/photoanalyzer/src/branch/main/delivery_backlog/E08-container-deployment.md) As an operator, I want one image that can run either application role, so deployment is a pull instead of a Python environment I have to reproduce by hand. ## Context The application shells out to `exiftool` and `immich-go`, writes into the library as a normal filesystem user, and serves a static frontend from `frontend/`. All three have to be true inside the image, or the container starts and then fails on the first real operation. ## Acceptance criteria - A `Dockerfile` builds from a pinned Python base, installs the project and its runtime dependencies, and contains no test, playwright, or build-only tooling in the final layer. - `exiftool` and `immich-go` are present at pinned versions, and their versions are recorded in the image and reported by `python -m photo_pipeline diagnostics`. - The image runs as a non-root user whose UID/GID are build-time arguments, so files the application renames or writes keep the ownership the host library expects. - One entrypoint selects the role: `serve` or `worker`, passing through the existing CLI arguments; no supervisor runs two roles in one container. - `serve` containers declare a `HEALTHCHECK` against `/api/v1/health/ready`, so an unmigrated or misconfigured database is not reported healthy. - The image contains no secrets, no library data, no database, and no `.git`; the build context is constrained by `.dockerignore`. - Image build is reproducible from a clean checkout and documented in `README.md`. ## Automated tests - A build-and-run test asserts the image starts, reports ready, serves the frontend index, and returns the pinned `exiftool` and `immich-go` versions. - A test asserts the container refuses to run as UID 0 and that a file created by the container is owned by the configured UID/GID. ## Dependencies - US07-05
domverse added a new dependency 2026-08-17 21:12:18 +02:00
domverse added a new dependency 2026-08-17 21:12:19 +02:00
domverse added a new dependency 2026-08-17 21:12:19 +02:00
domverse added a new dependency 2026-08-17 21:12:20 +02:00
domverse added this to the Photo Analyzer Delivery project 2026-08-17 21:15:36 +02:00
domverse added this to the E08 — Container Deployment milestone 2026-08-17 21:17:42 +02:00
domverse added status/in-progress and removed status/backlog labels 2026-08-18 22:16:51 +02:00
domverse self-assigned this 2026-08-18 22:16:52 +02:00
Author
Owner

Claimed for implementation on branch us/US08-02-build-a-reproducible-application-image.

Claimed for implementation on branch `us/US08-02-build-a-reproducible-application-image`.
domverse added status/review and removed status/in-progress labels 2026-08-18 23:10:53 +02:00
Author
Owner

Submitted for review: #97

Tests passed:

  • work_item/scripts/python -m unittest discover -s work_item/tests -v
  • work_item/scripts/python -m pytest tests -q
  • work_item/scripts/python -m pytest tests/integration/test_container_image.py tests/e2e/test_container_runtime.py -q
Submitted for review: https://git.domverse-berlin.eu/domverse/photoanalyzer/pulls/97 Tests passed: - `work_item/scripts/python -m unittest discover -s work_item/tests -v` - `work_item/scripts/python -m pytest tests -q` - `work_item/scripts/python -m pytest tests/integration/test_container_image.py tests/e2e/test_container_runtime.py -q`
domverse added status/done and removed status/review labels 2026-08-18 23:11:17 +02:00
Author
Owner

Completed and merged via PR #97.

Completed and merged via PR #97.
domverse moved this to Done in Photo Analyzer Delivery on 2026-08-18 23:30:08 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: domverse/photoanalyzer#88