docs(docker): Hub pages for aio + ml, and the image table in the README

picpeak/ml has an empty Hub overview and picpeak/aio has none at all,
while backend and frontend carry hand-written ones — so the two newest
images are the two with nothing on their registry page.

Adds .github/dockerhub/{aio,ml}.md as the source of those pages and a
dockerhub-descriptions job that pushes them on every main merge, so the
page cannot drift from the release it describes. backend/frontend stay
hand-maintained for now: capturing their current Hub text into files is
a prerequisite, not a side effect of this change.

README gains a registry table for all four images (both registries share
digests and tags), the org-move callout lists the full set, and the
feature list finally mentions People in this gallery, which shipped in
#1074 without a README line.
This commit is contained in:
Luca
2026-08-20 08:24:19 +02:00
parent 2df455784c
commit 899c9b3407
5 changed files with 170 additions and 3 deletions
+7 -1
View File
@@ -1,6 +1,6 @@
# Docker Build and Push Workflow
This GitHub Actions workflow automatically builds and pushes Docker images for the backend, the frontend, and the all-in-one image to GitHub Container Registry (ghcr.io).
This GitHub Actions workflow automatically builds and pushes Docker images for the backend, the frontend, the all-in-one image and the optional ML sidecar to GitHub Container Registry (ghcr.io). On the canonical org repo every one of them is mirrored to Docker Hub as `docker.io/picpeak/{backend,frontend,aio,ml}`; forks build the same images GHCR-only.
The **all-in-one image** (`<repo>/aio`, built from `Dockerfile.aio` at the repo root, #1042) bundles the backend and the built frontend into a single container with SQLite as the default engine — one `docker run`, no compose. It follows the same per-arch build → digest-merge → per-version tag scheme as the other two images, is mirrored to Docker Hub (`docker.io/picpeak/aio`) alongside GHCR on the canonical org repo, and every PR additionally runs a `smoke-aio` job that boots the image and asserts the SPA shell, brand-title rendering, immutable asset caching, and the SQLite engine resolution.
@@ -12,6 +12,7 @@ The **all-in-one image** (`<repo>/aio`, built from `Dockerfile.aio` at the repo
- 🔒 **Security scanning** with Trivy vulnerability scanner
- 💾 **Build caching** for faster subsequent builds
- 📊 **Build summaries** in GitHub Actions UI
- 📝 **Docker Hub pages** for `aio` and `ml` synced from `.github/dockerhub/*.md` on every `main` merge (`dockerhub-descriptions` job). `backend` and `frontend` pages are still hand-maintained in the Hub UI — add `.github/dockerhub/{backend,frontend}.md` with their current text before putting them under the same job.
## Authentication
@@ -54,6 +55,11 @@ docker pull ghcr.io/picpeak/picpeak/backend:v1.0.0
# Pull for specific architecture
docker pull --platform linux/arm64 ghcr.io/picpeak/picpeak/backend:latest
# The same images on Docker Hub (identical tags, identical digests)
docker pull picpeak/backend:latest
docker pull picpeak/aio:stable
docker pull picpeak/ml:stable
```
### Using in Docker Compose
+47
View File
@@ -1306,6 +1306,53 @@ jobs:
run: |
docker buildx imagetools inspect docker.io/picpeak/ml:${{ steps.meta-ml.outputs.version }}
# ---------------------------------------------------------------------------
# Docker Hub repository pages
# ---------------------------------------------------------------------------
# The Hub overview for an image is repository metadata, not part of the
# manifest, so pushing tags never updates it. Keep the copy for the two
# newest images in-repo and push it from CI, so a Hub visitor is never
# reading a page that describes a release from six months ago.
#
# Scope: aio and ml only. picpeak/{backend,frontend} still have their pages
# maintained by hand in the Hub UI — bring them under this job by adding
# .github/dockerhub/{backend,frontend}.md with the current text first,
# otherwise this would overwrite them with a near-copy.
#
# Only on `main` pushes for the canonical org repo: descriptions are
# per-repository, not per-tag, so once per merge is exactly enough.
dockerhub-descriptions:
needs: [merge-aio, merge-ml]
if: always() && github.repository == 'PicPeak/picpeak' && github.ref == 'refs/heads/main' && needs.merge-aio.result == 'success'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Update picpeak/aio description
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: picpeak/aio
short-description: "picpeak all-in-one — self-hosted photo sharing + CRM in a single container (SQLite)."
readme-filepath: .github/dockerhub/aio.md
# Skipped whenever the sidecar itself was skipped (FACENET_ONNX_URL unset),
# since the Hub repository only exists once something has been pushed to it.
- name: Update picpeak/ml description
if: needs.merge-ml.result == 'success'
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: picpeak/ml
short-description: "picpeak face-detection sidecar — optional and stateless. Pairs with picpeak/backend."
readme-filepath: .github/dockerhub/ml.md
summary:
needs: [build-backend, merge-backend, build-frontend, merge-frontend, build-aio, merge-aio, smoke-aio, build-ml, merge-ml]
if: always()